1 项目需求
实现一款推箱子游戏,效果如下图所示,具体规则:
- 箱子只能推动而不能拉动;
- 如果箱子前一格是地板或箱子目的地,则可以推动一个箱子往前走一格,如果箱子已经在箱子目的地则不能再推动;
- 推箱子的小人不能从箱子目的地上直接穿过;
- 注意不要把箱子推到死角上,不然就无法再推动它了;
- 所有箱子都成功推到箱子目的地,游戏结束,过关成功!
2 模块划分
作用:
- 化繁为简 。
- 适合团队协作。
- 高质量代码。
3 项目实现
3.1 地图初始化
搭台唱戏: 戏台坐标系(650 x 650)。
地图表示: 使用二维数组 。
- 游戏道具显示(墙、箱子、箱子目的地、小人、地板)。
- 便于程序在游戏过程中进行逻辑判断和控制小人向前一步的动作控制。
- 判断游戏结果。
道具表示:
- 墙:0
- 地板:1
- 箱子目的地:2
- 小人:3
- 箱子:4
- 箱子命中目标:5
#include <graphics.h>
#include <iostream>
#include <stdlib.h>
#include <string>
using namespace std;
#define RATIO 61
#define SCREEN_WIDTH 960
#define SCREEN_HEIGHT 768
#define LINE 9
#define COLUMN 12
#define START_X 100
#define START_Y 150
IMAGE images[6];
/*游戏地图*/
int map[LINE][COLUMN] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
{ 0, 1, 4, 1, 0, 2, 1, 0, 2, 1, 0, 0 },
{ 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0 },
{ 0, 1, 0, 2, 0, 1, 1, 4, 1, 1, 1, 0 },
{ 0, 1, 1, 1, 0, 3, 1, 1, 1, 4, 1, 0 },
{ 0, 1, 2, 1, 1, 4, 1, 1, 1, 1, 1, 0 },
{ 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }};
int main(void) {
IMAGE bg_img; //搭台唱戏
initgraph(SCREEN_WIDTH, SCREEN_HEIGHT);
loadimage(&bg_img, _T("blackground.bmp"), SCREEN_WIDTH, SCREEN_HEIGHT, true);
putimage(0, 0, &bg_img); //加载道具图标
loadimage(&images[0], _T("wall.bmp"), RATIO, RATIO, true);
loadimage(&images[1], _T("floor.bmp"), RATIO, RATIO, true);
loadimage(&images[2], _T("des.bmp"), RATIO, RATIO, true);
loadimage(&images[3], _T("man.bmp"), RATIO, RATIO, true);
loadimage(&images[4], _T("box.bmp"), RATIO, RATIO, true);
loadimage(&images[5], _T("box.bmp"), RATIO, RATIO, true);
for(int i = 0; i< LINE; i++){
for(int j = 0; j < COLUMN; j++){
putimage(START_X+j*RATIO, START_Y+i*RATIO, &images[map[i][j]]);
}
}
system("pause");
return 0;
}
3.2 热键控制
热键定义: 左 => a 下=> s 上=> w 右 => d 退出 => q。
#include <conio.h>
//控制键 上、下、左、右 控制方向,'q' 退出
#define KEY_UP 'w'
#define KEY_LEFT 'a'
#define KEY_RIGHT 'd'
#define KEY_DOWN 's'
#define KEY_QUIT 'q'
//游戏环节
bool quit = false;
do {
if(_kbhit()){
//玩家按键
char ch = _getch();
if (ch == KEY_UP){
gameControl(UP);
}else if(ch == KEY_DOWN){
gameControl(DOWN);
}else if(ch == KEY_LEFT){
gameControl(LEFT);
}else if(ch == KEY_RIGHT){
gameControl(RIGHT);
}else if(ch == KEY_QUIT){
quit = true;
}
}
Sleep(100);
}while(quit==false); //!quit
3.3 推箱子控制
/**********************************************
*实现游戏四个方向(上、下、左、右)的控制
* 输入:
* direct - 人前进方向
* 输出: 无
**********************************************/
void gameControl(enum _DIRECTION direct) {
struct _POS next_pos = man;
struct _POS next_next_pos = man;
switch (direct) {
case UP:
next_pos.x--;
next_next_pos.x -= 2;
break;
case DOWN:
next_pos.x++;
next_next_pos.x += 2;
break;
case LEFT:
next_pos.y--;
next_next_pos.y -= 2;
break;
case RIGHT:
next_pos.y++;
next_next_pos.y += 2;
break;
}
//宏展开 next_pos.x>=0 && next_pos.x<LINE && next_pos.y>=0 && next_pos.y <COLUMN
if( isValid(next_pos) && map[next_pos.x][next_pos.y] == FLOOR ){// 人的前方是地板
changeMap(&next_pos, MAN); //小人前进一格
changeMap(&man, FLOOR);
man = next_pos;
}else if(isValid(next_next_pos) && map[next_pos.x][next_pos.y] == BOX){//人的前方是箱子
//两种情况,箱子前面是地板或者是箱子目的地
if( map[next_next_pos.x][next_next_pos.y] == FLOOR){
changeMap(&next_next_pos, BOX);
changeMap(&next_pos, MAN); //小人前进一格
changeMap(&man, FLOOR);
man = next_pos;
}else if(map[next_next_pos.x][next_next_pos.y] == BOX_DES){
changeMap(&next_next_pos, HIT);
changeMap(&next_pos, MAN); //小人前进一格
changeMap(&man, FLOOR);
man = next_pos;
}
}
}
3.4 游戏结束
/**********************************************
*判断游戏是否结束,如果不存在任何一个箱子目的地,就代表游戏结束
*输入: 无
*返回值:
* true - 游戏结束 false - 游戏继续
**********************************************/
bool isGameOver() {
for (int i = 0; i< LINE; i++) {
for (int j = 0; j < COLUMN; j++) {
if (map[i][j] == BOX_DES)
return false;
}
}return true;
}
/**********************************************
*游戏结束场景,在玩家通关后显示
*输入:
* bg - 背景图片变量的指针
*返回值: 无
**********************************************/
void gameOverScene(IMAGE *bg) {
putimage(0, 0, bg);
settextcolor(WHITE);
RECT rec = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };
settextstyle(20, 0, _T("宋体"));
drawtext(_T("恭喜您~ \n 您终于成为了一个合格的搬箱子老司机!"),
&rec, DT_CENTER | DT_VCENTER | DT_SINGLELINE); }
//main 函数中
if(isGameOver()){
gameOverScene(&bg_img);
quit = true;
}