#include<stdio.h>
#include<graphics.h> //图形
#include<iostream>
#include<string>
#include<conio.h> //热键
using namespace std;
//图像大小
#define RATIO 61
//初始化的地图大小
#define SCREEN_WIDTH 960
#define SCREEN_HEIGHT 768
//地图的二维数组
#define LINE 9
#define COLUMN 12
//控制键: 上,下,左,右 (控制方向) 'q'退出
#define KEY_UP 'w' //char 'a'
#define KEY_DOWN 's'
#define KEY_LEFT 'a'
#define KEY_RIGHT 'd'
#define KEY_QUIT 'q'
//地图界面离(0,0)点的距离 (偏移量)
#define START_X 100
#define START_Y 100
//判断是否越界
#define isValid(pos) pos.x>=0 && pos.x<LINE &&pos.y>=0 && pos.y<COLUMN
typedef enum _PROPS PROPS;
typedef enum _DIRECTION DIRECTION;
typedef struct _POS POS;
//枚举 游戏道具
enum _PROPS{
WALL, //墙
FLOOR, //地板
BOX_DES, //箱子目的地
GIRL, //主角
BOX, //箱子
HIT, //箱子命中目标
ALL //道具的数量
};
//枚举 游戏控制方向
enum _DIRECTION{
UP,
DOWN,
LEFT,
RIGHT
};
//结构体
struct _POS{
int x; //小人所在二维数组的行
int y; //小人所在二维数组的列
};
IMAGE images[ALL];
struct _POS girl; //结构体定义 (小人在二维数组的位置)
bool isDes = false; //被覆盖的开关
/*游戏地图*/
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 },
};
/**********************************************
*判断游戏是否结束,如果不存在任何一个箱子目的地,就代表游戏结束
*输入: 无
*返回值:
* 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("恭喜你!终于成为一名推箱子的老司机了"), &rec, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
/************************
*改变游戏地图视图中的一格对应道具并重新显示
*输入:
* line - 道具在地图数组的行标
* column - 道具在地图数组的列下标
* prop - 道具的类型
*返回值: 无
************************/
void changeMap(POS *pos, PROPS prop){
map[pos->x][pos->y] = prop;
putimage(pos->y * RATIO+START_X, pos->x * RATIO+START_Y, &images[prop]);
};
/************************
*实现游戏四个方向(上 下 左 右)的控制'
*输入:
*direct - 人前进的方向
*输出: 无
************************/
void gameControl(DIRECTION direct){
POS next_pos = girl;
POS next_next_pos = girl;
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;
}
//宏展开 #define isValid(pos) pos.x>=0 && pos.x<LINE &&pos.y>=0 && pos.y<COLUMN
if(isValid(next_pos) && map[next_pos.x][next_pos.y] == FLOOR){//人的前方是地板
changeMap(&next_pos, GIRL);
if (isDes)
{
changeMap(&girl, BOX_DES);
isDes = false;
}
else
{
changeMap(&girl, FLOOR);
}
girl = next_pos;
}
else if(isValid(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, GIRL);
//changeMap(&girl, FLOOR);
if (isDes)
{
changeMap(&girl, BOX_DES);
isDes = false;
}
else
{
changeMap(&girl, FLOOR);
}
girl = next_pos;
}else if(map[next_next_pos.x][next_next_pos.y] == BOX_DES){ //下下一步是箱子目的地的话就说明,箱子的下一步是目的地(命中目标),女孩的下一步是箱子,所以女孩的位置改变为地板,所以不需要进行开关判断(因为女孩的位置没有到达目的地,所以不需要进行判断)
changeMap(&next_next_pos, HIT);
changeMap(&next_pos, GIRL);
changeMap(&girl, FLOOR);
girl = next_pos;
}
}
else if(isValid(next_pos) && map[next_pos.x][next_pos.y] == BOX_DES){ //下一步是目的地的话就开启开关
isDes = true;
changeMap(&next_pos, GIRL);
changeMap(&girl, FLOOR);
girl = next_pos;
}
else if (isValid(next_pos) && map[next_pos.x][next_pos.y] == HIT && map[next_next_pos.x][next_next_pos.y] != WALL) {//女孩的下一步是命中目标的话,那就开启开关进行判断
isDes = true;
changeMap(&next_next_pos, BOX);
changeMap(&next_pos, GIRL);
changeMap(&girl, FLOOR);
girl = next_pos;
}
}
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);
//加载道具图形并存放进images数组里面
loadimage(&images[WALL], _T("wall_right.bmp"), RATIO, RATIO, true);
loadimage(&images[FLOOR], _T("floor.bmp"), RATIO, RATIO, true);
loadimage(&images[BOX_DES], _T("des.bmp"), RATIO, RATIO, true);
loadimage(&images[GIRL], _T("girl.bmp"), RATIO, RATIO, true);
loadimage(&images[BOX], _T("box.bmp"), RATIO, RATIO, true);
loadimage(&images[HIT], _T("box.bmp"), RATIO, RATIO, true);
//放置图形
for(int i=0;i<9;i++){
for(int j=0;j<12;j++){
if(map[i][j] == GIRL){
girl.x = i; //结构体赋值
girl.y = j; //结构体赋值
}
putimage(j*RATIO+START_X, i*RATIO+START_Y, &images[map[i][j]]);
}
}
//游戏环节
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;
}
if(isGameOver()){
gameOverScene(&bg_img);
quit = true;
}
}
Sleep(100);
}while(quit == false);
system("pause");
//游戏结束,释放资源
closegraph();
return 0;
}
推箱子项目
最新推荐文章于 2022-09-03 16:30:02 发布