C++ Getting Started - Implementing Push Box Game

Reference resources

  1. C and C++ Game Fun Programming Kid Crystal

Push Box Game

Players use keyboards to control the characters and push all the yellow boxes to the white squares

Store level data in character array

There are six elements in the game:
(1) Blank area: Players can go through, boxes can be pushed up; English name: empty; abbreviation:'e'

(2) Wall: Players cannot pass, boxes cannot push past; English name: wall; abbreviation:'w'

(3) Box: Players can push without obstacles in front; English name: box; abbreviation:'b'

(4) Blank target: requires player to push box up; English name: target; abbreviation:'t'

(5) Achieving goals: the overlapping status of a box on the target; English name: achieved; abbreviation:'a'

(6) Game characters: Keyboard controls movement to push box to reach target; English name: player; Abbreviation:'p'

Define a global variable, level, to store map data, and draw patterns in the show() function based on the level[i][j]:

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#define B_SIZE 60//Square Size
#define B_NUM 8 // Number of squares, a total of 8*8 squares

// Storing map data in a character two-dimensional array
char level[B_NUM][B_NUM + 1] = { "wwwwwwww", "wwwtbeew", "weeeeeew", "weeeeeew", "weeeeeew", "weepaeew", "weeewwww", "wwwwwwww" };

void startup()
{
	initgraph(B_NUM * B_SIZE, B_NUM * B_SIZE);
	setbkcolor(RGB(150, 150, 150));             // Gray Background
	BeginBatchDraw();                           // Start batch drawing
}

void show()
{
	int i, j;
	cleardevice();
	for (i = 0; i < B_NUM; i++)
	{
		for (j = 0; j < B_NUM; j++)
		{
			if (level[i][j] == 'e')              // white space
			{
				setfillcolor(RGB(150, 150, 150));// Draw gray ground
				setlinecolor(RGB(150, 150, 150));
				fillrectangle(j * B_SIZE, i * B_SIZE, (j + 1) * B_SIZE, (i + 1) * B_SIZE);
			}
			else if (level[i][j] == 'w')         // wall
			{
				setfillcolor(RGB(155, 0, 0));
				setlinecolor(RGB(150, 150, 150));// Box with light red and grey lines
				fillrectangle(j * B_SIZE, i * B_SIZE, (j + 1) * B_SIZE, (i + 1) * B_SIZE);
			}
			else if (level[i][j] == 'b')         // case
			{
				setfillcolor(RGB(255, 255, 0));  // Yellow Square
				setlinecolor(RGB(150, 150, 150));
				fillrectangle(j * B_SIZE, i * B_SIZE, (j + 1) * B_SIZE, (i + 1) * B_SIZE);
			}
			else if (level[i][j] == 't')         // target
			{
				setfillcolor(RGB(250, 250, 250));// Small white square
				fillrectangle((j + 0.3) * B_SIZE, (i + 0.3) * B_SIZE, (j + 0.7) * B_SIZE, (i + 0.7) * B_SIZE);
			}
			else if (level[i][j] == 'a')         // Goal Completed
			{
				setlinecolor(RGB(150, 150, 150));
				setfillcolor(RGB(255, 255, 0));  // Small yellow square
				fillrectangle(j * B_SIZE, i * B_SIZE, (j + 1) * B_SIZE, (i + 1) * B_SIZE);
				setfillcolor(RGB(250, 250, 250));// Small white square
				fillrectangle((j + 0.3) * B_SIZE, (i + 0.3) * B_SIZE, (j + 0.7) * B_SIZE, (i + 0.7) * B_SIZE);
			}
			else if (level[i][j] == 'p')         // Game player
			{
				setfillcolor(RGB(255, 0, 0));    // Red Round Face
				fillcircle((j + 0.5) * B_SIZE, (i + 0.5) * B_SIZE, 0.4 * B_SIZE);
				setfillcolor(RGB(80, 80, 80));   // Black eyes
				setlinecolor(RGB(80, 80, 80));
				fillcircle((j + 0.3) * B_SIZE, (i + 0.45) * B_SIZE, 0.08 * B_SIZE);
				fillcircle((j + 0.7) * B_SIZE, (i + 0.45) * B_SIZE, 0.08 * B_SIZE);
				setlinestyle(PS_SOLID, 3);
				line((j + 0.35) * B_SIZE, (i + 0.7) * B_SIZE, (j + 0.65) * B_SIZE, (i + 0.7) * B_SIZE);
				setlinestyle(PS_SOLID, 1);
			}
		}
	}
	FlushBatchDraw();
}

