游戏一共有6种元素:
(1)空白区域:玩家可以穿过,箱子可以推上去;英文名称:empty;缩写:‘e’
(2)墙:玩家不能经过,箱子不能推过去;英文名称:wall;缩写:‘w’
(3)箱子:在前面没有障碍物的情况下,玩家可以推动;英文名称:box;缩写:‘b’
(4)空白目标:需要玩家将箱子推上去;英文名称:target;缩写:‘t’
(5)完成目标:一个箱子在目标上的叠加状态;英文名称:achieved;缩写:‘a’
(6)游戏角色:可以键盘控制移动,推动箱子到达目标;英文名称:player;缩写:‘p’
定义全局变量level存储地图数据,在show()函数中根据level[i][j]的值绘制图案:
#include
#include
#include
#define B_SIZE 60 // 方块大小
#define B_NUM 8 // 方块个数,一共8*8个方块
// 用字符型二维数组存储地图数据
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)); // 灰色背景
BeginBatchDraw(); // 开始批量绘制
}
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') // 空白区域
{
setfillcolor(RGB(150, 150, 150));// 绘制灰色地面
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') // 墙
{
setfillcolor(RGB(155, 0, 0));
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] == 'b') // 箱子
{
setfillcolor(RGB(255, 255, 0)); // 黄色方块
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') // 目标
{
setfillcolor(RGB(250, 250, 250));// 白色小方块
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') // 已完成目标
{
setlinecolor(RGB(150, 150, 150));
setfillcolor(RGB(255, 255, 0)); // 黄色小方块
fillrectangle(j * B_SIZE, i * B_SIZE, (j + 1) * B_SIZE, (i + 1) * B_SIZE);
setfillcolor(RGB(250, 250, 250));// 白色小方块
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') // 玩家
{
setfillcolor(RGB(255, 0, 0)); // 红色圆脸
fillcircle((j + 0.5) * B_SIZE, (i + 0.5) * B_SIZE, 0.4 * B_SIZE);
setfillcolor(RGB(80, 80, 80)); // 黑色眼睛
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;
}
定义结构体Player记录玩家位置:
struct Player
{
int i;
int j;
};
Player player;
遍历二维数组level,找到’p’的位置,即玩家位置,赋值给player,再把’p’变成’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';
}
}
}
将show()中对玩家的绘制独立出来,根据player中存储的位置,绘制玩家:
```cpp
void show()
{
i = player.i;
j = player.j;
setfillcolor(RGB(255, 0, 0)); // 红色圆脸
fillcircle((j + 0.5) * B_SIZE, (i + 0.5) * B_SIZE, 0.4 * B_SIZE);
setfillcolor(RGB(80, 80, 80)); // 黑色眼睛
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();
}
在update()中,根据用户按键,控制角色移动:
if (input == 'A' || input == 'S' || input == 'D' || input == 'W')
{
int goal_i = player.i; // 定义变量存储目标位置
int goal_j = player.j;
int goalNext_i = goal_i; // 存储目标位置再前一个位置
int goalNext_j = goal_j;
if (input == 'A') // 向左
{
goal_j = player.j - 1;
goalNext_j = goal_j - 1;
}
else if (input == 'D') // 向右
{
goal_j = player.j + 1;
goalNext_j = goal_j + 1;
}
else if (input == 'S') // 向下
{
goal_i = player.i + 1;
goalNext_i = goal_i + 1;
}
else if (input == 'W') // 向上
{
goal_i = player.i - 1;
goalNext_i = goal_i - 1;
}
假设角色向右移动,有以下13种情况:
(1)角色右边是empty。此时可以移动
(2)角色右边是target。此时可以移动
(3)角色右边是wall。此时不可以移动
(4)角色右边是box,再右边是empty。此时角色和box一起右移
(5)角色右边是box,再右边是target。此时角色和box一起右移
(6)角色右边是achieved,再右边是empty。此时角色和box一起右移
(7)角色右边是achieved,再右边是achieved。此时角色和box一起右移
(8)角色右边是box,再右边是wall。此时不可以移动
(9)角色右边是box,再右边是box。此时不可以移动
(10)角色右边是box,再右边是achieved。此时不可以移动
(11)角色右边是achieved,再右边是wall。此时不可以移动
(12)角色右边是achieved,再右边是box。此时不可以移动
(13)角色右边是achieved,再右边是achieved。此时不可以移动
根据用户的不同输入,变量goal_i、goal_j存储游戏角色移动的目标位置,goalNext_i、goalNext_j存储目标位置再向前的一个位置。共有6种情况会移动游戏角色及更新关卡元素,在update()中实现相应的处理:
void update()
{
if (_kbhit())
{
char input = _getch();
if (input == 'A' || input == 'S' || input == 'D' || input == 'W')
{
int goal_i = player.i; // 定义变量存储目标位置
int goal_j = player.j;
int goalNext_i = goal_i; // 存储目标位置再前一个位置
int goalNext_j = goal_j;
if (input == 'A') // 向左
{
goal_j = player.j - 1;
goalNext_j = goal_j - 1;
}
else if (input == 'D') // 向右
{
goal_j = player.j + 1;
goalNext_j = goal_j + 1;
}
else if (input == 'S') // 向下
{
goal_i = player.i + 1;
goalNext_i = goal_i + 1;
}
else if (input == 'W') // 向上
{
goal_i = player.i - 1;
goalNext_i = goal_i - 1;
}
// 根据不同情况,更新元素
if (level[goal_i][goal_j] == 'e' || level[goal_i][goal_j] == 't') // 目标位置是empty或target
{
player.i = goal_i;
player.j = goal_j;
}
else if (level[goal_i][goal_j] == 'b' && level[goalNext_i][goalNext_j] == 'e') // 目标位置是box,再前面是empty
{
player.i = goal_i; // 玩家移动到目标位置
player.j = goal_j;
level[goal_i][goal_j] = 'e'; // 目标位置变成empty
level[goalNext_i][goalNext_j] = 'b'; // 再前面变成box
}
else if (level[goal_i][goal_j] == 'b' && level[goalNext_i][goalNext_j] == 't') // 目标是box,再前面是target
{
player.i = goal_i; // 玩家移动到目标位置
player.j = goal_j;
level[goal_i][goal_j] = 'e'; // 目标位置变成empty
level[goalNext_i][goalNext_j] = 'a'; // 再前面变成achieved
}
else if (level[goal_i][goal_j] == 'a' && level[goalNext_i][goalNext_j] == 'e') // 目标位置是achieved,再前面是empty
{
player.i = goal_i; // 玩家移动到目标位置
player.j = goal_j;
level[goal_i][goal_j] = 't'; // 目标位置变成target
level[goalNext_i][goalNext_j] = 'b'; // 再前面变成box
}
else if (level[goal_i][goal_j] == 'a' && level[goalNext_i][goalNext_j] == 't') // 目标位置是achieved,再前面是target
{
player.i = goal_i; // 玩家移动到目标位置
player.j = goal_j;
level[goal_i][goal_j] = 't'; // 目标位置变成target
level[goalNext_i][goalNext_j] = 'a'; // 再前面变成achieved
}
else
{
return;
}
}
}
}
定义全局变量存储target个数、和achieved个数:
int targetNum, achievedNum;
在startup()中遍历二维数组时,如果地图元素为target或achieved,则将targetNum加1:
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++;
}
}
}
在update()函数中统计元素更新后的achieved个数:
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++;
}
}
}
如果完成目标,在show()中显示游戏胜利信息:
if (achievedNum == targetNum) // 如果完成目标
{
setbkmode(TRANSPARENT); // 透明显示文字
settextcolor(RGB(0, 255, 255));
settextstyle(80, 0, _T("宋体"));
outtextxy(80, 200, _T("游戏胜利"));
}
FlushBatchDraw();
定义三维数组levels存储所有关卡地图数据,定义currentLevelNum表示当前玩到第几关,二维数组level存储正在玩的这一关的地图数据:
// 获取当前管的地图数据
for (i = 0; i < B_NUM; i++)
{
for (j = 0; j < B_NUM; j++)
{
level[i][j] = levels[currentLevelNum][i][j];
}
}
在update()中,如果当前关卡完成,就将currentLevelNum加1,并调用startup()开始下一关的初始化:
if (achievedNum == targetNum)
{
show(); // 调用显示游戏胜利画面
if (currentLevelNum < LEVEL_TOTALNUM - 1)
{
currentLevelNum++;
startup(); // 开始下一关的初始化
}
}
在show()中,如果还有未完成的关卡,显示将要开始第几关游戏;如果所有关卡都完成了,提示游戏胜利:
if (achievedNum == targetNum) // 如果完成目标
{
setbkmode(TRANSPARENT); // 透明显示文字
settextcolor(RGB(0, 255, 100));
TCHAR str[20];
if (currentLevelNum < LEVEL_TOTALNUM - 1) // 还有未完成的关卡
{
settextstyle(50, 0, _T("宋体"));
swprintf_s(str, _T("开始第%d关", currentLevelNum + 2)); // 提示开始第几关
outtextxy(120, 160, str);
outtextxy(10, 250, _T("按空格键重玩当前关"));
}
else
{
settextstyle(80, 0, _T("宋体"));
outtextxy(80, 200, _T("游戏胜利"));
}
FlushBatchDraw();
Sleep(2500);
}
#include
#include
#include
#define B_SIZE 60 // 方块大小
#define B_NUM 8 // 方块个数,一共8*8个方块
#define LEVEL_TOTALNUM 5 // 一共多少关卡
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)); // 灰色背景
BeginBatchDraw(); // 开始批量绘制
int i, j;
// 获取当前管的地图数据
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') // 空白区域
{
setfillcolor(RGB(150, 150, 150));// 绘制灰色地面
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') // 墙
{
setfillcolor(RGB(155, 0, 0));
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] == 'b') // 箱子
{
setfillcolor(RGB(255, 255, 0)); // 黄色方块
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') // 目标
{
setfillcolor(RGB(250, 250, 250));// 白色小方块
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') // 已完成目标
{
setlinecolor(RGB(150, 150, 150));
setfillcolor(RGB(255, 255, 0)); // 黄色小方块
fillrectangle(j * B_SIZE, i * B_SIZE, (j + 1) * B_SIZE, (i + 1) * B_SIZE);
setfillcolor(RGB(250, 250, 250));// 白色小方块
fillrectangle((j + 0.3) * B_SIZE, (i + 0.3) * B_SIZE, (j + 0.7) * B_SIZE, (i + 0.7) * B_SIZE);
}
}
}
// 绘制玩家
i = player.i;
j = player.j;
setfillcolor(RGB(255, 0, 0)); // 红色圆脸
fillcircle((j + 0.5) * B_SIZE, (i + 0.5) * B_SIZE, 0.4 * B_SIZE);
setfillcolor(RGB(80, 80, 80)); // 黑色眼睛
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) // 如果完成目标
{
setbkmode(TRANSPARENT); // 透明显示文字
settextcolor(RGB(0, 255, 100));
TCHAR str[20];
if (currentLevelNum < LEVEL_TOTALNUM - 1) // 还有未完成的关卡
{
settextstyle(50, 0, _T("宋体"));
swprintf_s(str, _T("开始第%d关"), currentLevelNum + 2); // 提示开始第几关
outtextxy(120, 160, str);
outtextxy(10, 250, _T("按空格键重玩当前关"));
}
else
{
settextstyle(80, 0, _T("宋体"));
outtextxy(80, 200, _T("游戏胜利"));
}
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; // 定义变量存储目标位置
int goal_j = player.j;
int goalNext_i = goal_i; // 存储目标位置再前一个位置
int goalNext_j = goal_j;
if (input == 'A') // 向左
{
goal_j = player.j - 1;
goalNext_j = goal_j - 1;
}
else if (input == 'D') // 向右
{
goal_j = player.j + 1;
goalNext_j = goal_j + 1;
}
else if (input == 'S') // 向下
{
goal_i = player.i + 1;
goalNext_i = goal_i + 1;
}
else if (input == 'W') // 向上
{
goal_i = player.i - 1;
goalNext_i = goal_i - 1;
}
// 根据不同情况,更新元素
if (level[goal_i][goal_j] == 'e' || level[goal_i][goal_j] == 't') // 目标位置是empty或target
{
player.i = goal_i;
player.j = goal_j;
}
else if (level[goal_i][goal_j] == 'b' && level[goalNext_i][goalNext_j] == 'e') // 目标位置是box,再前面是empty
{
player.i = goal_i; // 玩家移动到目标位置
player.j = goal_j;
level[goal_i][goal_j] = 'e'; // 目标位置变成empty
level[goalNext_i][goalNext_j] = 'b'; // 再前面变成box
}
else if (level[goal_i][goal_j] == 'b' && level[goalNext_i][goalNext_j] == 't') // 目标是box,再前面是target
{
player.i = goal_i; // 玩家移动到目标位置
player.j = goal_j;
level[goal_i][goal_j] = 'e'; // 目标位置变成empty
level[goalNext_i][goalNext_j] = 'a'; // 再前面变成achieved
}
else if (level[goal_i][goal_j] == 'a' && level[goalNext_i][goalNext_j] == 'e') // 目标位置是achieved,再前面是empty
{
player.i = goal_i; // 玩家移动到目标位置
player.j = goal_j;
level[goal_i][goal_j] = 't'; // 目标位置变成target
level[goalNext_i][goalNext_j] = 'b'; // 再前面变成box
}
else if (level[goal_i][goal_j] == 'a' && level[goalNext_i][goalNext_j] == 't') // 目标位置是achieved,再前面是target
{
player.i = goal_i; // 玩家移动到目标位置
player.j = goal_j;
level[goal_i][goal_j] = 't'; // 目标位置变成target
level[goalNext_i][goalNext_j] = 'a'; // 再前面变成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(); // 调用显示游戏胜利画面
if (currentLevelNum < LEVEL_TOTALNUM - 1)
{
currentLevelNum++;
startup(); // 开始下一关的初始化
}
}
}
}
int main()
{
startup();
while (1)
{
show();
update();
}
return 0;
}