一个适合初学者的C++推箱子小游戏

一个适合初学者的C++推箱子小游戏

博主最近在学习关于C++的一些基础,这是本人突发奇想做的一个小游戏,编程其实并不难,重要的是,你的思路,以及优化,当然,这个小游戏,本人也是基于一个学习者编写的

本篇文章会教大家用C++基本语句来实现一个推箱子的小游戏。

展示

这是游戏开始时的界面。

一个适合初学者的C++推箱子小游戏_第1张图片
当然,如果你喜欢,你可以任意更改地图:
一个适合初学者的C++推箱子小游戏_第2张图片
当把所有箱子推到目的地,就完成游戏
一个适合初学者的C++推箱子小游戏_第3张图片

思路:

当有一个问题出现的时候,我们首先应该先考虑这个问题有可能的解法:
这里博主想到的方法是

1. 通过二维数组来存储地图信息
2. 通过交换数组元素,来达到角色移动的目的
3. 而推箱子,则让箱子和角色同步移动便可。
4. 移动控制:_getch()

ps:_getch()方法需要头文件conio.h的支持,功能是不需要按回车键便可以得到输入的字符

那么这里我们有了大概的思路,但是再实际操作中,我们发现二维数组并不方便,因为它有两个下标,会加剧问题的复杂度,这里我们用一维数组便可。
移动:我们知道地图是一个方形:要么是m*n,要么就是m^2(正方形);
一个适合初学者的C++推箱子小游戏_第4张图片

这里我们简单绘制一个长4,宽4的长方体来说明:
一个适合初学者的C++推箱子小游戏_第5张图片
如果我在5的位置,那么我要左移,应该是当前位置 -1,同样,向右便是 +1,向上 -4,向下 +4。

地图:

有了这些知识,我们便可以开始编程了,首先写出地图:

int map[100] =                   //玩家地图
 {
  1,1,1,1,1,1,1,1,1,1,
  1,0,0,0,0,0,0,0,0,1,
  1,0,0,0,3,0,4,0,0,1,
  1,2,0,0,0,0,0,0,0,1,
  1,0,0,0,0,0,0,0,0,1,
  1,0,0,3,0,4,0,0,0,1,
  1,0,0,0,0,0,0,0,0,1,
  1,0,0,0,3,0,0,0,0,1,
  1,0,0,0,0,0,0,4,0,1,
  1,1,1,1,1,1,1,1,1,1
 };

上面地图中:0代表空地,1代表墙壁,2代表玩家,3代表箱子,4代表箱子目的地,5代表当人和箱子目的地重合的时候显示的图标,6代表箱子放在正确位置时候的图标

for (int i = 0; i < 100; i++)
  {
   switch (map[i])
   {
   case 1:std::cout << "□"; break;     //墙壁
   case 0:std::cout << "  "; break;     //空地
   case 2:std::cout << "Pe"; break;     //人
   case 3:std::cout << "■"; break;    //箱子
   case 4:std::cout << "**"; break;    //箱子目的地
   case 5:std::cout << "×"; break;    //和人重合
   case 6:std::cout << "√"; break;    //和箱子重合
   }
   if (i % w == 9)
    std::cout << '\n';
  }

我们打印一下:一个适合初学者的C++推箱子小游戏_第6张图片
我们发现和我们一维数组里的数字所代表的意义是一样的!

移动:

移动需要记录当前位置和移动的目标位置,比如你向上,那么
当前坐标=(当前坐标-地图宽度)

我们声明如下变量:

    int input;						//输入常数
	int nowpoint=31;				//玩家现在的地点
	int shift;                       //玩家目标点
	const int w=10;                  //地图宽度

移动方法如下:

                    shift = map[nowpoint-w];         //把目标点赋值给shift
				    map[nowpoint - w] = map[nowpoint];     
					map[nowpoint] = shift;                   //移动目标点
					nowpoint -= w;                              //移动当前所处的坐标位置

