在LINUX环境终端下用C语言实现推箱子小游戏

首先要玩这个游戏得先获取键盘的键值,从而判定方向

获取方向键的功能:使用头文件 getch.h 中的gech函数
代码如下:

#ifndef GETCH_H
#define GETCH_H

#include <termios.h>
#include <unistd.h>

// 修改终端的控制方式,1取消回显、确认 2获取数据 3还原
static int getch(void)
{
    // 记录终端的配置信息
    struct termios old;
    // 获取终端的配置信息
    tcgetattr(STDIN_FILENO,&old);
    // 设置新的终端配置   
    struct termios new = old;
    // 取消确认、回显
    new.c_lflag &= ~(ICANON|ECHO);
    // 设置终端配置信息
    tcsetattr(STDIN_FILENO,TCSANOW,&new);

    // 在新模式下获取数据   
    int key_val = 0; 
    do{
    	key_val += getchar();
    }while(stdin->_IO_read_end - stdin->_IO_read_ptr);

    // 还原配置信息
    tcsetattr(STDIN_FILENO,TCSANOW,&old); 
    return key_val; 
}

#endif//GETCH_H

建立好头文件后由电脑到虚拟的LINUX环境步骤如下:

1、在windows中把getch.h头文件放入共享文件夹

2、终端进入贡献文件夹:
    cd /media/sf_Share
    
3、复制头文件到共享库
    sudo cp getch.h /usr/include/
    
4、加读取权限:
    sudo chmod +r /usr/include/gerch.h 

分别测试一下上下左右的键值

 #include <stdio.h>
 #include<getch.h>
 int main(int argc,const char*argv[])
 {
    for(int i=0;i<4;i++)
         printf("%d ",getch());
  }

在LINUX环境终端下用C语言实现推箱子小游戏

得到的方向以及键值如下:

上:183  下:184   右:185   左:186

再大致分析一下代码的整体轮廓
1.确定各种对应关系,墙体、路等用什么表示
2.画好地图
3.移动规则
4.判定规则

准备好这些就可以写代码啦

1.首先分析一下情况
推箱子游戏由路、墙、人、箱子以及目标组成
所以可以考虑用不同的数字代表这些情景,结合二维数组构成基本的地图
我这里的设定如下:分别用数字0、1、 2、 3、 4代表路、墙、人、箱子以及目标
2.地图定义如下:

	int arry[8][8]={
		{1,1,1,1,1,1,1,1},
		{1,1,1,4,4,1,1,1},
		{1,1,1,0,4,1,1,1},
		{1,1,0,0,3,4,1,1},
		{1,1,0,3,0,0,1,1},
		{1,0,0,1,3,3,0,1},
		{1,2,0,0,0,0,0,1},
		{1,1,1,1,1,1,1,1}
		};//0路1墙2人3箱子4目标

打印效果如下

		for(i=0;i<8;i++)
		{
			for(j=0;j<8;j++)
			{
				switch(arry[i][j])
				{
					case 1:
						printf(" * ");break;
					case 0:
						printf("   ");break;
					case 2:
						printf(" @ ");break;
					case 3:
						printf(" # ");break;
					case 4:
						printf(" o ");break;
				}
			}
			printf("\n");
		}

在LINUX环境终端下用C语言实现推箱子小游戏

可以看到已经有了基本轮廓

3.然后我们分析一下移动规则:
(1)移动方向前方是路则可以向前
移动方向前方是目标可以向前
以前前方如果是箱子,而箱子前方是目标或者路可以向前推动

4.胜利规则的判定,由于目标点是自己定的,知道坐标的情况下可以直接判断目标点上的值,
例如这里是(1,3)(1,4)(2,4)(3,5)
如果这些坐标上的值都等于3,说明箱子都归位了

在二维数组的基础上和好理解,定义indix1、indix2分别是人的行和列下标
则人的:

上方向  arry [indix1-1] [indix2]
下方向  arry [indix1+1] [indix2]
左方向  arry [indix1] [indix2-1]
右方向  arry [indix1] [indix2+1]

向上移动的代码例子如下:


