前面记录了贪吃蛇的代码实现以及一些用到的小知识点,现在记录一下推箱子,大体框架是相同的,知识点可前往此处:
贪吃蛇C++实现
接下来是推箱子的一些运行截图及代码,只是相较于贪吃蛇多设置了几个关卡,加个条件判断语句,多建立两张游戏地图即可实现关卡跳换。
箱子是让它们连着生成的,因为比较方便调试,别为难自己,可以在代码处改成真正的随机,像贪吃蛇的食物一样。
游戏菜单:
第一关:
把箱子推到空格位置,则判断进入下一关
第二关:
第三关:
结束:
菜单里的游戏设置,游戏信息等也做了跳转,比如点击游戏设置,会跳转至:
内容随意,这是个基础游戏框架,就没有加入各种设置,貌似推箱子游戏也没什么设置可以加,贪吃蛇还可以在界面渲染一个控制台,显示分数,关卡等。
关闭运行窗口则使用 exit(0)函数。
感觉到了C++的类的基石作用,生成对象方便,对象,就是类的实例化。
下面是代码:
// PushBoxComeTrue.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<Windows.h>
#include<iostream>
using namespace std;
#define KEY_DOWN(vk_code)GetAsyncKeyState(vk_code)&0x8000?1:0
enum
{
E_MENU_START,
E_MENU_SETTING,
E_MENU_EXIT,
E_MENU_INFORMATION
};
enum
{
E_GAME_MENU,
E_GAME_MAP,
E_GAME_RESULT,
E_GAME_SETTINGINFORMATION,
E_GAME_INFOR
};
int g_arrMap1[15][20]={
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,1,1,1,0,0,0,0,0,0,0,0,1},
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,1,0,0,0,0,0,0,0,1,1,1},
{1,0,0,1,1,1,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,1,1,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,1,1,1,1,1,0,0,0,0,0,0,0,1},
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
};
int g_arrMap2[15][20]={
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,0,0,0,0,0,0,0,0,1,0,1,0,1},
{1,0,0,0,0,0,0,0,0,0,1,1,1,0,1},
{1,0,0,1,0,1,0,0,0,0,1,1,1,0,1},
{1,0,0,1,0,1,0,0,0,0,0,1,0,0,1},
{1,1,1,1,0,1,1,1,0,0,0,0,0,0,1},
{1,1,0,0,0,0,0,1,0,0,0,0,0,0,1},
{1,1,1,0,0,0,1,1,0,0,0,0,0,0,1},
{1,0,1,0,0,0,1,0,0,0,0,0,0,0,1},
{1,0,1,0,0,0,1,0,0,0,0,0,0,0,1},
{1,0,1,0,0,0,1,0,0,0,0,1,1,1,1},
{1,0,1,0,0,0,1,0,0,0,0,0,0,0,1},
{1,0,0,1,1,1,0,0,0,0,0,1,1,1,1},
{1,0,0,0,1,0,0,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
};
int g_arrMap3[15][20]={
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,0,0,1,1,1,0,1,1,1,0,0,0,1},
{1,0,0,1,0,0,0,1,0,0,0,1,0,0,1},
{1,0,1,0,0,0,0,0,0,0,0,0,1,0,1},
{1,0,0,1,0,0,0,0,0,0,0,1,0,0,1},
{1,0,0,0,1,0,0,0,0,0,1,0,0,0,1},
{1,0,0,0,0,1,0,0,0,1,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,1,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,1,0,1,0,0,0,0,0,0,0,0,0,1},
{1,0,0,1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,1,0,0,0,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
};
int g_arrMap[15][20] ={};//地图数组的初始化,为接下来的地图切换做准备
struct SData//结构体声明
{
SData()
{
nRow = 0;
nCol = 0;
nRowBk = 0;
nColBk = 0;
}
SData(int nInRow,int nInCol)
{
nRow = nInRow;
nCol = nInCol;
nRowBk = nInRow;
nColBk = nInCol;
}
void backUp()//备份坐标
{
nRowBk = nRow;
nColBk = nCol;
}
void restore()//储存的坐标释放
{
nRow = nRowBk;
nCol = nColBk;
}
int nRow;
int nCol;
int nRowBk;
int nColBk;
};
int _tmain(int argc, _TCHAR* argv[])
{
int nMenuState=E_MENU_START;//表示菜单状态,0游戏开始,1设置,2结束,3游戏信息
int nGameState=E_GAME_MENU;//表示游戏状态,0菜单,1地图,2游戏结果,3设置信息界面,4游戏信息界面
memcpy(g_arrMap,g_arrMap1,sizeof(g_arrMap) );
SData sPlayer = SData(7,7);//声明一个结构体对象--玩家sPlayer
SData arrBox[3];//声明一个箱子数组
SData arrHole[3];//声明一个坑数组
int nLevel=1;//定义游戏关卡关数
for(int i =0;i < 3;i++)
{
arrBox[i] = SData(9,9+i);
arrHole[i]=SData(11,10+i);
}
while(true)
{
system("cls");
if(E_GAME_MENU==nGameState)//菜单
{
if(KEY_DOWN(VK_RETURN))//菜单数据更新按下enter键进入游戏地图
{/*按下enter键时要判断当前箭头是否指示在游戏开始的位置
判断nMenuState的值是否是0,是则切换,不是则不管*/
if(E_MENU_START==nMenuState)
{nGameState=E_GAME_MAP;}
else if(E_MENU_SETTING==nMenuState)
{nGameState=E_GAME_SETTINGINFORMATION;}
else if(E_MENU_INFORMATION==nMenuState)
{nGameState=E_GAME_INFOR;}
else if(E_MENU_EXIT==nMenuState)
{
exit(0);
}
}
//指令数据更新
if(KEY_DOWN(VK_UP))
{
nMenuState--;
if(nMenuState<E_MENU_START)
{nMenuState=E_MENU_INFORMATION;}//当箭头指到第一行时,跳到第三行
}
else if(KEY_DOWN(VK_DOWN))
{
nMenuState++;
if(nMenuState>E_MENU_INFORMATION)
{nMenuState=E_MENU_START;}
}
//游戏界面渲染
if(E_MENU_START==nMenuState)
{
cout<<"->游戏开始"<<endl;
cout<<" 游戏设置"<<endl;
cout<<" 游戏结束"<<endl;
cout<<" 游戏信息"<<endl;
}
else if(E_MENU_SETTING==nMenuState)
{
cout<<" 游戏开始"<<endl;
cout<<"->游戏设置"<<endl;
cout<<" 游戏结束"<<endl;
cout<<" 游戏信息"<<endl;
}
else if(E_MENU_EXIT==nMenuState)
{
cout<<" 游戏开始"<<endl;
cout<<" 游戏设置"<<endl;
cout<<"->游戏结束"<<endl;
cout<<" 游戏信息"<<endl;
}
else if(E_MENU_INFORMATION==nMenuState)
{
cout<<" 游戏开始"<<endl;
cout<<" 游戏设置"<<endl;
cout<<" 游戏结束"<<endl;
cout<<"->游戏信息"<<endl;
}
//else if(E_MENU_EXIT==nMenuState)
//{
// exit(0);
//}
}
else if(E_GAME_MAP==nGameState)//地图显示
{
if(KEY_DOWN(VK_ESCAPE))
{
nGameState=E_GAME_MENU;
}
//移动之前把玩家的坐标先存储起来,每次移动之前备份玩家坐标
sPlayer.backUp();
//玩家移动的按键控制:只需要按键之后根据相应的方向去更改玩家的坐标即可
if(KEY_DOWN(VK_UP))
{
sPlayer.nRow--;
}
else if(KEY_DOWN(VK_DOWN))
{
sPlayer.nRow++;
}
else if(KEY_DOWN(VK_LEFT))
{
sPlayer.nCol--;
}
else if(KEY_DOWN(VK_RIGHT))
{
sPlayer.nCol++;
}
//玩家移动后进入墙,玩家进入墙的时候,玩家应该静止不动(其实是快速回到上一步位置,视觉暂留而不可见)
//判断玩家撞墙,获取玩家玩家所在位置坐标对应于地图数组里面的值是否为1
if(1 == g_arrMap[sPlayer.nRow][sPlayer.nCol])//条件成立,则玩家即将陷到墙里面,玩家应该回到移动前的位置
{
sPlayer.restore();
}
//备份箱子坐标
for(int i = 0;i < 3;i++)
{
arrBox[i].backUp();
}
for(int i = 0;i < 3;i++)//3个箱子都检测一遍
{
//比较玩家是否碰到第i个箱子,玩家坐标 == 第i个箱子的坐标
if(arrBox[i].nRow == sPlayer.nRow && arrBox[i].nCol == sPlayer.nCol)
{
int nOffsetRow = sPlayer.nRow - sPlayer.nRowBk;
int nOffsetCol = sPlayer.nCol - sPlayer.nColBk;
arrBox[i].nRow += nOffsetRow;
arrBox[i].nCol += nOffsetCol;
break;
}
}
//箱子之间的碰撞
for(int i = 0;i < 3;i++)
{
int nBoxRow = arrBox[i].nRow;
int nBoxCol = arrBox[i].nCol;
//如果成立,那么表示第i个箱子与墙体会重合,箱子“消失”
if(1 == g_arrMap[nBoxRow][nBoxCol])
{
//还原箱子进入墙壁之前一步的坐标
arrBox[i].restore();
//玩家坐标的还原
sPlayer.restore();
break;
}
}
for(int i = 0;i < 3;i++)//被推箱子的自我检测
{
//被推的所有箱子自我挨个检测
for(int j = 0;j < 3;j++)
{
//i!=j,这样将导致玩家无法行动,因为当箱子比较自己时,一直还原
if(arrBox[i].nRow == arrBox[j].nRow &&arrBox[i].nCol == arrBox[j].nCol&&i!=j)
//条件成立表示推着的箱子与其他箱子接触了,无法推动
{
//当条件成立时还原游戏玩家与箱子的坐标
arrBox[i].restore();
sPlayer.restore();
}
}
}
//游戏胜利的判断
int count=0;
for(int i=0;i<3;i++)//判断地图的箱子是否都已经推到坑里?
{
for(int j=0;j<3;j++)
{
if(arrBox[i].nRow == arrHole[j].nRow && arrBox[i].nCol == arrHole[j].nCol)
{
count++;
break;
}
}
}
//游戏关卡的切换
//int nLevel=1;如果在这里定义游戏关卡,那么每次判断完游戏胜利又会刷新为1,则一直重复第二关
int nBoxNumber=sizeof(arrBox)/sizeof(SData);
if(count>=nBoxNumber)
{
nLevel++;
if(nLevel==2)
{
memcpy(g_arrMap,g_arrMap2,sizeof(g_arrMap));//地图切换至第二张
sPlayer=SData(2,2);//重新定义玩家初始位置
for(int i = 0;i < 3;i++)//重新定义箱子的位置
{
arrBox[i] = SData(7+i,9);
}
for(int i = 0;i < 3;i++)//重新定义坑的位置
{
arrHole[i] = SData(11,11+i);
}
}
else if(nLevel==3)
{
memcpy(g_arrMap,g_arrMap3,sizeof(g_arrMap));//地图切换至第三张
sPlayer=SData(6,1);
for(int i = 0;i < 3;i++)
{
arrBox[i] = SData(12,10+i);
}
for(int i = 0;i < 3;i++)
{
arrHole[i] = SData(9,9+i);
}
}
//将游戏状态切换到游戏结果处
else
{
nGameState = E_GAME_RESULT;
}
}
//行列字符的输出,游戏地图的渲染
for(int i=0;i<15;i++)
{
for(int j=0;j<20;j++)
{
bool bDrawBox = false;
for(int m = 0;m < 3;m++)
{
if(i == arrBox[m].nRow && j == arrBox[m].nCol)
{
bDrawBox = true;
break;
}
}
bool bDrawHole = false;
for(int m = 0;m < 3;m++)
{
if(i == arrHole[m].nRow && j == arrHole[m].nCol)
{
bDrawHole = true;
break;
}
}
if(1 == g_arrMap[i][j])
{
cout <<"■";
}
else if(i == sPlayer.nRow&& j==sPlayer.nCol)
{
cout <<"♀";
}
else if(bDrawBox)
{
cout <<"箱";
}
else if(bDrawHole)
{
cout<<"□";
}
else
{cout<<" ";}
}
cout<<endl;//一个for内循环,i*j次,每行输出后换行继续下一行的循环输出
}
}
else if(E_GAME_SETTINGINFORMATION==nGameState)//进入游戏设置界面
{
if(KEY_DOWN(VK_ESCAPE))//按ESC退出返回菜单界面
{
nGameState=E_GAME_MENU;
}
if(E_MENU_SETTING==nMenuState)
{
cout<<"抱歉, 这款游戏目前不配拥有游戏设置,我们老板将会去搬砖赚钱来请程序员开发"<<endl;
cout<<" 请按‘Esc’键返回主菜单";
}
}
else if(E_GAME_INFOR==nGameState)//进入游戏信息界面
{
if(KEY_DOWN(VK_ESCAPE))//按ESC退出返回菜单界面
{
nGameState=E_GAME_MENU;
}
if(E_MENU_INFORMATION==nMenuState)
{
cout<<"666"<<endl;
cout<<"666"<<endl;
cout<<"666"<<endl;
cout<<"谢谢您的使用,祝您生活愉快!";
}
}
//退出地图界面
else if(nGameState == E_GAME_RESULT)//==2
{
if(KEY_DOWN(VK_RETURN))
{
nGameState = E_GAME_MENU;
}
cout <<"恭喜过关!"<< endl;
}
}
return 0;
}