游戏推箱子(c语言)
一、项目背景
游戏推箱子既能锻炼思维的严密性,又有很多乐趣。本章将用C语言实现一个简单的推箱子游戏,旨在介绍推箱子游戏的实现方法,并逐步介绍C语言图形编程的方法和技巧。
二、设计目的
- 如何实现二维数组定义,操作等功能
- 如何从键盘输入中获取键值信息
- 如何在图形方式下实现光标的显示和定位
- 如何对图像函数进行使用
- 如何通过C语言实现游戏的基本控制操作和相关设置
三、项目功能需求
1、屏幕绘图输出
能够实现绘制城墙,在空地上绘制箱子,在目的地绘制箱子,绘制小人和绘制目的地等功能
2、移动箱子
能够实现箱子的移动,包括目的地之间,空地之间和目的地与空地之间的箱子移动等功能
3、移动小人
能够实现小人的移动,从而推动箱子到目的地
4、游戏功能控制
能够实现根据用户的键盘输入,指定位置状态判断功能和游戏操作等功能
5、关口选择
能够实现游戏关卡的选择,游戏共分为4关,以便用户选择所需要的关卡数
四、系统的功能结构图

五、功能模块介绍
1、绘制地图模块
- 绘制出每一关卡的基本地图,包括绘制城墙,在空地上绘制箱子,在目的地绘制箱子,绘制小人和绘制目的地。
- 根据用户的每次操作绘制出操作后变化的地图信息**。**
2、移动控制模块
- 根据用户的输入信息来实现对小人的控制
- 根据用户的输入信息来判断箱子的移动状态
3、关口选择模块
- 根据用户的输入的关卡选择相应的关数,并且在用户过关后自动进入下一关
- 每关对应不同的地图形状,共分为四关,每关的难度依次增大
4、游戏操作模块
- 判断用户游戏是否过关,以及捕获用户的键盘输入信息
六、详细设计
1、主函数
功能设计
- 用于实现主界面的显示,并响应用户对菜单项的选择。
- 主菜单为用户提供了3种不同的操作选项,当用户在界面上输入需要的操作选项时,系统会自动执行该选项对应的功能。
- 个功能执行完之后,还能自动回到主菜单,便于用户进行其他操作。
主函数程序流程图

2、绘制地图模块
功能设计
- 绘制出每一关卡的基本地图。
- 地图的绘制包括绘制城墙,在空地上绘制箱子,在目的地绘制箱子,绘制小人和绘制目的地等操作。
- 根据用户的每次操作绘制出操作后变化的地图信息。
- 模块也包含了对文字颜色的具体设置
3、移动控制模块
功能设计
- 根据用户的键盘输入信息来实现对小人的控制。
- 需要分情况判断小人的状态,判断用户输入的操作能否被执行**。**
- 根据用户输入信息来判断箱子的移动状态。
模块流程图

4、关口选择模块
功能设计
- 根据用户的输入的关卡选择相应的关数。
- 每关对应不同的地图形状,地图由二维数组表示,共分为四关,每关的难度依次增大。
- 在用户过关后自动进入下一关**。**
模块流程图

5、游戏操作模块
功能设计
- 判断用户游戏是否过关,即与箱子匹配的目的地数目是否等于目的地个数。
- 捕获用户的键盘输入信息:如用户输入N表示进入下一关,用户输入Q表示返回主界面。
- 用户输入键盘上下左右键实现控制信息。
游戏操作模块流程图