当然,我们要保证它不会“穿墙”:于是:

			shift = map[nowpoint-w];
			if (shift == 0)              //目标点必须是空地才能移动!
			{
					map[nowpoint - w] = map[nowpoint];
					map[nowpoint] = shift;
					nowpoint -= w;
			}

但是我们的推箱子人物都是可以穿过箱子的目标地点,也就是:
一个适合初学者的C++推箱子小游戏_第7张图片

一个适合初学者的C++推箱子小游戏_第8张图片
于是有如下代码:

shift = map[nowpoint-w];         //下一个移动的目标点设置给shift
			if (shift ==0)                    //当下一个目标是空地的时候
			{
				if (map[nowpoint] == 5)       //当和箱子目标点重合的时候且需要移动到空地
				{
					map[nowpoint] = 2;               //当前坐标设置为玩家
					map[nowpoint - w] = map[nowpoint];    //下一个坐标为玩家
					map[nowpoint] = 4;              //当前坐标为箱子目标点
					nowpoint -= w;                  //移动当前坐标
				}
				else                        //如果没有和箱子目标点重合,则正常移动
				{
					map[nowpoint - w] = map[nowpoint];     
					map[nowpoint] = shift;
					nowpoint -= w;
				}
			}
			if (shift == 4)                  //当下一个个目标点为箱子目标点时
			{
				map[nowpoint - w] = 5;            //目标点变为人和箱子重合的图案
				map[nowpoint] = 0;                //当前点变为空地
				nowpoint -= w;                    //移动人物的坐标
			}

那么有了这么一个开头,剩下的三个方向也就以此类推了。

接下来是推箱子部分:

这里我们需要注意的是,推箱子的时候,我们不仅仅要考虑玩家(2)的下一个坐标的情况,还要考虑箱子的移动坐标是否超出了我们的地图,那么通过本人总结,那么箱子前进的时候,玩家和箱子会遇到如下的情况:

  1. 前方是墙壁
  2. 前方是箱子
  3. 前方是箱子目的地
  4. 前方是放好的箱子
  5. 前方是空地

玩家有两种情况:

  1. 玩家处于箱子目的地的时候推箱子
  2. 玩家处于箱子目的地,但是推动的方向是墙壁

于是,我们有如下代码:

           if (shift == 3)                    //目标点为箱子
			{
				if (map[nowpoint- 2 * w]!=1&& map[nowpoint - 2 * w] != 3 && map[nowpoint - 2 * w] != 6)         //箱子的下一个目标点不能是墙壁,或者箱子
				{
					if (map[nowpoint - 2 * w] == 4)                     //箱子的下一个目标点是箱子目的地
					{
						map[nowpoint - 2*w] = 6;                       //箱子的下一个目标点变为和箱子重合
						map[nowpoint - w] = map[nowpoint];             //箱子的位置变为玩家位置
						map[nowpoint] = 0;                             //玩家为之变为空地
						nowpoint -=	w;                                 //移动玩家坐标
					}
					else if (map[nowpoint] == 5)                       //目标点为箱子,并且玩家处在箱子目标点里面
					{
						map[nowpoint -w] = map[nowpoint - 2*w];         //箱子向上
						map[nowpoint - 2*w] = shift;                  // 箱子目标点变为人物目标点
						map[nowpoint - w ]= 2;                        //箱子位置变为玩家
						map[nowpoint] = 4;							//玩家上一个点变为箱子目的地
						nowpoint -= w;
					}
					else                                          //其他情况自由移动
					{
						map[nowpoint - 2*w] = shift;             //箱子的目标点变为箱子
						map[nowpoint - w] = map[nowpoint];       //玩家目标点变为玩家
						map[nowpoint] = 0;						//玩家下面的点变为空地
						nowpoint -= w;							//移动玩家点
					}
				}
			}

我们不仅仅要把它推到目标点,还要能够推出来,所以:
一个适合初学者的C++推箱子小游戏_第9张图片
一个适合初学者的C++推箱子小游戏_第10张图片