switch(getch())//获取键值
{
	case 183:   //移动方向向上
		if(arry[indix1-1][indix2]==0||arry[indix1-1][indix2]==4)//行坐标-1,判断上方是路或者目标则可以向上移动,
		{	
		    arry[indix1-1][indix2]=2;      //把地图上人的位置重新赋值、更新			
			if((indix1==1&&(indix2==3||indix2==4))||(indix1==2&&indix2==4)||(indix1==3&&indix2==5))
				arry[indix1][indix2]=4;          //走出的位置是目标点,标记回目标    
			else
				arry[indix1][indix2]=0;        //否则变回路
			indix1=indix1-1;        //把人的下标更新,方便下次判断
			cnt++;         //记录步数
		}
		else if(arry[indix1-1][indix2]==3)       //如果上方是箱子的话
		{
			if(arry[indix1-2][indix2]==0||arry[indix1-2][indix2]==4)   //箱子前面如果是路或者目标则可以推
			{
				arry[indix1-2][indix2]=3;      //箱子的位置更新
				arry[indix1-1][indix2]=2;      //人的位置更新
				if((indix1==1&&(indix2==3||indix2==4))||(indix1==2&&indix2==4)||(indix1==3&&indix2==5))
					arry[indix1][indix2]=4;     //走出的位置是目标点,标记回目标    
				else
					arry[indix1][indix2]=0;     //否则变回路
				indix1=indix1-1;          //把人的下标更新,方便下次判断
				cnt++;
			}
		}
		break;

后面几个方向的原理类似,只要把代码复制下去改一下方向即可,篇幅原因,这里不贴出来


几个方向间的代码有很多的雷同之处,可以考虑总结一下优化代码

在前面提到过,这是方向的表示:
上方向  arry [indix1-1] [indix2]
下方向  arry [indix1+1] [indix2]
左方向  arry [indix1] [indix2-1]
右方向  arry [indix1] [indix2+1]

  对于上下方向、左右方向,可以分别用一个变量表示,获取相应键值后对不同变
量进行赋值这里用up表示上下、on表示左右
方向  arry [indix1+up] [indix2+on]对于(up,on)=(-1,0)/(1,0)/(0,-1)/(0,1)就能表示各个方向了

  对于移动、推箱子后的更新,可以考虑另一种赋值关系,这样对于出入目标值、成功的判断就不用坐标判断法
定义如下:
1、人移动到新的位置或者目标,则该处坐标+=2,即加上人对应的数值,离开则-=2
   这样子若移动的方向是路0+2=2,若是目标4+2=6,所以6打印的也是人
   离开原位2-2=0,还原路;6-2=4还原目标
2、推箱子也是一样,如果能推,箱子要移动到的坐标的值+=3,人移动到箱子的位置-=1;离开原位-=2
   这样子若移动的方向是路0+4=2,移动到箱子的位置3-1=2(打印的还是人),离开原位2-2=0,还原路;、
	
	若是目标4+3=7,所以7打印的也是箱子,并且是到了目标的箱子!!

原理基本就这样

优化后的代码


		cnt=0;    //记录箱子进入目标的个数,全部进入判定成功
		up=0;	   //清除上一次的方向
		on=0;	   //清除上一次的方向
		
		switch(getch())    //获取键值并决定移动方向
		{
			case 183:
				up--;
				break;
			case 184:
				up++;
				break;
			case 185:
				on++;
				break;
			case 186:
				on--;
				break;
		}
		if(0==arry[indix1+up][indix2+on]||4==arry[indix1+up][indix2+on])	//是路或者目标
		{
			arry[indix1+up][indix2+on] +=2;    //新位置
			arry[indix1][indix2]  -=2;		  //旧位置
			indix1 +=up;      //更新人的坐标
			indix2 +=on;
			step++;				//记录步数
		}
		else if(3==arry[indix1+up][indix2+on]||7==arry[indix1+up][indix2+on])	//是箱子
		{
			if(arry[indix1+up*2][indix2+on*2]==0||arry[indix1+up*2][indix2+on*2]==4) 
			//箱子要移动的方向是路或者目标
			{
				arry[indix1+up*2][indix2+on*2] +=3;		//箱子的新位置
				arry[indix1+up][indix2+on]  -=1;    	//人去到箱子原位置
				arry[indix1][indix2] -=2;				//人原来的位置
				indix1 +=up;							//更新人的下标
				indix2 +=on;
				step++;        //记录步数
			}
		}

总的代码如下:

#include <stdio.h>
#include<getch.h>
#include<stdlib.h>
int main(int argc,const char*argv[])
{
	
	int arry[8][8]={
		{0,0,0,1,1,1,0,0},
		{0,0,1,4,4,1,0,0},
		{0,0,1,0,4,1,1,0},
		{1,1,0,0,3,4,1,0},
		{1,1,0,3,0,0,1,1},
		{1,0,0,0,3,3,0,1},
		{1,2,0,0,0,0,0,1},
		{1,1,1,1,1,1,1,1}
		};//1墙2人3箱子4目标
		  //3+4=7箱子
		  //2+4=6人
	
	int up,on,i,j,cnt=0,step=0,indix1=6,indix2=1;

	while(1)
	{
		system("clear");         //清屏
		cnt=0;
		up=0;
		on=0;

		for(i=0;i<8;i++)
		{
			for(j=0;j<8;j++)
			{
				switch(arry[i][j])
				{
					case 1:
						printf(" * ");break;
					case 0:
						printf("   ");break;
					case 2:
						printf(" @ ");break;
					case 3:
						printf(" # ");break;
					case 4:
						printf(" o ");break;
					case 6:
						printf(" @ ");break;
					case 7:
						cnt++;             //统计一下目标与箱子叠加的个数
						printf(" # ");break;
				}
			}
			printf("\n");
		}

		if(cnt==4)         //四个箱子都在目标位置上就说你成功了
		{
			printf("走了:%d步数",step);
			return 0;
		}

		cnt=0;
		up=0;
		on=0;
		
		switch(getch())
		{
			case 183:
				up--;
				break;
			case 184:
				up++;
				break;
			case 185:
				on++;
				break;
			case 186:
				on--;
				break;
		}

		if(0==arry[indix1+up][indix2+on]||4==arry[indix1+up][indix2+on])	
		{
			arry[indix1+up][indix2+on] +=2;
			arry[indix1][indix2]  -=2;
			indix1 +=up;
			indix2 +=on;
			step++;
		}
		else if(3==arry[indix1+up][indix2+on]||7==arry[indix1+up][indix2+on])
		{
			if(arry[indix1+up*2][indix2+on*2]==0||arry[indix1+up*2][indix2+on*2]==4)
			{
				arry[indix1+up*2][indix2+on*2] +=3;
				arry[indix1+up][indix2+on]  -=1;
				arry[indix1][indix2] -=2;
				indix1 +=up;
				indix2 +=on;
				step++;
			}
		}

	}
}
	


上一篇:Vue指令 第三天


下一篇:Java项目实践:聊天工具