DEV Community

Krirk Srithaweewath
Krirk Srithaweewath

Posted on • Updated on

PuppyBox

Introduction

Github repo
Download Exe

Game animation

This is a clone go Gecko Shuffle game.

Rule of this game

  1. There are 3 boxes, 2 of which are blank boxes, and one of which features a picture of a puppy.
  2. Three of them will move at random.
  3. You choose the one you believe it is a puppy box.
  4. After you have choosen the box, program will reveal which box is a puppy.
  5. The more choices you guess correctly, the more points you receive.

The Code
This game is so small. So almost all of the logics are in the same place as UI.

The UI
Form1 contains the logic to shuffle and move the boxes,
the control we use for rendering the boxes is picturebox.

The Game
Game class keeps the score, box moving speed, current level, game state information.

Box class
This class reponsible for drawing itself.
There are 5 states of the box.

Drawing animation
The logic behind drawing an animation is in Form1.OpenBox() method.
Program will loop though all of the BoxStateEnum
then set a boxstate to a specific box object then call RefreshUI() method.

private void OpenBox(int BoxIndex) {
  var values = Enum.GetValues(typeof (Box.BoxStateEnum));
  foreach(Box.BoxStateEnum state in values) {
    boxs[BoxIndex].BoxState = state;
    RefreshUI();
    Wait(MiliSecondAnimationWaitEachFrame);

  }

}

public enum BoxStateEnum {
  Close,
  BegintoOpen1,
  BegintoOpen2,
  BegintoOpen3,
  Open
}
Enter fullscreen mode Exit fullscreen mode

The logic behind drawing method is using Graphics.FillPolygon() method.
We have DrawClose(),
DrawBeginToOpen1(),
DrawBeginToOpen2(),
DrawBeginToOpen3(),
DrawOpen()