七、代码
/*****推箱子游戏*****/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#define KEY_UP 72
#define KEY_DOWN 80
#define KEY_LEFT 75
#define KEY_RIGHT 77
#define KEY_RETURN 2
#define KEY_NEXT 4
#define SPACE_OUT 0
#define WALL 1
#define SPACE 2
#define TARGET 3
#define BOX 4
#define TARGET_IN 5
#define PERSON 6
/*函数声明*/
void SelectColor(int iColor);
void DesignUI();
int WelcomePage();/*初始界面,每次通关后跳回*/
void GetLevel1();
void GetLevel2();
void GetLevel3();
void GetLevel4();
int PlayGame(int aiMap[][16], int aiMap2[][16], int iSum, int iImp);
int PrintMap(int aiMap[][16], int iImp);
void MoveBox(int aiMap[][16], int iPlayerX, int iPlayerY, int iSelect, int aiMap2[][16]);
/*主函数*/
int main() {
while (1)
DesignUI();
}
/*文字颜色函数*/
void SelectColor(int iColor) //颜色函数
{
HANDLE hConsole =
GetStdHandle((STD_OUTPUT_HANDLE));//得到控制台输出设备的句柄
SetConsoleTextAttribute(hConsole, iColor);//设置控制台设备的属性
}
/*主界面函数*/
void DesignUI()
{
int iCh;
char cNum;
iCh = WelcomePage();
if (iCh == 49)/*键盘输入1,开始第一关游戏*/
GetLevel1();
else if (iCh == 50){/*键盘输入2,选择1到4关的游戏*/
printf("\n\t\t Please input level!(From 1 to 4):");
getchar();
cNum = getchar();
switch (cNum){
case '1':
GetLevel1();
break;
case '2':
GetLevel2();
break;
case '3':
GetLevel3();
break;
case '4':
GetLevel4();
break;
default:
printf("Enter error!\n");
Sleep(1000);
exit(0);
break;
}
}
else if (iCh == 51){/*键盘输入3,退出游戏*/
system("cls");
exit(0);
}
}
/*初始欢迎界面*/
int WelcomePage()
{
int i = 0;
system("cls");/*清屏*/
system("color 0E");/*设置颜色*/
printf("\n\n\t\t Welcome to play box!\n\n");
printf("\t\t Person:♀ Wall:▓ Box: ● Target:○ Reach target:☆\n");
printf("\t\t Up:↑\n\t\t Down:↓\n\t\t Left:← \n\t\t Right:→\n\n");
printf("\t\t Press number 1 to start new game\n\t\t\n");
printf("\t\t Press number 2 to choose level\n\t\t\n");
printf("\t\t Press number 3 to quit from game\n\t\t\n");
printf("\t\t Press right number to continue:");
while (1)
{
i = getchar();
if (i >= 49 && i <= 51)
return i;
}
}
/*打印地图函数*/
int PrintMap(int aiMap[][16], int iImp) {/*参数iImp代表游戏关卡*/
int i, j;
int iCount = 0;
for (i = 0; i<14; i++){
for (j = 0; j<16; j++)
{
switch (aiMap[i][j])
{
case 0: /*空地*/
printf(" ");
break;
case 1:
SelectColor(14); /*墙*/
printf("▓");
break;
case 2: /*内部空地*/
printf(" ");
break;
case 3:
SelectColor(11); /*目的地*/
printf("○");
break;
case 4: /*箱子*/
SelectColor(11);
printf("●");
break;
case 5: /*箱子推到目的地后显示*/
iCount++;
SelectColor(9);
printf("☆");
break;
case 6: /*小人*/
SelectColor(10);
printf("♀");
break;
}
}
printf("\n");
}
SelectColor(14);
printf("\n");
printf("\tYou are in Level %d!\t\t\n", iImp);
printf("\tPress arrow keys to play the game!\t\n");
printf("\tpress N to the next level!\t\n");
printf("\tpress Q to return the home page!\t\n");
return iCount; /*返回值表示以正确放入的箱子数*/
}
/*第一关*/
void GetLevel1() {
int aiMap2[14][16];/*表示原始地图*/
int i, j, iSum = 0; /*iSum表示箱子的数量*/
/*地图形状
1代表墙,2代表空地,3代表未放箱子的目标,4代表箱子,5代表以放箱子的目标,6代表小人
*/
int aiMap[14][16] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 1, 0, 0, 0, 0 },
{ 0, 0, 0, 1, 1, 3, 4, 2, 1, 1, 2, 1, 1, 0, 0, 0 },
{ 0, 0, 0, 1, 2, 3, 4, 6, 4, 2, 2, 3, 1, 0, 0, 0 },
{ 0, 0, 0, 1, 2, 3, 2, 4, 2, 4, 3, 1, 1, 0, 0, 0 },
{ 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 1, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
};
for (i = 0; i<14; i++)
for (j = 0; j<16; j++){
aiMap2[i][j] = aiMap[i][j];
if (aiMap[i][j] == TARGET || aiMap[i][j] == TARGET_IN)/*记录箱子个数*/
iSum++;
}
/*PlayGame函数返回值为4的情况代表键盘输入Q返回到主界面,
其他情况(过关,进入下一关)执行GetLevel2函数,进入第二关
*/
if (PlayGame(aiMap, aiMap2, iSum, 1) != KEY_RETURN)
GetLevel2();
}
/*第二关*/
void GetLevel2() {
int aiMap2[14][16];/*表示原始地图*/
int i, j, iSum = 0; /*iSum表示箱子的数量*/
/*地图形状
1代表墙,2代表空地,3代表未放箱子的目标,4代表箱子,5代表以放箱子的目标,6代表小人
*/
int aiMap[14][16] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
{ 0, 0, 0, 1, 2, 2, 1, 1, 2, 2, 2, 1, 0, 0, 0, 0 },
{ 0, 0, 0, 1, 2, 2, 2, 4, 2, 2, 2, 1, 0, 0, 0, 0 },
{ 0, 0, 0, 1, 2, 2, 1, 1, 1, 2, 4, 1, 0, 0, 0, 0 },
{ 0, 0, 0, 1, 2, 1, 3, 3, 3, 1, 2, 1, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 2, 1, 3, 3, 1, 1, 2, 1, 1, 0, 0, 0 },
{ 0, 0, 1, 2, 4, 2, 2, 4, 2, 2, 4, 2, 1, 0, 0, 0 },
{ 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 6, 2, 1, 0, 0, 0 },
{ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
};
for (i = 0; i<14; i++)
for (j = 0; j<16; j++){
aiMap2[i][j] = aiMap[i][j];
if (aiMap[i][j] == TARGET || aiMap[i][j] == TARGET_IN)/*记录箱子个数*/
iSum++;
}
/*PlayGame函数返回值为4的情况代表键盘输入Q返回到主界面,
其他情况(过关,进入下一关)执行GetLevel3函数,进入第三关
*/
if (PlayGame(aiMap, aiMap2, iSum, 2) != KEY_RETURN)
GetLevel3();
}
/*第三关*/
void GetLevel3() {
int aiMap2[14][16];/*表示原始地图*/
int i, j, iSum = 0;/*iSum表示箱子的数量*/
/*地图形状
1代表墙,2代表空地,3代表未放箱子的目标,4代表箱子,5代表以放箱子的目标,6代表小人
*/
int aiMap[14][16] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 0, 0 },
{ 0, 0, 1, 2, 4, 2, 1, 1, 1, 1, 4, 2, 2, 1, 0, 0 },
{ 0, 0, 1, 2, 2, 4, 3, 3, 3, 3, 2, 4, 2, 1, 0, 0 },
{ 0, 0, 1, 1, 2, 2, 2, 2, 1, 2, 6, 2, 1, 1, 0, 0 },
{ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
};
for (i = 0; i<14; i++)
for (j = 0; j<16; j++){
aiMap2[i][j] = aiMap[i][j];
if (aiMap[i][j] == TARGET || aiMap[i][j] == TARGET_IN)/*记录箱子个数*/
iSum++;
}
/*PlayGame函数返回值为4的情况代表键盘输入Q返回到主界面,
其他情况(过关,进入下一关)执行GetLevel5函数,进入第五关
*/
if (PlayGame(aiMap, aiMap2, iSum, 3) != KEY_RETURN)
GetLevel4();
}
/*第四关*/
void GetLevel4() {
int aiMap2[14][16];/*表示原始地图*/
int i, j, iSum = 0;/*iSum表示箱子的数量*/
/*地图形状
1代表墙,2代表空地,3代表未放箱子的目标,4代表箱子,5代表以放箱子的目标,6代表小人
*/
int aiMap[14][16] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 1, 2, 2, 2, 1, 3, 2, 1, 0, 0, 0 },
{ 0, 0, 0, 0, 1, 1, 2, 2, 4, 3, 3, 3, 1, 0, 0, 0 },
{ 0, 0, 0, 0, 1, 2, 2, 4, 2, 1, 5, 3, 1, 0, 0, 0 },
{ 0, 0, 0, 1, 1, 2, 1, 1, 4, 1, 2, 1, 1, 0, 0, 0 },
{ 0, 0, 0, 1, 2, 2, 2, 4, 2, 2, 4, 2, 1, 0, 0, 0 },
{ 0, 0, 0, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1, 0, 0, 0 },
{ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 6, 2, 1, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
};
for (i = 0; i<14; i++)
for (j = 0; j<16; j++){
aiMap2[i][j] = aiMap[i][j];
if (aiMap[i][j] == TARGET || aiMap[i][j] == TARGET_IN)/*记录箱子个数*/
iSum++;
}
/*PlayGame函数返回值为4的情况代表键盘输入Q返回到主界面,
其他情况(过关,进入下一关)执行GetLevel7函数,进入第七关
*/
PlayGame(aiMap, aiMap2, iSum, 4);
}
/*游戏操作函数*/
int PlayGame(int aiMap[][16], int aiMap2[][16], int iSum, int iImp)/*iSum代表箱子个数*/
{
int i, j;
int iPlayerX, iPlayerY; /*人的位置x,y坐标*/
char cOp; /*所按下的方向键*/
int iNum = 0; /*箱子推到目的地的个数*/
while (1)
{
for (i = 0; i < 14; i++)
{
for (j = 0; j < 16; j++) /*循环遍历寻找人的位置*/
{
if (aiMap[i][j] == PERSON) /*6代表人的位置*/
break;
}
if (j < 16)
break;
}
iPlayerX = i; /*将二维数组中的人的x,y坐标赋值给iPlayerX和iPlayerY*/
iPlayerY = j;
system("cls");
iNum = PrintMap(aiMap, iImp);
if (iNum == iSum)
{ /*将所有箱子都推到目的地*/
printf(" Congratulations!\n");
Sleep(3000);
return 0;
}
else
{ /*还有箱子没有推到目的地*/
cOp = getch(); /*捕获用户键盘输入*/
if ((cOp == 'n') || (cOp == 'N'))/*输入N进入下一关*/
return KEY_NEXT;
else if ((cOp == 'q') || (cOp == 'Q'))/*输入Q返回主界面*/
return KEY_RETURN;
}
switch (cOp)
{ /*用户输入方向键*/
case KEY_UP: /*上箭头*/
MoveBox(aiMap, iPlayerX, iPlayerY, 1, aiMap2);
break;
case KEY_LEFT: /*左箭头*/
MoveBox(aiMap, iPlayerX, iPlayerY, 2, aiMap2);
break;
case KEY_RIGHT: /*右箭头*/
MoveBox(aiMap, iPlayerX, iPlayerY, 3, aiMap2);
break;
case KEY_DOWN: /*下箭头*/
MoveBox(aiMap, iPlayerX, iPlayerY, 4, aiMap2);
break;
default:
break;
}
}
}
/*方向移动函数*/
void MoveBox(int aiMap[][16], int iPlayerX, int iPlayerY, int iSelect, int aiMap2[][16]) {
int iPlayerX1, iPlayerY1; /*小人下一个要走的位置坐标*/
int iPlayerX2, iPlayerY2; /*小人下下一个要走的位置坐标*/
switch (iSelect) {
case 1: /*向上移动*/
iPlayerX1 = iPlayerX - 1;
iPlayerY1 = iPlayerY;
iPlayerX2 = iPlayerX - 2;
iPlayerY2 = iPlayerY;
break;
case 2: /*向左移动*/
iPlayerX1 = iPlayerX;
iPlayerY1 = iPlayerY - 1;
iPlayerX2 = iPlayerX;
iPlayerY2 = iPlayerY - 2;
break;
case 3: /*向右移动*/
iPlayerX1 = iPlayerX;
iPlayerY1 = iPlayerY + 1;
iPlayerX2 = iPlayerX;
iPlayerY2 = iPlayerY + 2;
break;
case 4: /*向下移动*/
iPlayerX1 = iPlayerX + 1;
iPlayerY1 = iPlayerY;
iPlayerX2 = iPlayerX + 2;
iPlayerY2 = iPlayerY;
break;
default:
break;
}
/*对地图的操作*/
switch (aiMap[iPlayerX1][iPlayerY1])/*判断小人下一步要走的位置*/
{
case WALL: /*下一位置是墙,不能移动*/
break;
case SPACE: /*下一位置为墙内空地和下一位置为空目的地的情况相同处理*/
case TARGET:
aiMap[iPlayerX1][iPlayerY1] = PERSON;/*小人移动到下一位置*/
if (aiMap2[iPlayerX][iPlayerY] == TARGET || aiMap2[iPlayerX][iPlayerY] == TARGET_IN)
/*小人所在位置初始为空目的地或满目的地,小人移动后此处恢复为空目的地*/
aiMap[iPlayerX][iPlayerY] = TARGET;
else
/*小人所在位置初始为墙内空地、箱子或者小人,小人移动后此处恢复为墙内空地*/
aiMap[iPlayerX][iPlayerY] = SPACE;
break;
case BOX: /*下一位置是箱子和下一位置是已放箱子目的地的情况相同处理*/
case TARGET_IN:
if (aiMap[iPlayerX2][iPlayerY2] == TARGET)
{
/*下下位置为空目的地,箱子和小人一起移动,箱子落入目的地*/
aiMap[iPlayerX2][iPlayerY2] = TARGET_IN;
aiMap[iPlayerX1][iPlayerY1] = PERSON;
}
else if (aiMap[iPlayerX2][iPlayerY2] == SPACE)
{
/*下下位置为空地,箱子和小人一起移动,箱子落入空地*/
aiMap[iPlayerX2][iPlayerY2] = BOX;
aiMap[iPlayerX1][iPlayerY1] = PERSON;
}
else/*下下位置为墙、箱子或者满目的地,不能移动,直接退出*/
break;
if (aiMap2[iPlayerX][iPlayerY] == TARGET || aiMap2[iPlayerX][iPlayerY] == TARGET_IN)
/*小人所在位置初始为空目的地或满目的地,小人移动后此处恢复为空目的地*/
aiMap[iPlayerX][iPlayerY] = TARGET;
else/*小人所在位置初始为墙内空地、箱子或者小人,小人移动后此处恢复为墙内空地*/
aiMap[iPlayerX][iPlayerY] = SPACE;
break;
}
}
&spm=1001.2101.3001.5002&articleId=120538713&d=1&t=3&u=057181e412de4f029c30875cc151eac4)
1万+

被折叠的 条评论
为什么被折叠?



