推箱子C++实现 实训认识小游戏

前面记录了贪吃蛇的代码实现以及一些用到的小知识点,现在记录一下推箱子,大体框架是相同的,知识点可前往此处:
贪吃蛇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;
}
	
		
		







发布了7 篇原创文章 · 获赞 12 · 访问量 1931

猜你喜欢

转载自blog.csdn.net/qq_44114055/article/details/103947067