These method follow the same logic

  1. Create a list of Point
  2. using FillPolyGon method to draw each part of the picture. For DrawClose() and DrowOpen, it is quite simple but for DrawBegingToOpen1(), DrawBegingToOpen2(), DrawBegingToOpen3() They are quite complicated.
    private void DrawClose(Graphics g) {
      Rectangle FillArea = new Rectangle(new Point(Left, Top), new Size(Width - 2, Height - 2));
      g.FillRectangle(BackBrush, FillArea);
      List < Point > listPoint = new List < Point > ();

      Point LeftSideTopLeft = new Point(TopLeftPoint.X - this.BoxLength, TopLeftPoint.Y + this.BoxLength);
      Point LeftSideBottomLeft = new Point(LeftSideTopLeft.X, LeftSideTopLeft.Y + this.Height);

      listPoint.Add(TopLeftPoint);
      listPoint.Add(LeftSideTopLeft);
      listPoint.Add(LeftSideBottomLeft);
      listPoint.Add(BottomLeftPoint);

      g.FillPolygon(BackBrush, listPoint.ToArray());
      listPoint.Clear();
      Point DownSideBottomLeft = LeftSideBottomLeft;
      Point DownSideBottomRight = new Point(LeftSideBottomLeft.X + this.Width, DownSideBottomLeft.Y);
      Point DownSideTopRight = BottomRightPoint;

      listPoint.Add(BottomLeftPoint);
      listPoint.Add(DownSideBottomLeft);
      listPoint.Add(DownSideBottomRight);
      listPoint.Add(DownSideTopRight);

      g.FillPolygon(BackBrush, listPoint.ToArray());
    }
    int BoxLength = 10;

    private void DrawBeginToOpen1(Graphics g) {
      Point TopLeftCustom = new Point(TopLeftPoint.X - 10, TopLeftPoint.Y + 10);
      Point BottomLeftCustom = new Point(TopLeftCustom.X, TopLeftCustom.Y + this.Height);
      Point TopRightCustom = new Point(TopLeftPoint.X + this.Width - 10, TopLeftCustom.Y - 30);
      Point BottomRightCustom = new Point(TopLeftPoint.X + this.Width - 10, TopRightCustom.Y + this.Height);
      List < Point > listPoint = new List < Point > ();

      listPoint.Add(TopLeftCustom);
      listPoint.Add(BottomLeftCustom);
      listPoint.Add(BottomRightCustom);
      listPoint.Add(TopRightCustom);
      g.FillPolygon(BackBrush, listPoint.ToArray());

      Point DownSideBottomLeft = new Point(BottomLeftCustom.X + 10, BottomLeftCustom.Y + 10);
      Point DownSideBottomRight = new Point(BottomRightCustom.X + 10, BottomRightCustom.Y + 10);
      listPoint = new List < Point > ();
      listPoint.Add(BottomLeftCustom);
      listPoint.Add(DownSideBottomLeft);
      listPoint.Add(DownSideBottomRight);
      listPoint.Add(BottomRightCustom);
      g.FillPolygon(BackBrush, listPoint.ToArray());

      Point RightSideTopRight = new Point(TopRightCustom.X + 10, TopRightCustom.Y + 10);
      Point RightSideBottomRight = new Point(BottomRightCustom.X + 10, BottomRightCustom.Y + 10);
      listPoint = new List < Point > ();
      listPoint.Add(TopRightCustom);
      listPoint.Add(RightSideTopRight);
      listPoint.Add(RightSideBottomRight);
      listPoint.Add(BottomRightCustom);
      g.FillPolygon(BackBrush, listPoint.ToArray());

    }

    private void DrawBeginToOpen2(Graphics g) {

      Point TopLeftCustom = new Point(TopLeftPoint.X + BoxLength, TopLeftPoint.Y + BoxLength);
      Point BottomLeftCustom = new Point(TopLeftCustom.X, TopLeftCustom.Y + this.Height);
      Point TopRightCustom = new Point(TopLeftPoint.X + (this.Width / 2) - 10, TopLeftCustom.Y - (this.Height / 2));
      Point BottomRightCustom = new Point(TopLeftPoint.X + (this.Width / 2) - 10, TopRightCustom.Y + this.Height);
      List < Point > listPoint = new List < Point > ();

      listPoint.Add(TopLeftCustom);
      listPoint.Add(BottomLeftCustom);
      listPoint.Add(BottomRightCustom);
      listPoint.Add(TopRightCustom);
      g.FillPolygon(BackBrush, listPoint.ToArray());

      Point DownSideBottomLeft = new Point(BottomLeftCustom.X + BoxLength, BottomLeftCustom.Y);
      Point DownSideBottomRight = new Point(BottomRightCustom.X + BoxLength, BottomRightCustom.Y);
      listPoint = new List < Point > ();
      listPoint.Add(BottomLeftCustom);
      listPoint.Add(DownSideBottomLeft);
      listPoint.Add(DownSideBottomRight);
      listPoint.Add(BottomRightCustom);
      g.FillPolygon(BackBrush, listPoint.ToArray());

      Point RightSideTopRight = new Point(TopRightCustom.X + BoxLength, TopRightCustom.Y);
      Point RightSideBottomRight = new Point(BottomRightCustom.X + BoxLength, BottomRightCustom.Y);
      listPoint = new List < Point > ();
      listPoint.Add(TopRightCustom);
      listPoint.Add(RightSideTopRight);
      listPoint.Add(RightSideBottomRight);
      listPoint.Add(BottomRightCustom);
      g.FillPolygon(BackBrush, listPoint.ToArray());
    }
    private void DrawBeginToOpen3(Graphics g) {
      Point TopLeftCustom = new Point(TopLeftPoint.X + 20, TopLeftPoint.Y - 20);
      Point BottomLeftCustom = new Point(TopLeftCustom.X, TopLeftCustom.Y + this.Height);
      Point TopRightCustom = new Point(TopLeftPoint.X + this.Width - 20, TopLeftCustom.Y + this.BoxLength);
      Point BottomRightCustom = new Point(TopRightCustom.X, TopRightCustom.Y + this.Height);
      List < Point > listPoint = new List < Point > ();

      listPoint.Add(TopLeftCustom);
      listPoint.Add(BottomLeftCustom);
      listPoint.Add(BottomRightCustom);
      listPoint.Add(TopRightCustom);
      g.FillPolygon(FaceBrushEmpty, listPoint.ToArray());

      Point LeftSideTopLeft = new Point(TopLeftCustom.X - BoxLength, TopLeftCustom.Y + this.BoxLength);
      Point LeftSideBottomLeft = new Point(LeftSideTopLeft.X, LeftSideTopLeft.Y + this.Height);
      listPoint = new List < Point > ();
      listPoint.Add(TopLeftCustom);
      listPoint.Add(LeftSideTopLeft);
      listPoint.Add(LeftSideBottomLeft);
      listPoint.Add(BottomLeftCustom);
      g.FillPolygon(BackBrush, listPoint.ToArray());

      Point DownSideBottomRight = new Point(BottomRightCustom.X - BoxLength, BottomRightCustom.Y + BoxLength);
      listPoint = new List < Point > ();
      listPoint.Add(BottomLeftCustom);
      listPoint.Add(LeftSideBottomLeft);
      listPoint.Add(DownSideBottomRight);
      listPoint.Add(BottomRightCustom);
      g.FillPolygon(BackBrush, listPoint.ToArray());

    }
    private void DrawOpen(Graphics g) {
      DrawClose(g);
      Rectangle FillArea = new Rectangle(new Point(Left + 1, Top + 1), new Size(Width - 2, Height - 2));

      g.FillRectangle(BackBrush, FillArea);
      if (IsDog) {
        g.DrawImage(DogImage, FillArea);
      } else {
        g.FillRectangle(FaceBrushEmpty, FillArea);
      }

    }
