Introduction

I want to present my first project that I make in the first stage of the 2ยบ course. It's a classic sliding puzzle, but I included more features. You can preview the solution, pause the game, view the shuffle effect, 2 skins, 3 board sizes (3x3, 4x4 and 5x5), so on...
Important Note
All of the code has comments, but in Spanish. You can translate this using the Google translator.
The reason is that it's a school project.
Quick View of Game Features
- Shuffle effect: You can see how the cards are shuffled.
- Preview the solution: You can see a preview of the solution, and while you're watching, the game is paused. (The preview of the solution is shown in grayscale).
- Classifications: The game has a database that stores everything related to games results. I decided to save in a database because this way I can do searches and filtering in an easier way. For example, while playing with a 3x3 board, you will not see the ratings board 4x4 and 5x5, and only compete in your category. The position on the classification is determined by elapsed time and then by the movements.
- Skins: The game has two skins, zen and aluminum. The Zen theme is a style of wood, while the aluminum is a metal style.
- Pause: You can pause the game whenever you want, and resume the game later.
- Board Size: The game has 3 board sizes (3x3, 4x4, 5x5).
- Insert images on the board: You can insert your own pictures on the board. Sliding Puzzle cuts it in the appropriate size and inserted. The game is ready for any size image if the image is smaller than the board, will stretch the image, and if it is larger, shrink the image.
Note: To give more playability, you can number the images or not.
- Arrows in real time: You can see the possible directions you can take in real time, using the blue arrows.
Game Screenshots
Zen Theme

Aluminium Theme

Classifications Form

Game with images and numered images

While you are previewing the solution

Main menu
Using my Class clsImage to Crop the Image
How you can cut an image using my class clsImage?
To crop an image using my clsImage
class is very easy, just set the image path in the property "Establecer_Ruta
", then call the function "Preparar_Imagen
" and arguments we pass the size of the board, and the desired size each piece of the picture. To retrieve each piece, simply call the function "GetImageFromIndex
" and as a parameter index in the list.
Sample
This example cuts an image into 9 pieces and returns the first piece. Each piece has a size of 70x70.
private Image CropImage(string imagePath)
{
clsImage imageClass = new clsImage();
imageClass.Establecer_Ruta = imagePath;
imageClass.Preparar_Imagen(3,3,70,70);
return imageClass.GetImageFromIndex(0);
}
Some Enumerations and Structures
Enumeration "enumDirection"
This enumeration contains the possible directions that can have a tab. This list is used to create a list of possible addresses that can take a tab.
public enum enumDireccion
{
Arriba = 0, Abajo = 1, Izquierda = 2, Derecha = 3 }
Structure "structFicha"
This structure is stored in the property "tag
" of each board PictureBox
, and contains the current position of the chip on the board, the position should be, and a Boolean value that indicates whether the card is empty or not.
private struct structFicha
{
public int Posicion; public int Valor; public bool Comodin; }
Enumeration "enumGameStatus"
This enumeration contains all possible states in which the game can be.
private enum enumGameStatus
{
Iniciada = 0, Pausada = 1, Finalizada = 2, Scramble = 3, }
Scramble Function
private void Scramble()
{
.....
while (moves < 100)
{
PosiblesDirecciones = Movimientos_Posibles(tmpComodin);
CurrentDirection = PosiblesDirecciones[rndDirection.Next
(0, PosiblesDirecciones.Count)];
if (firstMove != true)
{
if (LastPosition.Equals(CurrentDirection) == false)
{
LastPosition = this.DireccionContraria(CurrentDirection);
Application.DoEvents();
this.MoverCelda(CurrentDirection, true);
moves++;
}
}
else
{
firstMove = false;
LastPosition = this.DireccionContraria(CurrentDirection);
this.MoverCelda(CurrentDirection, true);
moves++;
}
}
}
Function "MoverCelda"
This function is the main game, which is responsible for moving the different tabs on the board. This function receives two parameters, the address to which you want to move the wildcard, and whether or not to move with effect.
private void MoverCelda(enumDireccion Direccion, bool WithEfect)
{
if ((this.PanelJuego.Controls.Count > 0) &&
((this.EstadoPartida == enumGameStatus.Iniciada) ||
(this.EstadoPartida == enumGameStatus.Scramble)) && (this.moveInAction == false))
{
this.moveInAction = true;
PictureBox tmpImagen = null;
Point tmpPoint = new Point();
bool movimientoValido = false;
bool FinPartida = false;
PictureBox tmpComodin = GetPictureComodin(); switch (Direccion)
{
case enumDireccion.Abajo:
if (tmpComodin.Top != 0)
{
tmpComodin.Visible = false;
tmpImagen = this.GetPictureFromPoints(new Point
(tmpComodin.Location.X, tmpComodin.Location.Y - tmpComodin.Height));
tmpPoint = new Point(tmpImagen.Location.X, tmpImagen.Location.Y);
if (WithEfect == true)
{
int posY = tmpImagen.Location.Y;
for (int i = posY; i <= tmpComodin.Location.Y; i++)
{
tmpImagen.Location = new Point(tmpComodin.Location.X, i);
}
}
else
{
tmpImagen.Location = new Point
(tmpComodin.Location.X, tmpComodin.Location.Y);
}
tmpComodin.Location = new Point(tmpPoint.X, tmpPoint.Y);
this.TooglePicturePosition(ref tmpImagen, ref tmpComodin);
movimientoValido = true;
tmpComodin.Visible = true;
}
break;
..........
}
if (this.EstadoPartida == enumGameStatus.Iniciada)
{
if (movimientoValido == true)
{
this.MovimientosPartida += 1;
this.lblStepsValue.Text = Convert.ToString(this.MovimientosPartida);
if (((structFicha)tmpComodin.Tag).Posicion ==
((structFicha)tmpComodin.Tag).Valor)
{
FinPartida = this.EvaluarFinJuego();
}
if (FinPartida != true)
{
tmpComodin.Image = this.Imagen.InsertarArrows
(this.Theme.imgEmpty, this.Movimientos_Posibles(tmpComodin));
}
}
}
this.moveInAction = false;
}
}
}
Insert the Arrows into the Blank Images
To insert the arrows on any image, in our case a wildcard image, simply call the function "InsertarArrows
" clsImage
class. This function receives two parameters, the image that you want to insert arrows, and different arrows to be entered.
public Image InsertarArrows(Image Imagen, List<enumDireccion> Arrows)
{
Graphics g = null;
Image tmpImg = null;
tmpImg = (Image)(Imagen.Clone());
g = Graphics.FromImage(tmpImg);
foreach (enumDireccion Arrow in Arrows)
{
switch (Arrow)
{
case enumDireccion.Arriba:
g.DrawImage(Properties.Resources.arrow_up, new Point
(30, Imagen.Height - Properties.Resources.arrow_down.Height));
break;
case enumDireccion.Abajo:
g.DrawImage(Properties.Resources.arrow_down, new Point(30, 0));
break;
case enumDireccion.Izquierda:
g.DrawImage(Properties.Resources.arrow_left,
new Point(Imagen.Width - Properties.Resources.arrow_down.Width, 30));
break;
case enumDireccion.Derecha:
g.DrawImage(Properties.Resources.arrow_right, new Point(0, 30));
break;
}
}
g.Dispose();
return tmpImg;
}
Resources
The board pictures are included, and also the *. psd (Photoshop). The menu images are the property of http://p.yusukekamiyamane.com/.