【自用13.1】C++推箱子游戏

57 篇文章 0 订阅
30 篇文章 0 订阅

以下是初版代码,进行了初步的简单优化,具体思路以及优化步骤已经在备注中标明。

后期根据情况会出详细版的讲解。

#include <graphics.h>
#include <iostream>
#include <stdlib.h>
#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
#define START_X 100
#define START_Y 150

#define isValid(pos) pos.x>0 && pos.x<LINE && pos.y>0 && pos.y<COLUMN

//控制键上下左右控制方向,q退出,增强代码可读性
#defin KEY_UP 'w'
#defin KEY_DOWN 's'
#defin KEY_LEFT 'a'
#defin KEY_RIGHT 'd'
#defin KEY_QUIT 'q'

//IMAGE images[6];//全局变量设置图标种类数目

enum _PROPS{
    WALL, //墙
    FLOOR, //地板
    BOX_DES, //箱子目的地
    MAN, //小人
    BOX, //箱子
    HIT, //箱子命中目标
    ALL
};

struct _POS{
    int x;//小人所在的二维数组的行
    int y;//小人所在的二维数组的列
}

IMAGE images[ALL];

enum _DIRECTION{
    UP,
    DOWN,
    LEFT,
    RIGHT
};

/*游戏地图*/
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("恭喜您!\n通过关卡!"),&rec,DT_CENTER|DT_VCENTER|DT_SINGLELINE);//水平居中|垂直居中|文字显示单行
}

/*******************************************************
 *改变游戏地图视图中一格对应道具并重新显示
 *输入:
 *    line-道具在地图数组的行下标
 *    column-道具在地图数组的列下标
 *    prop-道具的类型
 *返回值:无
 ******************************************************/
void changeMap(struct _POS pos, enum _PROPS prop){//int line,int column
    //map[line][column]=prop;
    map[pos->x][pos->y]=prop;
    //putimage(START_X+column*RATIO, START_Y+line*RATIO,&images[prop]);
    putimage(START_X+pos->y*RATIO, START_Y+pos->x*RATIO,&images[prop]);
}

/*******************************************************
 *实现游戏四个方向(上下左右)的控制
 *输入:
 *    direct-人前进方向
 *输出:无
 ******************************************************/
void getControl(enum _DIRECTION direct){
    //int x=man.x;
    //int y=man.y;

    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(isVaild(next_pos) && map[next_pos.x][next_pos.y]==FLOOR){//人的前方是地板
        //changeMap(next_pos.x,next_pos.y);
        changeMap(&next_pos,MAN);
        //changeMap(man.x,man.y,FLOOR);
        changeMap(&man,FLOOR);
        man=next_pos;
    }else if(isVaild(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;
        }
    }

    //优化前
    // if(direct==UP){//先处理前进方向是地板的情况
    //     if((man.x-1)>=0 && map[next_pos.x][next_pos.y]==FLOOR){//map[x-1][y]==FLOOR
    //         //changeMap(x-1,y,MAN);//小人前进一格
    //         changeMap(next_pos.x,next_pos.y);
    //         //man.x=x-1;
    //         changeMap(man.x,man.y,FLOOR);
    //         man=next_pos;
    //         //changeMap(x,y,FLOOR);
    //     }
    // }else if(direct==DOWN){
    //     if((man.x+1)<LINE && map[next_pos.x][next_pos.y]==FLOOR){//map[x+1][y]==FLOOR
    //         // changeMap(x+1,y,MAN);
    //         // man.x=x+1;
    //         // changeMap(x,y,FLOOR);
    //         changeMap(next_pos.x,next_pos.y);
    //         changeMap(man.x,man.y,FLOOR);
    //         man=next_pos;
    //     }
    // }else if(direct==LEFT){
    //     if((man.y-1)>=0 && map[next_pos.x][next_pos.y]==FLOOR){//map[x][y-1]==FLOOR
    //         // changeMap(x,y-1,MAN);
    //         // man.y=y-1;
    //         // changeMap(x,y,FLOOR);
    //         changeMap(next_pos.x,next_pos.y);
    //         changeMap(man.x,man.y,FLOOR);
    //         man=next_pos;
    //     }
    // }else if(direct==RIGHT){
    //     if((man.y+1)<COLUMN && map[next_pos.x][next_pos.y]==FLOOR){//map[x][y+1]==FLOOR
    //         // changeMap(x,y+1,MAN);
    //         // man.y=y+1;
    //         // changeMap(x,y,FLOOR);
    //         changeMap(next_pos.x,next_pos.y);
    //         changeMap(man.x,man.y,FLOOR);
    //         man=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);//放置画面背景图片,并设置其位置

    //加载道具图标
    loadimage(&images[WALL], _T("wall.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[MAN], _T("man.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< LINE; i++){
        for(int j = 0; j < COLUMN; j++){
            if(map[i][j]==MAN){//找到小人的位置
                man.x=i;
                man.y=j;
            }
            putimage(START_X+j*RATIO, START_Y+i*RATIO,&images[map[i][j]]);//在对应位置放置道具图标
        }
    }

    //游戏环节
    bool quit=false;

    do{
        if(_kbhit()){//如果键盘被敲击,_kbhit()函数会返回true
            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);//休眠0.1秒

    }while(quit==false)

    system("pause");

    //游戏结束,释放资源
    closegraph();

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值