Enter fullscreen mode Exit fullscreen mode

For the ShuffleBox,
the first parameter is Direction, there are 2 directions ClockWise, AntiClockWise,
the second is From
the third is to

We have DictionaryPositionToBoxIndex to keep the indexposition
and boxs to keep the list of the box object.
The reason we need DictionaryPositionToBoxIndex is
Supposing at the initial state we have boxes in this order.
box1, box2, box3

Then we shuffle between the first box and the second box, here is the result.
box3, box2, box1

If we would like to shuffle between the first box and the second box
we need to shuffle between box3 and box2
DictionaryPositionToBoxIndex can tell us
the firstbox is box3 not box1 anymore.

    private void DoShuffleBox(DirectionEnum Direction, int From, int To, int SpeedLevel) {
      Box boxFrom = null;
      Box boxTo = null;
      int IndexFrom = DictionaryPositionToBoxIndex[From];
      int IndexTo = DictionaryPositionToBoxIndex[To];

      boxFrom = boxs[IndexFrom];
      boxTo = boxs[IndexTo];

      if (Direction == DirectionEnum.ClockWise) {
        while (boxFrom.Top > TopPosition) {
          boxFrom.Top -= SpeedLevel;
          boxTo.Top += SpeedLevel;
          pictureBox1.Refresh();

        }
        while (boxFrom.Left < listPositionBox[To].X) {
          boxFrom.Left += SpeedLevel;
          boxTo.Left -= SpeedLevel;
          pictureBox1.Refresh();
        }
        while (boxFrom.Top < NormalTopPosition) {
          boxFrom.Top += SpeedLevel;
          boxTo.Top -= SpeedLevel;
          pictureBox1.Refresh();

        }
      } else {
        while (boxFrom.Top < BottopPosition) {
          boxFrom.Top += SpeedLevel;
          boxTo.Top -= SpeedLevel;
          pictureBox1.Refresh();

        }
        while (boxFrom.Left < listPositionBox[To].X) {
          boxFrom.Left += SpeedLevel;
          boxTo.Left -= SpeedLevel;
          pictureBox1.Refresh();
        }
        while (boxTo.Top < NormalTopPosition) {
          boxTo.Top += SpeedLevel;
          boxFrom.Top -= SpeedLevel;
          pictureBox1.Refresh();

        }
      }
      ShuffleBoxPosition(From, To);
    }
Enter fullscreen mode Exit fullscreen mode

Reference

This is a clone of Gecko Shuffle game
You can watch the the Original Gecko Shuffle here
https://www.youtube.com/watch?v=u5SKVLbDNrE&ab_channel=258JD
https://archive.org/details/win3_gecko
https://gamesdb.launchbox-app.com/games/images/105102

puppy.png credit
https://pngtree.com/so/cute

Top comments (0)