c++之简单的推箱子游戏

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhoutian_19950630/article/details/54575470

c++推箱子小游戏(linux也可以运行)

C++一直都是游戏开发的主流语言,特别是游戏引擎的开发。学了半年C++,网上找了一些C++推箱子的小游戏,涉及到的知识面太广,从容器到BFS等等算法,尤其是推多个箱子的时候。本人水平有限,只做到了固定地图,并且只有一个箱子可以推。能基本的实现后退,重新开始,上下关卡切换的功能。因为大部分游戏都是在Windows C++平台下编写运行的,很少有linux下也可以运行的推箱子游戏。

//Sokoban.h
class Sokoban
{
private:
    enum {L = 21,H = 10};
    int Pex,Pey,OrgPex,OrgPey,OldPex,OldPey;//人的实时位置坐标,上一步人的坐标,人的初始位置坐标
    int Boxx,Boxy,OrgBoxx,OrgBoxy,OldBoxx,OldBoxy;//箱子的实时位置,上一步箱子的初始位置坐标,箱子的初始位置坐标
    int Tx,Ty;  //目标位置的坐标
    int Succeed;    //判断成功的标志位
    int dx[4],dy[4];//方向数组
    int dir;
public:
    Sokoban();//构造函数
    ~Sokoban();//析构函数
    void Initial();//地图初始化函数
    void Show();//地图刷新函数
    void Button();//按键判断函数
    void Move();//箱子移动函数
    bool Check(int x,int y);//验证越界函数
    void Rest();//重新开始
};
//Sokoban.cpp
#include"Sokoban.h"
int level = 1;//游戏关卡
char map[10][22]={"0"};//用来时时更新地图
char oldmap[10][22]={"0"};//前一步的地图
char orgmap[10][22]={"0"};//最初的地图

void OldMap()
{
    int i = 0,j = 0;
    for(i = 0;i<10;i++)
        {
            for(j = 0;j<21;j++)
                {
                        oldmap[i][j] = map[i][j];
                }
        }
}

void OrgMap()
{
        int i = 0,j = 0;
        for(i = 0;i<10;i++)
        {
                for(j = 0;j<21;j++)
                {
                        orgmap[i][j] = map[i][j];
                }
        }
}

void Back()
{
    int i = 0,j = 0;
    for(i = 0;i<10;i++)
        {
            for(j = 0;j<21;j++)
                {
                        map[i][j] = oldmap[i][j];
        }
    }
}

void Sokoban::Rest()
{
    int i = 0,j = 0;
    for(i = 0;i<10;i++)
        {
            for(j = 0;j<21;j++)
                {
                        map[i][j] = orgmap[i][j];
                }
    }
    Pex = OrgPex;//最初的地图恢复
    Pey = OrgPey;
    Boxx = OrgBoxx;
    Boxy = OrgBoxy;             
}

Sokoban::Sokoban()
{
    dir = -1;
    Succeed = 0;
    //0~3分别代表上右下左
    dx[0] = -1;  dx[1] = 0;  dx[2] = 1;  dx[3] = 0;    
    dy[0] = 0;   dy[1] = 1;  dy[2] = 0;  dy[3] = -1;  
}


Sokoban::~Sokoban()
{

}

void Sokoban::Initial()
{
char   a[10][22]={//123456789012345678901
    /*1*/      "#####################",
    /*2*/      "#X #         #   #  #", 
    /*3*/      "## # ######  O      #",
    /*4*/      "## # #       #####  #",
    /*5*/      "## # # ##### ###### #",
    /*6*/      "##   # #         T  #",
    /*7*/      "#### # # ########   #",
    /*8*/      "##   # #      #     #",
    /*9*/      "##       #   #      #", 
    /*10*/     "#####################"
        };
char   b[10][22]={//123456789012345678901
    /*1*/      "#####################",
    /*2*/      "#X #                #", 
    /*3*/      "## # ############## #",
    /*4*/      "#  # #  # #    # #  #",
    /*5*/      "#  #        ##  #  ##",
    /*6*/      "#  #  # #           #",
    /*7*/      "# ## # #  ####### O #",
    /*8*/      "# T   #   #    #    #",
    /*9*/      "##      #    #      #", 
    /*10*/     "#####################"
        };
char   c[10][22]={//123456789012345678901
    /*1*/      "#####################",
    /*2*/      "#  #          #  #  #", 
    /*3*/      "## # # #####        #",
    /*4*/      "#  # #   O   ## # # #",
    /*5*/      "## # #######  ## #  #",
    /*6*/      "#         X         #",
    /*7*/      "#### ## ## ## ##  ###",
    /*8*/      "##     #  #  #  #   #",
    /*9*/      "##T                 #", 
    /*10*/     "#####################"
        };
char   d[10][22]={//123456789012345678901
    /*1*/      "X#   ################",
    /*2*/      " # #             #  #", 
    /*3*/      " #  # # ###### #    #",
    /*4*/      " # # #       ## # # #",
    /*5*/      " # # #######  ## #  #",
    /*6*/      " #                  #",
    /*7*/      " # # ## ##### ##  # #",
    /*8*/      " # # #      #  # O# #",
    /*9*/      " #T#                #", 
    /*10*/     "   ##################"
        };
char   e[10][22]={//123456789012345678901
    /*1*/      "#####################",
    /*2*/      "     #        #  #  #", 
    /*3*/      "        #####       #",
    /*4*/      "   # # #    ##  # # #",
    /*5*/      " # ### ## ##  ## #  #",
    /*6*/      "     #              #",
    /*7*/      " #####  #  ## ##  ###",
    /*8*/      " # #   #  #  #  # O #",
    /*9*/      "T#                  #", 
    /*10*/     "X####################"
        };
/********************地图初始化**************/
    char (*pc)[22] = a;
    switch(level)
    {
        case 0: break;
        case 1: pc = a;break;
        case 2: pc = b;break;
        case 3: pc = c;break;
        case 4: pc = d;break;
        case 5: pc = e;break;

    }
/**********************人,箱子,目标位置的初始化****************/
    int i = 0,j = 0;
        for(;i<10;i++)
                {
                        for(j = 0;j<21;j++)
                        {
                                map[i][j]  = pc[i][j];
                            if(map[i][j] == 'X')
                {
                    OrgPex = Pex = i;
                    OrgPey = Pey = j;
                }
                else if(map[i][j] == 'O')
                {
                    OrgBoxx = Boxx = i;
                    OrgBoxy = Boxy = j;
                }
                else if(map[i][j] == 'T')
                {
                    Tx = i;
                    Ty = j;
                }
            }

                }
    OrgMap();//最初的地图
    Sokoban::Show();
}