一个适合初学者的C++推箱子小游戏_第11张图片


        if (shift == 6&& map[nowpoint - 2 * w] != 1)                  //如果下一个点为重合点,且前方不是墙壁
			{
				map[nowpoint - 2*w] = 3;                     //目标点的下一个点变为箱子
				map[nowpoint - w] = 5;                       //下一个点变为和人重合
				map[nowpoint] = 0;                           //人物当前点变为空地
				nowpoint -= w;                                //变换当前坐标
			}

我们解决了一个方向的移动问题,那么接下来的移动,和前面类似,只需要改变移动变量就可以了。

向下:当前坐标=(当前坐标+地图宽度)
向左:当前坐标=(当前坐标-1)
向右:当前坐标=(当前坐标+1)

当你需要修改地图的时候,只需要修改数组里面的的1就可以了,如果觉得图案自己不喜欢,那么在switch里面就可以更换。

游戏结束判断:

我们做了移动和推箱子,但是并没有游戏成功的判定:我们加上如下判断成功的语句:

bool Isgameover(int *map,int Rbox)     //Rbox  为了方便拓展,此参数为目的地个数
{
	int n=0;
	for (int i = 0; i < 100; i++)
	{
		if (*(map+i)==6)
		{
			n++;
		}
	}
	if (Rbox == n)
	{
		std::cout << "恭喜通关!!!\n";
		return true;
	}
	else
	{
		return false;
	}
}

再于循环体里加入如下代码:

if (Isgameover(map, 3))
		{
			break;
		}

完整源码,基于Vs2017:

#include 
#include
bool Isgameover(int *map,int Rbox)     //Rbox  为了方便拓展,此参数为目的地个数
{
	int n=0;
	for (int i = 0; i < 100; i++)
	{
		if (*(map+i)==6)
		{
			n++;
		}
	}
	if (Rbox == n)
	{
		std::cout << "恭喜通关!!!\n";
		return true;
	}
	else
	{
		return false;
	}
}