void update()
{

}

int main()
{
	startup();
	while (1)
	{
		show();
		update();
	}
	return 0;
}

Keyboard controls character movement

Define the structure Player to record player positions:

struct Player
{
	int i;
	int j;
};
Player player;

Traverse the two-dimensional array level to find the position of'p', that is, the player's position, assign it to the player, and change'p'to'e':

int i, j;
for (i = 0; i < B_NUM; i++)
{
	for (j = 0; j < B_NUM; j++)
	{
		if (level[i][j] == 'p')
		{
			player.i = i;
			player.j = j;
			level[i][j] = 'e';
		}
	}
}

Separate the drawing of the player in show() and draw the player according to the location stored in the player:

```cpp
void show()
{
	i = player.i;
	j = player.j;
	setfillcolor(RGB(255, 0, 0));    // Red Round Face
	fillcircle((j + 0.5) * B_SIZE, (i + 0.5) * B_SIZE, 0.4 * B_SIZE);
	setfillcolor(RGB(80, 80, 80));   // Black eyes
	setlinecolor(RGB(80, 80, 80));
	fillcircle((j + 0.3) * B_SIZE, (i + 0.45) * B_SIZE, 0.08 * B_SIZE);
	fillcircle((j + 0.7) * B_SIZE, (i + 0.45) * B_SIZE, 0.08 * B_SIZE);
	setlinestyle(PS_SOLID, 3);
	line((j + 0.35) * B_SIZE, (i + 0.7) * B_SIZE, (j + 0.65) * B_SIZE, (i + 0.7) * B_SIZE);
	setlinestyle(PS_SOLID, 1);
	FlushBatchDraw();
}

In update(), control the role movement according to the user keys:

if (input == 'A' || input == 'S' || input == 'D' || input == 'W')
{
	int goal_i = player.i;    // Define variable storage destination
	int goal_j = player.j;
	int goalNext_i = goal_i;  // Store target location and previous location
	int goalNext_j = goal_j;

	if (input == 'A')         // Towards the left
	{
		goal_j = player.j - 1;
		goalNext_j = goal_j - 1;
	}
	else if (input == 'D')    // Towards the right
	{
		goal_j = player.j + 1;
		goalNext_j = goal_j + 1;
	}
	else if (input == 'S')    // down
	{
		goal_i = player.i + 1;
		goalNext_i = goal_i + 1;
	}
	else if (input == 'W')    // Up
	{
		goal_i = player.i - 1;
		goalNext_i = goal_i - 1;
	}

Element Update

Assuming the role moves to the right, there are 13 scenarios:
(1) To the right of the character is empty. You can move it now.

(2) To the right of the role is the target. You can move it now.

(3) The right side of the character is the wall. It cannot be moved at this time.

(4) The right side of the role is box, and the right side is empty.

(5) The right side of the role is box, and then the right side is target. At this time, the role and box move to the right together

(6) The right side of the role is achieved, and the right side is empty.

(7) The right side of the role is achieved, and the right side is achieved. At this point, the role and box move to the right together

(8) The role has a box on the right and a wall on the right. It cannot be moved at this time.

(9) The role has a box on the right and a box on the right. It cannot be moved at this time.

(10) The role has a box on the right and achieved on the right. It cannot be moved at this time.

(11) The right side of the role is achieved, and the right side is wall. It cannot be moved at this time.

(12) The role has achieved on the right and box on the right. It cannot be moved at this time.

(13) The right side of the role is achieved, and the right side is achieved. It cannot be moved at this time.

Depending on the user's input, the variables goal_i and goal_j store the target location where the game character moves, and goalNext_i and goalNext_j store the target location one more place forward. There are six scenarios that move the game character and update the level elements to achieve the corresponding processing in update():

void update()
{
	if (_kbhit())
	{
		char input = _getch();
		if (input == 'A' || input == 'S' || input == 'D' || input == 'W')
		{
			int goal_i = player.i;    // Define variable storage destination
			int goal_j = player.j;
			int goalNext_i = goal_i;  // Store target location and previous location
			int goalNext_j = goal_j;

			if (input == 'A')         // Towards the left
			{
				goal_j = player.j - 1;
				goalNext_j = goal_j - 1;
			}
			else if (input == 'D')    // Towards the right
			{
				goal_j = player.j + 1;
				goalNext_j = goal_j + 1;
			}
			else if (input == 'S')    // down
			{
				goal_i = player.i + 1;
				goalNext_i = goal_i + 1;
			}
			else if (input == 'W')    // Up
			{
				goal_i = player.i - 1;
				goalNext_i = goal_i - 1;
			}

			// Update elements according to different situations
			if (level[goal_i][goal_j] == 'e' || level[goal_i][goal_j] == 't') // Target location is empty or target
			{
				player.i = goal_i;
				player.j = goal_j;
			}
			else if (level[goal_i][goal_j] == 'b' && level[goalNext_i][goalNext_j] == 'e') // The target location is box, followed by empty
			{
				player.i = goal_i;                                                         // Player moves to target position
				player.j = goal_j;
				level[goal_i][goal_j] = 'e';                                               // Target location becomes empty
				level[goalNext_i][goalNext_j] = 'b';                                       // Turn into a box in front
			}
			else if (level[goal_i][goal_j] == 'b' && level[goalNext_i][goalNext_j] == 't') // Target is box, followed by target
			{
				player.i = goal_i;                                                         // Player moves to target position
				player.j = goal_j;
				level[goal_i][goal_j] = 'e';                                               // Target location becomes empty
				level[goalNext_i][goalNext_j] = 'a';                                       // Beyond that becomes achieved
			}
			else if (level[goal_i][goal_j] == 'a' && level[goalNext_i][goalNext_j] == 'e') // The target location is achieved, followed by empty
			{
				player.i = goal_i;                                                         // Player moves to target position
				player.j = goal_j;
				level[goal_i][goal_j] = 't';                                               // Target position becomes target
				level[goalNext_i][goalNext_j] = 'b';                                       // Turn into a box in front
			}
			else if (level[goal_i][goal_j] == 'a' && level[goalNext_i][goalNext_j] == 't') // The target location is achieved, followed by target
			{
				player.i = goal_i;                                                         // Player moves to target position
				player.j = goal_j;
				level[goal_i][goal_j] = 't';                                               // Target position becomes target
				level[goalNext_i][goalNext_j] = 'a';                                       // Beyond that becomes achieved
			}
			else
			{
				return;
			}
		}
	}
}

Game Win Judgment

Define the number of global variables to store target s and achieved s:

int targetNum, achievedNum;

When traversing a two-dimensional array in startup(), add targetNum to 1 if the map element is target or achieved:

for (i = 0; i < B_NUM; i++)
{
	for (j = 0; j < B_NUM; j++)
	{
		if (level[i][j] == 'p')
		{
			player.i = i;
			player.j = j;
			level[i][j] = 'e';
		}
		else if (level[i][j] == 't' || level[i][j] == 'a')
		{
			targetNum++;
		}
	}
}

In the update() function, the number of achieved s for which the statistical element has been updated:

achievedNum = 0;
int i, j;
for (i = 0; i < B_NUM; i++)
{
	for (j = 0; j < B_NUM; j++)
	{
		if (level[i][j] == 'a')
		{
			achievedNum++;
		}
	}
}

If you achieve your goal, display the winning message in show():

if (achievedNum == targetNum)    // If Goals are Achieved
{
	setbkmode(TRANSPARENT);      // Transparent display text
	settextcolor(RGB(0, 255, 255));
	settextstyle(80, 0, _T("Song Style"));
	outtextxy(80, 200, _T("Game victory"));
}
FlushBatchDraw();

Multi-level implementation

Define a three-dimensional array levels to store all card map data, define a current LevelNum to represent the first level you are playing, and a two-dimensional array levels to store map data for the level you are playing:

// Get map data for the current tube
for (i = 0; i < B_NUM; i++)
{
	for (j = 0; j < B_NUM; j++)
	{
		level[i][j] = levels[currentLevelNum][i][j];
	}
}

In update(), if the current level is complete, add currentLevelNum to 1 and call startup() to start the initialization of the next level:

if (achievedNum == targetNum)
{
	show();																		   // Call to display the game winning screen
	if (currentLevelNum < LEVEL_TOTALNUM - 1)
	{
		currentLevelNum++;
		startup();                                                                 // Start Initialization of Next Level
	}
}

In show(), if there are still unfinished levels, show which level the game will start; if all levels are completed, prompt the game to win:

if (achievedNum == targetNum)    // If Goals are Achieved
{
	setbkmode(TRANSPARENT);      // Transparent display text
	settextcolor(RGB(0, 255, 100));
	TCHAR str[20];
	if (currentLevelNum < LEVEL_TOTALNUM - 1) // There are still unfinished levels
	{
		settextstyle(50, 0, _T("Song Style"));
		swprintf_s(str, _T("Beginning%d shut", currentLevelNum + 2));  // Prompt to start level
		outtextxy(120, 160, str);
		outtextxy(10, 250, _T("Press the space bar to play the current level again"));
	}
	else
	{
		settextstyle(80, 0, _T("Song Style"));
		outtextxy(80, 200, _T("Game victory"));
	}
	FlushBatchDraw();
	Sleep(2500);
}

Complete Code

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#define B_SIZE 60//Square Size
#define B_NUM 8 // Number of squares, a total of 8*8 squares
#define LEVEL_TOTALNUM 5 //How many levels in total

struct Player
{
	int i;
	int j;
};
Player player;

char levels[LEVEL_TOTALNUM][B_NUM][B_NUM + 1] =
{
	{"wwwwwwww", "wwwtbeew", "weeeeeew", "weeeeeew", "weeeeeew", "wepbteew", "weeewwww", "wwwwwwww"},
	{"wwwwwwww", "wwweewww", "wpetbwww", "weeebeww", "wewteeww", "weeeeeww", "weepwwww", "wwwwwwww"},
	{"wwwwwwww", "wwpeewww", "weeweeww", "webabeww", "weeteeww", "wwetewww", "wwwwwwww", "wwwwwwww"},
	{"wwwwwwww", "wwwwwwww", "weeeewww", "weeettew", "webbbpew", "weewetww", "wwwwwwww", "wwwwwwww"},
	{"wwwwwwww", "wwwwwwww", "wwteewww", "weewebpw", "weewewew", "weaeebtw", "weeeewww", "wwwwwwww"}
};
int currentLevelNum = 0;
char level[B_NUM][B_NUM + 1];
int targetNum, achievedNum;

void startup()
{
	initgraph(B_NUM * B_SIZE, B_NUM * B_SIZE);
	setbkcolor(RGB(150, 150, 150));             // Gray Background
	BeginBatchDraw();                           // Start batch drawing
	int i, j;

	// Get map data for the current tube
	for (i = 0; i < B_NUM; i++)
	{
		for (j = 0; j < B_NUM; j++)
		{
			level[i][j] = levels[currentLevelNum][i][j];
		}
	}

	targetNum = 0;
	achievedNum = 0;
	for (i = 0; i < B_NUM; i++)
	{
		for (j = 0; j < B_NUM; j++)
		{
			if (level[i][j] == 'p')
			{
				player.i = i;
				player.j = j;
				level[i][j] = 'e';
			}
			else if (level[i][j] == 't' || level[i][j] == 'a')
			{
				targetNum++;
			}
		}
	}
}

void show()
{
	int i, j;
	cleardevice();
	for (i = 0; i < B_NUM; i++)
	{
		for (j = 0; j < B_NUM; j++)
		{
			if (level[i][j] == 'e')              // white space
			{
				setfillcolor(RGB(150, 150, 150));// Draw gray ground
				setlinecolor(RGB(150, 150, 150));
				fillrectangle(j * B_SIZE, i * B_SIZE, (j + 1) * B_SIZE, (i + 1) * B_SIZE);
			}
			else if (level[i][j] == 'w')         // wall
			{
				setfillcolor(RGB(155, 0, 0));
				setlinecolor(RGB(150, 150, 150));// Box with light red and grey lines
				fillrectangle(j * B_SIZE, i * B_SIZE, (j + 1) * B_SIZE, (i + 1) * B_SIZE);
			}
			else if (level[i][j] == 'b')         // case
			{
				setfillcolor(RGB(255, 255, 0));  // Yellow Square
				setlinecolor(RGB(150, 150, 150));
				fillrectangle(j * B_SIZE, i * B_SIZE, (j + 1) * B_SIZE, (i + 1) * B_SIZE);
			}
			else if (level[i][j] == 't')         // target
			{
				setfillcolor(RGB(250, 250, 250));// Small white square
				fillrectangle((j + 0.3) * B_SIZE, (i + 0.3) * B_SIZE, (j + 0.7) * B_SIZE, (i + 0.7) * B_SIZE);
			}
			else if (level[i][j] == 'a')         // Goal Completed
			{
				setlinecolor(RGB(150, 150, 150));
				setfillcolor(RGB(255, 255, 0));  // Small yellow square
				fillrectangle(j * B_SIZE, i * B_SIZE, (j + 1) * B_SIZE, (i + 1) * B_SIZE);
				setfillcolor(RGB(250, 250, 250));// Small white square
				fillrectangle((j + 0.3) * B_SIZE, (i + 0.3) * B_SIZE, (j + 0.7) * B_SIZE, (i + 0.7) * B_SIZE);
			}
		}
	}
	// Draw Player
	i = player.i;
	j = player.j;
	setfillcolor(RGB(255, 0, 0));    // Red Round Face
	fillcircle((j + 0.5) * B_SIZE, (i + 0.5) * B_SIZE, 0.4 * B_SIZE);
	setfillcolor(RGB(80, 80, 80));   // Black eyes
	setlinecolor(RGB(80, 80, 80));
	fillcircle((j + 0.3) * B_SIZE, (i + 0.45) * B_SIZE, 0.08 * B_SIZE);
	fillcircle((j + 0.7) * B_SIZE, (i + 0.45) * B_SIZE, 0.08 * B_SIZE);
	setlinestyle(PS_SOLID, 3);
	line((j + 0.35) * B_SIZE, (i + 0.7) * B_SIZE, (j + 0.65) * B_SIZE, (i + 0.7) * B_SIZE);
	setlinestyle(PS_SOLID, 1);

	if (achievedNum == targetNum)    // If Goals are Achieved
	{
		setbkmode(TRANSPARENT);      // Transparent display text
		settextcolor(RGB(0, 255, 100));
		TCHAR str[20];
		if (currentLevelNum < LEVEL_TOTALNUM - 1) // There are still unfinished levels
		{
			settextstyle(50, 0, _T("Song Style"));
			swprintf_s(str, _T("Beginning%d shut"), currentLevelNum + 2);  // Prompt to start level
			outtextxy(120, 160, str);
			outtextxy(10, 250, _T("Press the space bar to play the current level again"));
		}
		else
		{
			settextstyle(80, 0, _T("Song Style"));
			outtextxy(80, 200, _T("Game victory"));
		}
		FlushBatchDraw();
		Sleep(2500);
	}
	FlushBatchDraw();
}

void update()
{
	if (_kbhit() && (achievedNum < targetNum))
	{
		char input = _getch();
		if (input == ' ')
		{
			startup();
		}
		if (input == 'A' || input == 'S' || input == 'D' || input == 'W')
		{
			int goal_i = player.i;    // Define variable storage destination
			int goal_j = player.j;
			int goalNext_i = goal_i;  // Store target location and previous location
			int goalNext_j = goal_j;

			if (input == 'A')         // Towards the left
			{
				goal_j = player.j - 1;
				goalNext_j = goal_j - 1;
			}
			else if (input == 'D')    // Towards the right
			{
				goal_j = player.j + 1;
				goalNext_j = goal_j + 1;
			}
			else if (input == 'S')    // down
			{
				goal_i = player.i + 1;
				goalNext_i = goal_i + 1;
			}
			else if (input == 'W')    // Up
			{
				goal_i = player.i - 1;
				goalNext_i = goal_i - 1;
			}

			// Update elements according to different situations
			if (level[goal_i][goal_j] == 'e' || level[goal_i][goal_j] == 't') // Target location is empty or target
			{
				player.i = goal_i;
				player.j = goal_j;
			}
			else if (level[goal_i][goal_j] == 'b' && level[goalNext_i][goalNext_j] == 'e') // The target location is box, followed by empty
			{
				player.i = goal_i;                                                         // Player moves to target position
				player.j = goal_j;
				level[goal_i][goal_j] = 'e';                                               // Target location becomes empty
				level[goalNext_i][goalNext_j] = 'b';                                       // Turn into a box in front
			}
			else if (level[goal_i][goal_j] == 'b' && level[goalNext_i][goalNext_j] == 't') // Target is box, followed by target
			{
				player.i = goal_i;                                                         // Player moves to target position
				player.j = goal_j;
				level[goal_i][goal_j] = 'e';                                               // Target location becomes empty
				level[goalNext_i][goalNext_j] = 'a';                                       // Beyond that becomes achieved
			}
			else if (level[goal_i][goal_j] == 'a' && level[goalNext_i][goalNext_j] == 'e') // The target location is achieved, followed by empty
			{
				player.i = goal_i;                                                         // Player moves to target position
				player.j = goal_j;
				level[goal_i][goal_j] = 't';                                               // Target position becomes target
				level[goalNext_i][goalNext_j] = 'b';                                       // Turn into a box in front
			}
			else if (level[goal_i][goal_j] == 'a' && level[goalNext_i][goalNext_j] == 't') // The target location is achieved, followed by target
			{
				player.i = goal_i;                                                         // Player moves to target position
				player.j = goal_j;
				level[goal_i][goal_j] = 't';                                               // Target position becomes target
				level[goalNext_i][goalNext_j] = 'a';                                       // Beyond that becomes achieved
			}
			else
			{
				return;
			}
		}
		achievedNum = 0;
		int i, j;
		for (i = 0; i < B_NUM; i++)
		{
			for (j = 0; j < B_NUM; j++)
			{
				if (level[i][j] == 'a')
				{
					achievedNum++;
				}
			}
		}
		
		if (achievedNum == targetNum)
		{
			show();																		   // Call to display the game winning screen
			if (currentLevelNum < LEVEL_TOTALNUM - 1)
			{
				currentLevelNum++;
				startup();                                                                 // Start Initialization of Next Level
			}
		}
	}
}

int main()
{
	startup();
	while (1)
	{
		show();
		update();
	}
	return 0;
}

Tags: C++

Posted on Tue, 05 Oct 2021 14:29:51 -0400 by theDog