void Sokoban::Show()
{
    int i = 0,j = 0;
    int key = 0;
    while(true)
    {
        usleep(500000);//刷新

        Sokoban::Button();
        Sokoban::Move();
        system("clear");
        //打印地图
        for(i = 0;i<10;i++)
                {
                    for(j = 0;j<21;j++)
                        {
                                printf("%c",map[i][j]);
                        }
                        cout<<endl;
                 }
    //画面
        cout<<endl;
        cout << " _________________________________" << endl;  
        cout << "|     C++语言推箱子游戏  (共5关)    |" << endl;  
        cout << "|    游戏规则:     当前关卡: "<<level<<"   |" << endl;  
        cout << "|     X:人        O:箱子          |" << endl;  
        cout << "|    #:障碍物    T:目的地          |" << endl;  
        cout << "|    操作说明:    Q:退出           | " << endl;
        cout << "|     W:上         S:下           |"<<endl;
        cout << "|     D:右         A:左           |"<<endl;
        cout << "|     R:重新开始   B:后退         |"<<endl;
        cout << "|     U:上张地图   N:下张地图      |"<<endl;
        cout << "|————————————————————————————————|" << endl;  
        cout << "|    友请提示:                    |" << endl;  
        cout << "|    每次移动过后只能后退一次!      |" << endl;  
        cout << "|    人将箱子推到目的地即过关!      |" << endl;  
        cout << "|   输入按键后按一次回车才能生效!   |" << endl;  
        cout << "|————————————————————————————————|" << endl;  

        //箱子成功到达目的地
        if(Succeed)
        {   
            if(level == 5)
            {
                cout<<"太厉害了!!!你差点就和游戏开发者一样聪明了"<<endl;   
                break;
            }
            else if(level == 0)
            {
                sleep(1);
                break;
            }
            else
            {
                cout<<"       恭喜你啊,智商可以啊,有本是来通关阿!"<<endl;
                cout<<"输入Q回车退出游戏,输入任意键回车等待2秒即可开启下一关卡"<<endl;
                sleep(1);
                if(kbhit() != 0)
                {
                    while(kbhit() != 0)
                    key = getchar();
                    if(key == 113)//按q
                    break;
                    else
                    {
                        usleep(500000);
                        Succeed = 0; 
                        level++;//等级+1,地图就会更新
                        Sokoban::Initial();
                    }
                }
            }
        }
    }
}