int main()
{
	int input;						//输入常数
	int nowpoint=31;				//玩家现在的地点
	int shift;                       //玩家目标点
	const int w=10;                  //地图宽度
	int map[100] =                   //玩家地图
	{
		1,1,1,1,1,1,1,1,1,1,
		1,0,0,0,0,0,0,0,0,1,
		1,0,0,0,3,0,4,0,0,1,
		1,2,0,0,0,0,0,0,0,1,
		1,0,0,0,0,0,0,0,0,1,
		1,0,0,3,0,4,0,0,0,1,
		1,0,0,0,0,0,0,0,0,1,
		1,0,0,0,3,0,0,0,0,1,
		1,0,0,0,0,0,0,4,0,1,
		1,1,1,1,1,1,1,1,1,1
	};
	while (true)
	{
		system("cls");
		for (int i = 0; i < 100; i++)
		{
			switch (map[i])
			{
			case 1:std::cout << "□"; break;     //墙壁
			case 0:std::cout << "  "; break;     //空地
			case 2:std::cout << "Pe"; break;     //人
			case 3:std::cout << "■"; break;    //箱子
			case 4:std::cout << "**"; break;    //箱子目的地
			case 5:std::cout << "×"; break;    //和人重合
			case 6:std::cout << "√"; break;    //和箱子重合
			}
			if (i % w == 9)
				std::cout << '\n';
		}
		if (Isgameover(map, 3))
		{
			break;
		}
		input=_getch();


		//往上
		if (input=='w'||input=='W')
		{
			shift = map[nowpoint-w];         //下一个移动的目标点设置给shift
			if (shift ==0)                    //当下一个目标是空地的时候
			{
				if (map[nowpoint] == 5)       //当和箱子目标点重合的时候且需要移动到空地
				{
					map[nowpoint] = 2;               //当前坐标设置为玩家
					map[nowpoint - w] = map[nowpoint];    //下一个坐标为玩家
					map[nowpoint] = 4;              //当前坐标为箱子目标点
					nowpoint -= w;                  //移动当前坐标
				}
				else                        //如果没有和箱子目标点重合,则正常移动
				{
					map[nowpoint - w] = map[nowpoint];     
					map[nowpoint] = shift;
					nowpoint -= w;
				}
			}
			else if (shift == 4)                  //当下一个个目标点为箱子目标点时
			{
				map[nowpoint - w] = 5;            //目标点变为人和箱子重合的图案
				map[nowpoint] = 0;                //当前点变为空地
				nowpoint -= w;                    //移动人物的坐标
			}
			else if (shift == 6&& map[nowpoint - 2 * w] != 1)                  //如果下一个点为箱子和箱子的目标点重合
			{
				map[nowpoint - 2*w] = 3;                     //目标点的下一个点变为箱子
				map[nowpoint - w] = 5;                       //下一个点变为和人重合
				map[nowpoint] = 0;                           //人物当前点变为空地
				nowpoint -= w;
			}
			else if (shift == 3)                    //目标点为箱子
			{
				if (map[nowpoint- 2 * w]!=1&& map[nowpoint - 2 * w] != 3 && map[nowpoint - 2 * w] != 6)         //箱子的下一个目标点不能是墙壁,或者箱子
				{
					if (map[nowpoint - 2 * w] == 4)                     //箱子的下一个目标点是箱子目的地
					{
						map[nowpoint - 2*w] = 6;                       //箱子的下一个目标点变为和箱子重合
						map[nowpoint - w] = map[nowpoint];             //箱子的位置变为玩家位置
						map[nowpoint] = 0;                             //玩家为之变为空地
						nowpoint -=	w;                                 //移动玩家坐标
					}
					else if (map[nowpoint] == 5)                       //目标点为箱子,并且玩家处在箱子目标点里面
					{
						map[nowpoint -w] = map[nowpoint - 2*w];         //箱子向上
						map[nowpoint - 2*w] = shift;                  // 箱子目标点变为人物目标点
						map[nowpoint - w ]= 2;                        //箱子位置变为玩家
						map[nowpoint] = 4;							//玩家上一个点变为箱子目的地
						nowpoint -= w;
					}
					else                                          //其他情况自由移动
					{
						map[nowpoint - 2*w] = shift;             //箱子的目标点变为箱子
						map[nowpoint - w] = map[nowpoint];       //玩家目标点变为玩家
						map[nowpoint] = 0;						//玩家下面的点变为空地
						nowpoint -= w;							//移动玩家点
					}
				}
			}
			
			
		}
		//往下
		else if (input == 's' || input == 'S')
		{
			shift = map[nowpoint+w];
			if (shift == 0)
			{
				if (map[nowpoint]==5)
				{
					map[nowpoint] = 2;
					map[nowpoint + w] = map[nowpoint];
					map[nowpoint] = 4;
					nowpoint += w;
				}
				else
				{
					map[nowpoint + w] = map[nowpoint];
					map[nowpoint] = shift;
					nowpoint += w;
				}
				
			}
			else if (shift==4)
			{
				map[nowpoint + w] = 5;
				map[nowpoint] = 0;
				nowpoint += w;
			}
			else if (shift == 6 && map[nowpoint + 2 * w] != 1)
			{
				map[nowpoint + 2*w] = 3;
				map[nowpoint + w] = 5;
				map[nowpoint] = 0;
				nowpoint += w;
			}
			else if (shift == 3)
			{
				if (map[nowpoint+2*w]!=1 && map[nowpoint + 2 * w] != 3 && map[nowpoint + 2 * w] != 6)
				{
					if (map[nowpoint + 2 * w] == 4)
					{
						map[nowpoint + 2 * w] = 6;
						map[nowpoint + w] = map[nowpoint];
						map[nowpoint] = 0;
						nowpoint += w;
					}
					else if (map[nowpoint] == 5)
					{
						map[nowpoint + w] = map[nowpoint + 2 * w];
						map[nowpoint + 2 * w] = shift;
						map[nowpoint + w] = 2;
						map[nowpoint] = 4;
						nowpoint += w;
					}
					else
					{
						map[nowpoint + 2 * w] = shift;
						map[nowpoint + w] = map[nowpoint];
						map[nowpoint] = 0;
						nowpoint += w;
					}
				}
				
			}
		}


		//往左
		else if (input == 'a' || input == 'A')
		{
			shift = map[nowpoint-1];
			if (shift == 0)
			{
				if (map[nowpoint] == 5)
				{
					map[nowpoint] = 2;
					map[nowpoint - 1] = map[nowpoint];
					map[nowpoint] = 4;
					nowpoint -= 1;
				}
				else
				{
					map[nowpoint - 1] = map[nowpoint];
					map[nowpoint] = shift;
					nowpoint -= 1;
				}
			}
			else if (shift == 4)
			{
				map[nowpoint -1] = 5;
				map[nowpoint] = 0;
				nowpoint -= 1;
			}
			else if (shift == 6 && map[nowpoint - 2] != 1)
			{
				map[nowpoint - 2] = 3;
				map[nowpoint - 1] = 5;
				map[nowpoint] = 0;
				nowpoint -= 1;
			}
			else if (shift == 3)
			{
				if (map[nowpoint - 2]!=1 && map[nowpoint - 2] != 3 && map[nowpoint - 2] != 6)
				{
					if (map[nowpoint - 2]==4)
					{
						map[nowpoint - 1] = map[nowpoint - 2];
						map[nowpoint - 2] = 6;
						map[nowpoint - 1] = map[nowpoint];
						map[nowpoint] = 0;
						nowpoint -= 1;
					}
					else if (map[nowpoint] == 5)
					{
						map[nowpoint - 1] = map[nowpoint - 2];
						map[nowpoint - 2] = shift;
						map[nowpoint - 1] = 2;
						map[nowpoint] = 4;
						nowpoint -= 1;
					}
					else
					{
						map[nowpoint - 2] = shift;
						map[nowpoint - 1] = map[nowpoint];
						map[nowpoint] = 0;
						nowpoint -= 1;
					}
					
				}
				
			}
			
		}

		//往右
		else if (input == 'd' || input == 'D')
		{
			shift = map[nowpoint+1];
			if (shift == 0)
			{
				if (map[nowpoint] == 5)
				{

					map[nowpoint] = 2;
					map[nowpoint + 1] = map[nowpoint];
					map[nowpoint] = 4;
					nowpoint += 1;
				}
				else
				{
					map[nowpoint + 1] = map[nowpoint];
					map[nowpoint] = shift;
					nowpoint += 1;
				}
			}
			else if (shift == 4)
			{
				map[nowpoint + 1] = 5;
				map[nowpoint] = 0;
				nowpoint += 1;
			}
			else if (shift == 6 && map[nowpoint +2] != 1)
			{
				map[nowpoint + 2] = 3;
				map[nowpoint + 1] = 5;
				map[nowpoint] = 0;
				nowpoint += 1;
			}
			else if (shift == 3)
			{
				if (map[nowpoint + 2]!=1 && map[nowpoint + 2] != 3 && map[nowpoint + 2 ] != 6)
				{
					if (map[nowpoint + 2] == 4)
					{
						map[nowpoint + 1] = map[nowpoint + 2];
						map[nowpoint + 2] = 6;
						map[nowpoint + 1] = map[nowpoint];
						map[nowpoint] = 0;
						nowpoint += 1;
						std::cout << "!!!";
					}
					else if (map[nowpoint] == 5)
					{
						map[nowpoint + 1] = map[nowpoint + 2];
						map[nowpoint + 2] = shift;
						map[nowpoint + 1] = 2;
						map[nowpoint] = 4;
						nowpoint += 1;
						std::cout << "!!";
					}
					else
					{
						map[nowpoint + 2] = shift;
						map[nowpoint + 1] = map[nowpoint];
						map[nowpoint] = 0;
						nowpoint += 1;
						std::cout << "!";
					}
				}
			}
		}
	}
	system("pause");
	return 0;
	
}

这里由于博主的编程水平处于学习阶段,此代码并不够高效,如果对代码有任何建议,都可以给博主发邮件,我很欢迎大家来讨论。

你可能感兴趣的:(学习)