void Sokoban::Button()
{
     int key = 0; 
     if(kbhit() != 0) //检查当前是否有键盘输入,若有则返回一个非0值,否则返回0  
     {   
        while(kbhit() != 0)  //可能存在多个按键,要全部取完,以最后一个为主  
            key = getchar(); //将按键从控制台中取出并保存到key中  
        switch(key)  
        {    
            //上  
            case 119:  dir = 0;  
                    break;  
            //右  
            case 100:  dir = 1;       
                    break;  
                    //下  
            case 115:  dir = 2;   
                    break;  
            //左  
            case 97:  dir = 3;   
                    break; 
            //后退 
            case 98: {
                    Back();
                    Pex = OldPex;
                    Pey = OldPey;
                    Boxx = OldBoxx;
                    Boxy = OldBoxy;

                break;
                }
            //重新开始
            case 114: {
                    Rest();
                break;
                }
            //切换到下张图
            case 110:{
                    level++; 
                    if(level == 6)
                    level = 1;
                    Sokoban::Initial();
                break;
                }
            //切换到上张图
            case 117:{
                    level--; 
                    if(level == 0)
                    level = 5;
                    Sokoban::Initial();
                break;
                }
            //退出
            case 113:
                {
                    level = 0;
                    Succeed = 1;
                    break;              
                }
        }  
    }   
}
//人推箱子移动函数
void Sokoban::Move()
{
    int x,y;
    //有按键的时候
    if(dir != -1)
    {
        OldPex = Pex;
        OldPey = Pey;
        OldBoxx = Boxx;
        OldBoxy = Boxy;
        //人所推向的坐标位置 
        x = Pex + dx[dir]; 
        y = Pey + dy[dir];
        //1.人所推位置为空,就走向该位置,并且人初始位置不在目标位置上
        if(Check(x,y) && map[x][y] == ' ' && (Pex != Tx || Pey != Ty))
        {   
            OldMap();
            map[Pex][Pey] = ' ';
            map[x][y] = 'X';
            Pex = x;
            Pey = y;

            dir = -1;
        }
        else    //2.人所推的位置是箱子,就将箱子移向人走的方向这点,并且初始位置不在目标位置上
        if(Check(x,y) && map[x][y] == 'O' && Check( x+dx[dir],y+dy[dir] ) && map[ x+dx[dir] ][ y+dy[dir] ] == ' ' && (Pex != Tx || Pey != Ty))
        {
            OldMap();
            map[Pex][Pey] = ' ';    //人的位置改变
            Pex = x;
            Pey = y;
            map[Boxx][Boxy] = 'X';  //箱子位置改变,且人移动到箱子的位置
            map[x+dx[dir]][y+dy[dir]] = 'O';//箱子移动的位置
            Boxx = x + dx[dir];     
            Boxy = y + dy[dir];

            dir = -1;
        }
        else    //3.人将箱子推向的方向刚好是目的地
        if(Check(x,y) && map[x][y] == 'O' && Check( x+dx[dir],y+dy[dir] ) && map[ x+dx[dir] ][ y+dy[dir] ] == 'T') 
        {   
            OldMap();
            map[Pex][Pey] = ' ';    //人的移动前位置改变
                        Pex = x;
                        Pey = y;
                        map[Boxx][Boxy] = 'X';  //箱子位置改变,且人移动到箱子的位置
                        map[x+dx[dir]][y+dy[dir]] = 'O';//箱子移动的位置
                        Boxx = x + dx[dir];
                        Boxy = y + dy[dir];
            dir = -1;

            Succeed = 1;
        }else   //4.人走到目标位置
        if(Check(x,y) && map[x][y] == 'T') 
        {
            OldMap();
            map[Pex][Pey] = ' ';
            map[x][y] = 'X';
            Pex = x;
            Pey = y;
            dir = -1;
        }else   //5.人离开目标位置且推不到箱子
        if(Pex == Tx && Pey == Ty && Check(x,y) && map[x][y] == ' ')
        {
            OldMap();
            map[Tx][Ty] = 'T';//人的位置变成目标地址 
            map[x][y] = 'X';    //人移动后的位置
            Pex = x;
            Pey = y;
            dir = -1;
        }
        else   //6.人离开目标位置且能推到箱子
        if(Pex == Tx && Pey == Ty && Check(x,y) && map[x][y] == 'O' && Check( x+dx[dir],y+dy[dir] ) && map[ x+dx[dir] ][ y+dy[dir] ] == ' ')
        {
            OldMap();
            map[Pex][Pey] = 'T';//人的位置变成目标地址
            map[x][y] = 'X';    //人的移动后的位置
            Pex = x;
            Pey = y;
                        map[Boxx][Boxy] = 'X';  //箱子位置改变,且人移动到箱子的位置
                        map[x+dx[dir]][y+dy[dir]] = 'O';//箱子移动的位置
                        Boxx = x + dx[dir];
                        Boxy = y + dy[dir];
            dir = -1;
        }
    }
}
//判断越界情况
bool Sokoban::Check(int x,int y)
{
    if(x < 0 || x >= H || y < 0 || y >= L)
    return 0;
    else
    return 1;
}
//-----------------------------------------------------
//kbhit.h//按键的程序
#ifndef KEY_H
#define KEY_H
#include <termios.h>
#include <iostream>
#include"kbhit.h"
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>

int  kbhit(void);

#endif

//---------------------------------------------
//kbhit.cpp
#include"kbhit.h"

int kbhit (void)
{
  struct timeval tv;
  fd_set rdfs;

  tv.tv_sec = 0;
  tv.tv_usec = 0;

  FD_ZERO(&rdfs);
  FD_SET (STDIN_FILENO, &rdfs);

  select(STDIN_FILENO+1, &rdfs, NULL, NULL, &tv);
  return FD_ISSET(STDIN_FILENO, &rdfs);
}
//---------------------------------------------
//main.cpp
#include"Sokoban.h"
using namespace std;

int main()
{
    Sokoban s;
    s.Initial();
    return 0;
}

//运行方式

g++ -o main Sokoban.cpp hbit.cpp main.cpp

./main

游戏开始的界面
游戏开始的界面

游戏结束的界面
游戏结束画面

阅读更多

没有更多推荐了,返回首页