(单片机原理与应用)大液晶屏的游戏设计(推箱子)

中文摘要

设计一款在以51单片机为核心的硬件系统中运行的推箱子游戏。游戏一共9关,功能包括:1、显示游戏开机界面和游戏界面;2、按键处理包括移动小人和移动箱子,通过移动上下左右键来控制小人的移动,通过小人推动箱子,把箱子推到指定的目的地为过关,箱子只能推不能拉;3、用于可以任意选关,并能随时退出、进入游戏;4、每一关都有时间计时,显示当前玩家的游戏耗时。

关键字:推箱子、51单片机

前言

推箱子是一个来自日本的经典游戏,目的是在训练逻辑思考能力。在一个规定区域中,要求把木箱放到指定的位置,稍不小心就会出现箱子无法移动或者通道被堵住的情况,所以需要巧妙的利用有限的空间和通道,合理安排移动的次序和位置,才能顺利的完成任务。本设计利用C语言将推箱子游戏移植到51单片机的硬件系统,选择基于51单片机的推箱子游戏设计作为本次课设的题目。

系统的开发过程

第一节 硬件设计

根据设计目标,整个系统框图如下:

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第1张图片

图一:总体设计框图

第一小节AT89C51简介

AT89C51是美国ATMEL公司生产的低功耗,高性能CMOS8位单片机,片内含4kbytes的可编程的Flash只读程序存储器,兼容标准8051指令系统及引脚,并集成了 Flash 程序存储器,既可在线编程(ISP),也可用传统方法进行编程,因此,低价位AT89C51单片机可应用于许多高性价比的场合,可灵活应用于各种控制领域,对于简单的测温系统已经足够。单片机AT89C51具有低电压供电和体积小等特点,四个端口只需要两个口就能满足电路系统的设计需要,很适合便携手持式产品的设计使用系统可用二节电池供电。芯片AT89C51的引脚排列如图二所示:

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第2张图片

图二:AT89C51单片机引脚图

第二小节晶振电路的设计

单片机晶振电路的设计如图三所示。XTAL1(X1)为反向振荡放大器的输入及内部时钟工作电路的输入。按照理论上AT89C51使用的是12MHz的晶振,但实测使用11.0592MHz。所以设计者通常用的是11.0592MHz。 

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第3张图片

图三:单片机晶振电路

第三小节游戏显示电路的设计

选用内置T6963C控制控制器的12864图形点阵液晶(以下简称Lcd12864)做为显示模块。

T6963C控制器的最大特点具是有硬件初始值设置功能,显示驱动所需的参数,例如:占空比系数、每行驱动传输的字节数、字符的字体选择等均由引脚电平设置。所以,液晶显示模块在上电时T6963C控制器就进行初始化设置,软件操作的主要精力就可以全部用于显示界面的设计上。

LCD12864和单片机以模拟方式连接,即通过模拟操作时序的方法控制液晶显示。具体的接线图如图四所示: 

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第4张图片

图四:显示电路设计图

第五小节按键电路的设计

本设计用到的按键不多,故最后选择使用7个轻触按键连接成2*4-1矩阵键盘,作为按键电路,如图五所示:

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第5张图片

图五:按键设计电路图

第二节 界面设计

第一小节 Lcd12864显示驱动程序

      准备向Lcd12864进行操作时,首先要读取lcd12864的当前的状态,只有lcd12864不忙的时候才能读写操作和数据。相关函数如下:

/**************************************************

函数名:status_bit_01()

功能:状态位sta1(读/写指令),sta0(读/写数据)判断

入口参数:

返回值:状态值i                                                      

***************************************************/

/*********************************************

函数名:write_data(unsigned char dat)

功能:写数据

入口参数:8位数据dat

返回值:

*********************************************/

/*********************************************

函数名:write_cmd1(unsigned char cmd)

功能:写命令,无参数

入口参数:8位命令cmd

返回值:

*********************************************/

/*********************************************

函数名:write_cmd2(unsigned char cmd)

功能:写单参数命令

入口参数:8位数据dat,8位命令cmd

返回值:

*********************************************/

/************************************************

函数名:write_cmd3(unsigned char cmd)

功能:写双参数命令

入口参数:8位数据data1,8位数据data2,8位命令cmd

返回值:

*************************************************/

图六为Lcd12864的指令集,向Lcd12864写入相关的指令,即可控制其显示。

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第6张图片

图六:Lcd12864的指令集

使用液晶前必须对其进行初始化操作,初始化的内容包括光标指针设置,图形区首地址,图形区宽度,显示方式设置,图形方式显示,标形状设置。相关函数如下:

/************************************************

函数名:init_12864()

功能:初始化lcd12864

入口参数:

返回值:

*************************************************/     

第二小节 按键扫描程序

初始P1的电平为0x0f,当有按键下时,电平发生变化,开始程序开始扫描判断哪个按键被按下,并返回按键号,相关函数如下:

/********************************

函数名:keys_scan()

功能:按键扫描

入口参数:

返回值:按键号keyno

*********************************/

第三小节游戏元素设计和显示

出现在显示画面中的游戏元素总共有6种:空白,人物,砖头(墙壁),箱子,目标,箱子到达目标。每个元素在液晶上以8个字符显示,即8×8的点阵。在字模提取软件设计各个元素,并获得元素的显示码。显示码的每8位构成字符的一行,8就行有8个字节。其中1表示该点显示,0表示该点不显示。图七-1至图七-6为各种游戏元素的图标:

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第7张图片

定义一个二维数组unsignedchar code elements[][8],存储这些点阵信息。其中行号为元素代号。由于T6963c液晶是按以列1字符(8点),行1点来定位的,所以显示时,要先定位显示字符位的列字符和行字符首地址,即行*0x80+列;再定义一个循环变量i,从0,到7,定位该字符位的8个点行,即行*0x80+列+i*0x10,定位到每个点行后,写入对应的元素字节,即elements[元素代号][i],就可以在液晶的指定字符位置上显示该元素了。相关元素显示子函数如下:

/************************************************

函数名:printelement()

功能:指定字符位置,显示元素

入口参数:列字符地址xh,行字符地址yh,元素代码elnum

返回值:

*************************************************/

调用如下程序,对显示元素进行测试,图19为显示效果:

printelement(0,1,1);  //在第0列,第1行,显示1号元素(人物)

printelement(1,1,2);  //在第1列,第1行,显示2号元素(墙壁)

printelement(2,1,3);  //在第2列,第1行,显示3号元素(箱子)

printelement(3,1,4);  //在第3列,第1行,显示4号元素(目的地)

printelement(4,1,5);  //在第4列,第1行,显示5号元素(箱子在目的地上)

第四小节游戏关卡界面设计

游戏每关都是在8×8个字符组成的区域中进行的,只要在每一个字符显示相应的元素,就可以组成游戏界面。定义一个三维数组code level[][8][8],存储每一关每一个字符位上要显示的元素。下面图八-1至图八-9为游戏界面

 各关卡的界面如下:

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第8张图片

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第9张图片

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第10张图片

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第11张图片

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第12张图片

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第13张图片

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第14张图片

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第15张图片

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第16张图片

第五小节开机界面

开机画面是用画图程序制作的一个128像素×64像素的单色位图,并用软件提取该图像的点阵信息,共1024字节。使用t6963c的写数据地址自动加1的命令写入上述全部1024字节的数据,显示开机画面如下,图像的点阵码在unsigned char code start_box[]中定义,其中宽度*高度=128*64。

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第17张图片

第三节 游戏流程设计

游戏中,程序循环执行按键扫描程序,并做出相应判断。整个程序中,最关键的部分是要根据玩家的输入,控制小人、箱子的移动。

定义一个二维数组,用于保存当前游戏状态每个字符位的元素,当玩家按键输入时,改变该数组中相应得数据,再将此二维数组每个数据代码的元素显示出来,就可以出现人物,箱子移动的效果。

每关开始,进行游戏初始化。将关卡数据写入上述二维数组中,并记入小人的位置(man_x,man_y)。

程序只要根据人物移动方向周围的元素信息,结合游戏规则,只要判断能够移动箱子、小人的情况,才显示出来,而不用对不能移动的情况进行判定,这大大简化了程序的编写。游戏的流程框图如下(以向上移动为例,其他方向类似):

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第18张图片

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第19张图片

每进行一次移动后就进行是否过关的判定。将记录本关每个字符位状态的数组与存储本关原始信息的数组的对应数据进行比较,若发现目的地上没有箱子,则不算过关,程序退出,进入等待按键输入程序,若所有的目的地都有箱子,则游戏过关,初始化下一关游戏,显示下一关游戏界面。按相应的选关键,会改变记录游戏关卡的变量levelg,对游戏重新初始化,即可记录所选关卡。

第四节 计时设计

利用右半屏的8×8字节的空间,显示当前游戏计时和当前关卡。其中汉字占4个字符,数字占两个字符。显示方式与游戏元素的显示方式相同。显示效果如图所示,使用定时器0的计时功能,每到1秒,触发中断程序,计时变量Timtcount就加1,在对其进行数字分解,将各位在响应的位置上显示出来。
(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第20张图片

图十一 计时界面显示效果

系统测试情况

进入测试,游戏程序如下图所示,首先会显示开机界面,玩家可以按照按开始按钮即可开始游戏,游戏过程中可以进行计时,玩家可以上下左右移动控制人物的位置,也可以搬箱子移动指定目的地,当关卡完成自动进入下一关。当然,玩家也可以选择不同关卡进行游戏。最后,如果按退出按钮即可返回开机界面。

(单片机原理与应用)大液晶屏的游戏设计(推箱子)_第21张图片

图十二 游戏程序界面

系统的优点与不足

优点:游戏容易上手,而且可以锻炼大脑思维

不足:有些关卡设计简单

参考文献

[1] 陈海宴. 51单片机原理及应用--基于Keil C与Proteus. 北京航空航天大学出版,2010-07-01,第1版.

[2] 彭伟. 单片机C语言程序设计实训100例——基于8051+PROTEUS仿真. 电子工业出版社,2009-06-01 .

[3] 浦滨. C游戏编程从入门到精通. 北京希望电子出版社,2002-5-1

[4] 李宏 张家田,等. 液晶显示器件应用技术  机械工业出版社, 2004-7-1

[5]AT89c52数据手册

附录代码

Variable.h
#define uchar unsigned char
#define uint unsigned int
//**********T6963c命令宏定义*********************//
//地址指针设置
#define cur_pos 0x21 //光标位置设置
#define CGR_pos 0x22 //CGRAM偏置地址设置
#define add_pos 0x24 //地址指针位置

//显示区域设置
#define txt_stp 0x40 //文本区首地址
#define txt_wid 0x41 //文本区宽度
#define grh_stp 0x42 //图形区首地址
#define grh_wid 0x43 //图形区宽度

//显示方式设置
#define mod_or  0x80 //显示方式:逻辑或
#define mod_xor 0x81 //显示方式:逻辑异或
#define mod_and 0x82 //显示方式:逻辑与
#define mod_tch 0x83 //显示方式:文本特征

//显示状态设置
#define dis_sw 0x90 //显示开关
                    //D0=1/0:光标闪烁启用/禁用
					//D1=1/0:光标显示启用/禁用
					//D2=1/0:文本显示启用/禁用
					//D3=1/0:图形显示启用/禁用

//光标形状设置
#define cur_shp 0xa0 //光标形状选择:0xa0~0xa7光标占的行数:1行~8行

//数据自动读写设置
#define aut_wr  0xb0 //自动写
#define aut_rd  0xb1 //自动读
#define aut_ovr 0xb2 //自动读写结束

//数据一次读写设置
#define inc_wr 0xc0 //数据写,地址+1
#define inc_rd 0xc1 //数据读,地址+1
#define dec_wr 0xc2 //数据写,地址-1
#define dec_rd 0xc3 //数据读,地址-1
#define noc_wr 0xc4 //数据写,地址不变
#define noc_rd 0xc5 //数据读,地址不变

uchar tcount;  			//中断计数
uint Timtcount;			//计时变量(秒)
uchar playing,startflag;//游戏标志,开始标志
uchar levelg; 			//记录当前关卡
uchar man_x,man_y;		//纪录当前小人所在位置
//**********lcd12864引脚位定义*********************//
sbit wr =P2^0;
sbit rd =P2^1; 
sbit cd =P2^2;
sbit rst=P2^3; 

uchar code Number[][16]= //数字0-9
{
	0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00,	    //0
	0x00,0x00,0x00,0x10,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,		//1
	0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x04,0x04,0x08,0x10,0x20,0x42,0x7E,0x00,0x00,		//2
	0x00,0x00,0x00,0x3C,0x42,0x42,0x04,0x18,0x04,0x02,0x02,0x42,0x44,0x38,0x00,0x00,		//3
	0x00,0x00,0x00,0x04,0x0C,0x14,0x24,0x24,0x44,0x44,0x7E,0x04,0x04,0x1E,0x00,0x00,	    //4
	0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x58,0x64,0x02,0x02,0x42,0x44,0x38,0x00,0x00,		//5
	0x00,0x00,0x00,0x1C,0x24,0x40,0x40,0x58,0x64,0x42,0x42,0x42,0x24,0x18,0x00,0x00,		//6
	0x00,0x00,0x00,0x7E,0x44,0x44,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,		//7
	0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x42,0x3C,0x00,0x00,		//8
	0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x26,0x1A,0x02,0x02,0x24,0x38,0x00,0x00,		//9
};
//开机画面
uchar code start_box[]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xE0,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xFC,0x7C,0xC0,0x06,0x30,0xC6,0x00,0x1F,0xFF,0xFF,0x00,0x00,0x00,
0x00,0x00,0x01,0x86,0xC7,0xF0,0x06,0x1F,0xC7,0xF8,0x30,0x00,0x01,0xC0,0x00,0x00,
0x00,0x00,0x01,0x87,0x86,0x18,0x0C,0x01,0x80,0x0C,0x30,0x00,0x00,0xC0,0x00,0x00,
0x00,0x00,0x01,0x87,0x82,0x18,0x1C,0x01,0x80,0x0E,0x30,0x00,0x00,0x40,0x00,0x00,
0x00,0x00,0x01,0x87,0x06,0x0C,0x18,0x01,0x00,0x06,0x30,0x00,0x00,0x40,0x00,0x00,
0x00,0x00,0x0F,0x87,0x07,0x0F,0x10,0x03,0x00,0x0C,0x30,0x00,0x00,0xC0,0x00,0x00,
0x00,0x00,0x0C,0x06,0x00,0x01,0x90,0x43,0x00,0x0C,0x1F,0xFF,0x01,0x80,0x00,0x00,
0x00,0x00,0x0C,0x06,0x00,0x01,0x98,0xC3,0x08,0x38,0x00,0x3E,0x03,0x00,0x00,0x00,
0x00,0x00,0x0C,0x0C,0x00,0x01,0x8F,0xC3,0x1C,0x38,0x00,0x3C,0x06,0x00,0x00,0x00,
0x00,0x00,0x0C,0x0C,0x00,0x03,0x1F,0xC7,0xFC,0x7C,0x7F,0xF6,0x0F,0xE0,0x00,0x00,
0x00,0x00,0x0F,0x88,0x1E,0x1F,0x1C,0x7F,0x67,0xDC,0xC0,0x03,0x18,0x30,0x00,0x00,
0x00,0x00,0x01,0x8C,0x00,0x03,0x18,0x01,0x80,0x0C,0xC0,0x01,0xF0,0x30,0x00,0x00,
0x00,0x00,0x03,0x87,0x80,0x03,0x10,0x00,0x80,0x0C,0xC0,0x00,0x00,0x30,0x00,0x00,
0x00,0x00,0x0E,0x01,0x80,0x03,0x10,0x00,0x9F,0x0C,0xC0,0x00,0x00,0x30,0x00,0x00,
0x00,0x00,0x0C,0x01,0x80,0x03,0x18,0x0F,0x80,0x0C,0xC0,0x00,0x00,0x30,0x00,0x00,
0x00,0x00,0x0C,0x01,0x9E,0x1F,0x0E,0x1B,0x80,0x0C,0xC0,0x00,0x00,0x30,0x00,0x00,
0x00,0x00,0x0C,0x03,0x00,0x03,0x0E,0x31,0x00,0x0C,0x7F,0xF0,0x7F,0xE0,0x00,0x00,
0x00,0x00,0x0C,0x06,0x00,0x03,0x1C,0x30,0x9F,0x0C,0x00,0x30,0x60,0x00,0x00,0x00,
0x00,0x00,0x07,0x86,0x00,0x03,0x38,0x30,0xC0,0x0C,0x00,0x30,0x60,0x00,0x00,0x00,
0x00,0x00,0x01,0x86,0x1E,0x1F,0x30,0x18,0xC0,0x0C,0x01,0xF0,0x60,0x00,0x00,0x00,
0x00,0x00,0x07,0x86,0x00,0x01,0xB0,0x0F,0x80,0x0C,0x03,0x00,0x60,0x00,0x00,0x00,
0x00,0x00,0x0C,0x06,0x00,0x01,0x98,0x07,0x1F,0x0C,0x03,0x00,0x60,0x00,0x00,0x00,
0x00,0x00,0x0C,0x06,0x00,0x01,0x8C,0x06,0x00,0x0C,0x03,0x00,0x60,0x00,0x00,0x00,
0x00,0x00,0x0C,0x06,0x00,0x03,0x07,0x06,0x00,0x0C,0x03,0x00,0x60,0x00,0x00,0x00,
0x00,0x00,0x0C,0x06,0x0F,0xFF,0x03,0x06,0x00,0x0C,0x03,0x00,0x60,0x00,0x00,0x00,
0x00,0x00,0x0C,0x0F,0x18,0x00,0x03,0x07,0x00,0x18,0x03,0x00,0xC0,0x00,0x00,0x00,
0x00,0x00,0x07,0xF9,0xF0,0x00,0x01,0xFD,0xFF,0xF0,0x01,0xFF,0x80,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFD,0xFE,0x18,0x7F,0x3F,0xC0,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x8D,0xB6,0x18,0x31,0xB6,0xC0,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x8C,0x30,0x1C,0x31,0x86,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x30,0x3C,0x31,0x86,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x30,0x3C,0x3F,0x06,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x30,0x36,0x36,0x06,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x30,0x3E,0x36,0x06,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x30,0x66,0x33,0x06,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x8C,0x30,0x63,0x33,0x06,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x8C,0x30,0x63,0x31,0x86,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xF8,0x78,0xF7,0xF9,0xCF,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
/*********************************************
游戏关卡 一共9关
数字符号表示:人物1 砖头2 箱子3 目的4 成功5
**********************************************/
uchar code level[][8][8]={
	/*第1关*/
	0,0,2,2,2,2,2,0,
	2,2,2,0,0,0,2,0,
	2,0,3,0,2,0,2,2,
	2,0,2,0,0,4,0,2,
	2,0,0,0,0,2,0,2,
	2,2,0,2,0,0,0,2,
	0,2,1,0,0,2,2,2,
	0,2,2,2,2,2,0,0,
	
	/*第2关*/
	2,2,2,2,2,2,2,2,
	2,0,0,0,0,0,1,2,
	2,0,0,0,5,0,0,2,
	2,0,0,2,2,2,2,2,
	2,2,0,0,2,0,0,0,
	2,0,3,0,2,0,0,0,
	2,0,0,4,2,0,0,0,
	2,2,2,2,2,0,0,0,

	/*第3关*/
	0,0,2,2,2,2,0,0,
	0,0,2,4,4,2,0,0,
	0,2,2,0,4,2,2,0,
	0,2,0,0,3,4,2,0,
	2,2,0,3,0,0,2,2,
	2,0,0,2,3,3,0,2,
	2,0,0,1,0,0,0,2,
	2,2,2,2,2,2,2,2,

	/*第4关*/
	0,0,0,2,2,2,2,0,
	0,2,2,2,0,1,2,0,
	0,2,0,0,3,0,2,0,
	2,2,0,2,0,2,2,2,
	2,0,0,2,0,2,4,2,
	2,0,2,0,0,3,4,2,
	2,0,0,0,0,0,0,2,
	2,2,2,2,2,2,2,2,

	/*第5关*/
	0,0,0,2,2,2,2,0,
	0,2,2,2,0,1,2,0,
	0,2,0,0,3,0,2,0,
	2,2,0,2,0,2,2,2,
	2,0,0,2,0,2,4,2,
	2,0,2,0,0,0,0,2,
	2,0,0,0,0,0,0,2,
	2,2,2,2,2,2,2,2,

	/*第6关*/
	0,0,0,2,2,2,2,0,
	0,2,2,2,0,1,2,0,
	0,2,0,0,3,0,2,0,
	2,2,0,2,0,2,2,2,
	2,0,0,2,0,2,4,2,
	2,0,2,0,0,3,4,2,
	2,0,3,0,0,0,4,2,
	2,2,2,2,2,2,2,2,
	
	/*第7关*/
	0,0,2,2,2,2,2,0,
	2,2,2,0,0,0,2,0,
	2,0,3,0,2,0,2,2,
	2,0,2,0,0,4,0,2,
	2,0,0,0,0,2,0,2,
	2,2,3,2,4,0,0,2,
	0,2,1,0,0,2,2,2,
	0,2,2,2,2,2,0,0, 	
	
	/*第8关*/
	0,2,2,2,2,0,0,0,
	2,2,0,0,2,0,0,0,
	2,1,3,0,2,0,0,0,
	2,2,3,0,2,2,0,0,
	2,2,0,3,0,2,0,0,
	2,4,3,0,0,2,0,0,
	2,4,4,5,4,2,0,0,
	2,2,2,2,2,2,0,0,

	/*第9关*/
	0,0,0,2,2,2,2,0,
	0,2,2,2,0,0,2,0,
	2,2,0,1,3,0,2,0,
	2,0,4,3,0,0,2,0,
	2,0,4,5,0,2,2,0,
	2,0,4,3,0,2,0,0,
	2,2,0,0,2,2,0,0,
	0,2,2,2,2,0,0,0,
	
};
uchar level_temp[8][8]=				//记录当前的游戏界面的变化
{
	0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,
};
uchar code elements[][8]=
{
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //0空白
	0x3C,0x7E,0x66,0x3C,0x7E,0x99,0x3C,0x66,  //1人物
	0x7F,0x7F,0x7F,0x00,0xEF,0xEF,0xEF,0x00,  //2砖头
	0xFF,0xC3,0xA5,0x99,0x99,0xA5,0xC3,0xFF,  //3箱子
	0x00,0x18,0x24,0x4A,0x52,0x24,0x18,0x00,  //4目标
	0xFF,0xBD,0xDB,0xE7,0xE7,0xDB,0xBD,0xFF,  //5箱子到达目标	 	
};	
unsigned char code Di[]=	//"第"字														  //第
{
	0x20,0x40,0x3F,0x7E,0x48,0x90,0x85,0x08,0x3F,0xF8,0x01,0x08,0x01,0x08,0x3F,0xF8,
	0x21,0x00,0x21,0x00,0x3F,0xFC,0x03,0x04,0x05,0x04,0x19,0x28,0xE1,0x10,0x01,0x00,
};
unsigned char code Guan[]=	//“关”字													   //关
{
	0x10,0x10,0x08,0x10,0x08,0x20,0x00,0x00,0x3F,0xF8,0x01,0x00,0x01,0x00,0x01,0x00,
	0xFF,0xFE,0x01,0x00,0x02,0x80,0x02,0x80,0x04,0x40,0x08,0x20,0x30,0x18,0xC0,0x06,
};

unsigned char code Yong[]=	//“用”字														//用
{
	0x00,0x00,0x3F,0xF8,0x21,0x08,0x21,0x08,0x21,0x08,0x3F,0xF8,0x21,0x08,0x21,0x08,
	0x21,0x08,0x3F,0xF8,0x21,0x08,0x21,0x08,0x21,0x08,0x41,0x08,0x41,0x28,0x80,0x10,
}; 

unsigned char code Shi[]=	//“时”字															//时
{
	0x00,0x08,0x00,0x08,0x7C,0x08,0x44,0x08,0x45,0xFE,0x44,0x08,0x44,0x08,0x7C,0x08,
	0x44,0x88,0x44,0x48,0x44,0x48,0x44,0x08,0x7C,0x08,0x44,0x08,0x00,0x28,0x00,0x10,
};

unsigned char code Miao[]=	//“秒”字														//秒
{
	0x08,0x20,0x1C,0x20,0xF0,0x20,0x10,0xA8,0x10,0xA4,0xFC,0xA2,0x11,0x22,0x31,0x20,
	0x3A,0x24,0x54,0x24,0x54,0x28,0x90,0x08,0x10,0x10,0x10,0x20,0x10,0xC0,0x00,0x00,
};



main.c
#include
#include"Variable.h"
/**************************************************
函数名:status_bit_01()
功能:状态位sta1(读/写指令),sta0(读/写数据)判断
入口参数:
返回值:状态值i	
***************************************************/ 
uchar status_bit_01()     
{
	uchar i;  	
	P0=0xff;
	cd=1;
	rd=0;
	for(i=10;i>0;i--)
	{
		if((P1&0x03)==0x03)
		break;
	}
	rd=1;
	return i;                 
}

/*********************************************
函数名:write_data(uchar dat)
功能:写数据
入口参数:8位数据dat
返回值:
*********************************************/
void write_data(uchar dat)
{
	while(status_bit_01()==0); 
	rd=1;cd=0;wr=0;
	P0=dat;
	wr=1;cd=1;	  //一定要有这一句,补完后面的时序!
} 
/*********************************************
函数名:write_cmd1(uchar cmd)
功能:写命令,无参数
入口参数:8位命令cmd
返回值:
*********************************************/
void write_cmd1(uchar cmd)
{
	while(status_bit_01()==0);
	rd=1;cd=1;wr=0;
	P0=cmd;
	wr=1;cd=0;	 //一定要有这一句,补完后面的时序!
}
 
/************************************************
函数名:write_cmd3(uchar cmd)
功能:写双参数命令
入口参数:8位数据data1,8位数据data2,8位命令cmd
返回值:
*************************************************/
void write_cmd3(uchar data1,uchar data2,uchar cmd)
{
   	write_data(data1); 	
	write_data(data2); 
	write_cmd1(cmd);
}

/************************************************
函数名:setc_xy()
功能:定位
入口参数:列字符地址x,行位地址y
返回值:
*************************************************/
void setc_xy(uchar x, uchar y)
{
	int temp;
	temp = y * 0x10 + x;
	write_cmd3(temp&0xff,temp/0xff,add_pos);		
}
/*********************************************
函数名:write_cmd2(uchar cmd)
功能:写单参数命令
入口参数:8位数据dat,8位命令cmd
返回值:
*********************************************/
void write_cmd2(uchar dat,uchar cmd)
{
	write_data(dat);
	write_cmd1(cmd);
}

/*********************************
功能:分解计时值的各位,并显示在响应的位置上
函数名:	time_change(unsigned int ttime)
入口参数:计时值
返回值:

***********************************/

void time_change(uint ttime)
{
	uchar a1,a2,a3,a4,a5;
	uchar i,j;
	a1=ttime/10000;	  
	a2=ttime/1000%10;
	a3=ttime/100%10;
	a4=ttime/10%10;
	a5=ttime%10;


	for(j=0;j<16;j++)	//a1
	{
		for(i=0;i<1;i++)
		{
			setc_xy(9+i,32+j); 
			write_cmd2(Number[a1][j],inc_wr);			 
		}
	}

	for(j=0;j<16;j++)	//a2
	{
		for(i=0;i<1;i++)
		{
			setc_xy(10+i,32+j);
			write_cmd2(Number[a2][j],inc_wr);			 
		}
	}

	for(j=0;j<16;j++)	 //a3
	{
		for(i=0;i<1;i++)
		{
			setc_xy(11+i,32+j);
			write_cmd2(Number[a3][j],inc_wr); 
		}
	}

	for(j=0;j<16;j++)	//a4
	{
		for(i=0;i<1;i++)
		{
			setc_xy(12+i,32+j);
			write_cmd2(Number[a4][j],inc_wr);			 
		}
	}

	for(j=0;j<16;j++)	 //a5
	{
		for(i=0;i<1;i++)
		{
			setc_xy(13+i,32+j);
			write_cmd2(Number[a5][j],inc_wr);		
		}
	} 		
}
/*********************************
功能:初始化51
函数名:	int51_timec()
入口参数:
返回值:

***********************************/
void int51_timec()
{
	EA=1;
	TMOD=0x11;
	ET0=1;
	TR0=0;
	TH0=(65536-50000)/256;
	TL0=(65536-50000)%256;

}
/*********************************
功能:定时器0中断
函数名:	t0_tt()
入口参数:
返回值:

***********************************/
void t0_tt() interrupt 1
{
	TH0=(65536-50000)/256;
	TL0=(65536-50000)%256;
	tcount++;
	if(tcount==20)
	{
		tcount=0;
		Timtcount++;
		time_change(Timtcount);	
	}			
}
/************************************************
函数名:init_12864()
功能:初始化lcd12864
入口参数:
返回值:
*************************************************/	
void init_12864()
{
	wr=1;rd=1;cd=1;rst=1;//初始化
	write_cmd3(0x01,0x00,0x21);//光标指针设置
	write_cmd3(0x00,0x00,0x42);//图形区首地址
	write_cmd3(16,0x00,0x43);//图形区宽度 
	write_cmd1(0x88);//显示方式设置,正常显示
	write_cmd1(0x98);//图形方式显示,不显示字母,只打点
	write_cmd1(0xa0);//光标形状设置1 0 1 0 0 N2 N1 N0
}
/************************************************
函数名:start_ui()
功能:开机画面
入口参数:
返回值:
*************************************************/
void start_ui()
{
	uint i;
	setc_xy(0,0);
	for(i=0;i<1024;i++)
	{
		write_cmd2(start_box[i],inc_wr);
	}
} 
/********************************
函数名:delayms(x)
功能:按键扫描延时
入口参数:x=延迟时间
返回值:
*********************************/
void delayms(uint x)
{
	uchar i;
	while(x--); 
	for(i=0;i<100;i++);
}  

/********************************
函数名:keys_scan()
功能:按键扫描
入口参数:
返回值:按键号keyno 
*********************************/
uchar  keys_scan()	   
{	
	uchar tmp; //高4位置1,放入4行
	uchar keyno=16;
	if(P1 != 0x0f)
	{
		P1 = 0x0f; 	
		delayms(1); 
		//按键后00001111将编程0000××××,×中有一个为0.其余为1
		//下面的异或操作会把3个1变成0,唯一的0变成1
		tmp = P1 ^ 0x0f;
		//判断按键发生于0-3列中哪一列
		switch(tmp)
		{
			case 1: keyno = 0;break;
			case 2: keyno = 1;break;
			case 4: keyno = 2;break;
			case 8: keyno = 3;break;
			default:keyno = 16;//无键按下	
		}	
		//低4位置0,放入4列
		P1 = 0xf0;
		delayms(1);
		//按键后11110000将变成××××0000,×中有1个为0,3个仍为1
		tmp = (P1 >> 4)^ 0x0f;
		//对0-3行分别附加起始值0,4,8,12
		switch(tmp)
		{
			case 1:keyno += 0;break;
			case 2:keyno += 4;break;
			case 4:keyno += 8;break;
			case 8:keyno += 12;break;	
		}
		P1=0x0f;	
		return keyno;
	}	
	return keyno; 	
}
/************************************************
函数名:clc()
功能:清屏
入口参数:
返回值:
*************************************************/
void clc()
{			  
	int i;
	write_cmd3(0,0,add_pos);
	for(i = 0; i < 1024; i++)
		write_cmd2(0x00,inc_wr);
}
/************************************************
函数名:printelement()
功能:指定字符位置,显示元素
入口参数:列字符地址xh,行字符地址yh,元素代码elnum
返回值:
*************************************************/
void printelement(uchar xh, uchar yh,uchar elnum)	 
{
	uchar i;
	int temp; 	
	for(i=0;i<8;i++)  //行地址加+1
	{
		temp = yh* 0x80+i*0x10 + xh;
		write_cmd3(temp&0xff,temp/0xff,add_pos);
		write_cmd2(elements[elnum][i],noc_wr); 
	} 	
}
void display_time()
{
	unsigned i,j;	
	for(j=0;j<16;j++)//显示“第”字
	{
		for(i=0;i<2;i++)
		{
			setc_xy(9+i,j);
			write_cmd2(Di[j*2+i],inc_wr);//数组的地址不要乱!
		}
	}

	for(j=0;j<16;j++)//关数
	{
		for(i=0;i<1;i++)
		{
			setc_xy(11+i,j);
			write_cmd2(Number[levelg+1][j],inc_wr);	//数组的地址不要乱!
		}
	}

	for(j=0;j<16;j++)
	{
		for(i=0;i<2;i++)
		{
			setc_xy(12+i,j);
			write_cmd2(Guan[j*2+i],inc_wr);//“关”字	 
		}
	}

	for(j=0;j<16;j++)
	{
		for(i=0;i<2;i++)												//列式按字符寻址的,行是按位寻址的
		{
			setc_xy(9+i,16+j);
			write_cmd2(Yong[j*2+i],inc_wr);		//“用”字	 
		}
	}

	for(j=0;j<16;j++)
	{
		for(i=0;i<2;i++)
		{
			setc_xy(12+i,16+j);
			write_cmd2(Shi[j*2+i],inc_wr);		//“时”字	 
		}
	}

	for(j=0;j<16;j++)
	{
		for(i=0;i<2;i++)
		{				 
			setc_xy(14+i,32+j);
			write_cmd2(Miao[j*2+i],inc_wr);		//“秒”字	 
		}
	}  
}

/************************************************
函数名:gamebg()
功能:显示游戏本关卡游戏界面
入口参数:关卡代号g
返回值:
*************************************************/
void gamebg(uchar g)
{
	unsigned i,j;
	for(i=0;i<8;i++)                                      //行
	{
		for(j=0;j<8;j++)                                  //列
		{
			if(level[g][i][j]==1) 
			{
				man_x=j;
				man_y=i;
			}
			level_temp[i][j]=level[g][i][j];              //当前关卡存入游戏缓冲
			printelement(j,i,level_temp[i][j]);          //显示当前关卡	
		}
	}

	display_time();
	time_change(Timtcount);	
		
}
/************************************************
函数名:level_suc()
功能:判断是否通过本关卡
入口参数:
返回值:
*************************************************/
void level_suc()
{
	uchar i,j,k=1;
	for(i = 0; i < 8; i++)	                                    //行
	{
		if(k==0) break;
		for(j = 0; j < 8; j++)									//列
		{	                                                     
			if(level[levelg][i][j]==4||level[levelg][i][j]==5)	//循环扫描目标位置都有箱子在,此关卡就通过
			{
				if(level_temp[i][j]==5)
					k=1;										//此位置箱子在目标位置上
				else
				{
					k=0;										//有目标位置没有箱子
					break;
				}
			}
		}
	}
	if(k==1)													 //所有目标位置都有箱子
	{
		if(levelg<8)
			levelg+=1;
		else 
			levelg=0;			 //通关后重新从第一关开始
		Timtcount=0;			 //计时清零
		TH0=(65536-50000)/256;
		TL0=(65536-50000)%256;
		tcount=0;
		gamebg(levelg);			
	}
}

/************************************************
函数名:key_up()
功能:按向上键的操作
入口参数:
返回值:
注释含义:
          ?=:是否等与
		  上:本位置的上一个位置
		  目: 箱子的目标位置
		  成:箱子在目标位置上
		  源:位置最开始的元素
		  本:本位置
		  空:空白位置
		  再上:本位置的再上一个位置
		  箱:箱子
*************************************************/
void key_up()
{
	if(level_temp[man_y-1][man_x]==0||level_temp[man_y-1][man_x]==4)	             //上?=目/成   
	{		 
		if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)           //本,源?=目/成
		{
			level_temp[man_y][man_x]=4;										         //本=目
			printelement(man_x,man_y,4);	   
		}
		else
		{
			level_temp[man_y][man_x]=0;										         //本=空
			printelement(man_x,man_y,0);
		}
		man_y=man_y-1;													             //上=人//完成一次移动
		level_temp[man_y][man_x]=1;
		printelement(man_x,man_y,1);
	} 
	else if(level_temp[man_y-1][man_x]==3)								             //上?=箱
	{				  
		if(level_temp[man_y-2][man_x]==0)									         //再上?=空白
		{
			if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)	     //本,源?=目/成
			{
				level_temp[man_y][man_x]=4;										     //本=目
				printelement(man_x,man_y,4);
			}
			else																	 //本=空
			{
				level_temp[man_y][man_x]=0;
				printelement(man_x,man_y,0);
			}
			man_y=man_y-1;														     //上=人
			level_temp[man_y][man_x]=1;
			printelement(man_x,man_y,1);
			level_temp[man_y-1][man_x]=3;										     //再上=箱//完成一次移动
			printelement(man_x,man_y-1,3);
		}
		else if(level_temp[man_y-2][man_x]==4)									     //再上?=目
		{
			if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)		 //本,源?=目/成
			{
				level_temp[man_y][man_x]=4;											 //本=目
				printelement(man_x,man_y,4);
			}
			else																	 //本=空
			{
				level_temp[man_y][man_x]=0;
				printelement(man_x,man_y,0);
			}
			man_y=man_y-1;					   
			level_temp[man_y][man_x]=1;												 //上=人
			printelement(man_x,man_y,1);
			level_temp[man_y-1][man_x]=5;											 //再上=成
			printelement(man_x,man_y-1,5); 			
		} 
	}
	else if(level_temp[man_y-1][man_x]==5)	                                          //上?=成
	{		   
		if(level_temp[man_y-2][man_x]==0)											  //再上?=空
		{
			if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)		  //本,源?=目/成
			{
				level_temp[man_y][man_x]=4;											  //本=目
				printelement(man_x,man_y,4);
			}
			else
			{																		  //本=空
				level_temp[man_y][man_x]=0;
				printelement(man_x,man_y,0);
			}
			man_y=man_y-1;															  //上=人
			level_temp[man_y][man_x]=1;
			printelement(man_x,man_y,1);
			level_temp[man_y-1][man_x]=3;										      //再上=箱
			printelement(man_x,man_y-1,3);
		}
		else if(level_temp[man_y-2][man_x]==4)										  //再上?=目
		{
			if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)		  //本,源?=目/成
			{
				level_temp[man_y][man_x]=4;											  //本=目
				printelement(man_x,man_y,4);
			}
			else																	  //本=空
			{
				level_temp[man_y][man_x]=0;
				printelement(man_x,man_y,0);
			}
			man_y=man_y-1;															  //上=人
		    level_temp[man_y][man_x]=1;
		    printelement(man_x,man_y,1);
		    level_temp[man_y-1][man_x]=5;											  //再上=成
		    printelement(man_x,man_y-1,5);	 		    
		}  			
	}
	level_suc();                                                                    //判断是否完成本关				 
}

/************************************************
函数名:key_down()
功能:按向下键的操作
入口参数:
返回值:
*************************************************/
void key_down()
{
	if(level_temp[man_y+1][man_x]==0||level_temp[man_y+1][man_x]==4)				   
	{
		if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)			   
		{
			level_temp[man_y][man_x]=4;												   
			printelement(man_x,man_y,4);
		}
		else
		{																			   
			level_temp[man_y][man_x]=0;
			printelement(man_x,man_y,0);
		} 																			   
	    man_y=man_y+1;
		level_temp[man_y][man_x]=1;
		printelement(man_x,man_y,1);
	}
	else if(level_temp[man_y+1][man_x]==3)											   
	{
		if(level_temp[man_y+2][man_x]==0)											  
		{
			if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)		   
			{
				level_temp[man_y][man_x]=4;											   
			    printelement(man_x,man_y,4);
			}
			else
			{
				level_temp[man_y][man_x]=0;											  
			    printelement(man_x,man_y,0);
			} 
			man_y=man_y+1;															   
			level_temp[man_y][man_x]=1;
			printelement(man_x,man_y,1);
			level_temp[man_y+1][man_x]=3;											   
			printelement(man_x,man_y+1,3);
		}
		else if(level_temp[man_y+2][man_x]==4)											
		{
			if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)
			{
				level_temp[man_y][man_x]=4;
				printelement(man_x,man_y,4);
			}
			else
			{
				level_temp[man_y][man_x]=0;
				printelement(man_x,man_y,0);
			}
			man_y=man_y+1;
			level_temp[man_y][man_x]=1;
			printelement(man_x,man_y,1);
			level_temp[man_y+1][man_x]=5;
			printelement(man_x,man_y+1,5);			
		}
	}
	else if(level_temp[man_y+1][man_x]==5)
	{
		if(level_temp[man_y+2][man_x]==0)
		{
			if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)
			{
				level_temp[man_y][man_x]=4;
			    printelement(man_x,man_y,4);
			}
			else
			{
				level_temp[man_y][man_x]=0;
			    printelement(man_x,man_y,0);
			}
				man_y=man_y+1;
				level_temp[man_y][man_x]=1;
				printelement(man_x,man_y,1);
				level_temp[man_y+1][man_x]=3;
				printelement(man_x,man_y+1,3);
		}
		else if(level_temp[man_y+2][man_x]==4)
		{
			if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)
			{
				level_temp[man_y][man_x]=4;
			    printelement(man_x,man_y,4);
			}
			else
			{
				level_temp[man_y][man_x]=0;
			    printelement(man_x,man_y,0);
			}					      
			man_y=man_y+1;
			level_temp[man_y][man_x]=1;
			printelement(man_x,man_y,1);
			level_temp[man_y+1][man_x]=5;
			printelement(man_x,man_y+1,5); 						  
		} 				  
	}				  				  
	level_suc();
}
/************************************************
函数名:key_left()
功能:按向左键的操作
入口参数:
返回值:
*************************************************/
void key_left()
{
	if(level_temp[man_y][man_x-1]==0||level_temp[man_y][man_x-1]==4)
	{
		if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)
		{
			level_temp[man_y][man_x]=4;
			printelement(man_x,man_y,4);
		}
		else
		{
			level_temp[man_y][man_x]=0;
			printelement(man_x,man_y,0);
		}
		man_x=man_x-1;
		level_temp[man_y][man_x]=1;
		printelement(man_x,man_y,1);
	}
	else if(level_temp[man_y][man_x-1]==3)
	{
		if(level_temp[man_y][man_x-2]==0)
		{
			if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)
			{
				level_temp[man_y][man_x]=4;
				printelement(man_x,man_y,4);
			}
			else
			{
				level_temp[man_y][man_x]=0;
				printelement(man_x,man_y,0);
			} 
			man_x=man_x-1;
			level_temp[man_y][man_x]=1;
			printelement(man_x,man_y,1);
			level_temp[man_y][man_x-1]=3;
			printelement(man_x-1,man_y,3);
		} 
		else if(level_temp[man_y][man_x-2]==4)
		{ 
			if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)
			{
				level_temp[man_y][man_x]=4;
				printelement(man_x,man_y,4);
			}
			else
			{
				level_temp[man_y][man_x]=0;
				printelement(man_x,man_y,0);
			}
			man_x=man_x-1;
			level_temp[man_y][man_x]=1;
			printelement(man_x,man_y,1);
			level_temp[man_y][man_x-1]=5;
			printelement(man_x-1,man_y,5);
		}
	}  
	else if(level_temp[man_y][man_x-1]==5)
	{
		if(level_temp[man_y][man_x-2]==0)
		{	
			if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)
			{
				level_temp[man_y][man_x]=4;
				printelement(man_x,man_y,4);
			}
			else
			{
				level_temp[man_y][man_x]=0;
				printelement(man_x,man_y,0);
			}
			man_x=man_x-1;
			level_temp[man_y][man_x]=1;
			printelement(man_x,man_y,1);
			level_temp[man_y][man_x-1]=3;
			printelement(man_x-1,man_y,3); 						      
		}
		else if(level_temp[man_y][man_x-2]==4)
		{	  
			if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)
			{
				level_temp[man_y][man_x]=4;
				printelement(man_x,man_y,4);
			}
			else
			{
				level_temp[man_y][man_x]=0;
				printelement(man_x,man_y,0);
			}	  					      
			man_x=man_x-1;
			level_temp[man_y][man_x]=1;
			printelement(man_x,man_y,1);
			level_temp[man_y][man_x-1]=5;
			printelement(man_x-1,man_y,5);
		}						 
	}			
	level_suc();			
}
/************************************************
函数名:key_right()
功能:按向右键的操作
入口参数:
返回值:
*************************************************/
void key_right()
{
	if(level_temp[man_y][man_x+1]==0||level_temp[man_y][man_x+1]==4)
	{
		if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)
		{
			level_temp[man_y][man_x]=4;
			printelement(man_x,man_y,4);
		}
		else
		{
			level_temp[man_y][man_x]=0;
			printelement(man_x,man_y,0);
		}
			man_x=man_x+1;
			level_temp[man_y][man_x]=1;
			printelement(man_x,man_y,1);
	}	
	else if(level_temp[man_y][man_x+1]==3)
	{	 
		if(level_temp[man_y][man_x+2]==0)
		{	  
			if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)
			{
				level_temp[man_y][man_x]=4;
				printelement(man_x,man_y,4);
			}
			else
			{
				level_temp[man_y][man_x]=0;
				printelement(man_x,man_y,0);
			}
			man_x=man_x+1;
			level_temp[man_y][man_x]=1;
			printelement(man_x,man_y,1);
			level_temp[man_y][man_x+1]=3;
			printelement(man_x+1,man_y,3);
		}
		else if(level_temp[man_y][man_x+2]==4)
		{	  
			if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)
			{
				level_temp[man_y][man_x]=4;
				printelement(man_x,man_y,4);
			}
			else
			{
				level_temp[man_y][man_x]=0;
				printelement(man_x,man_y,0);
			}	
			man_x=man_x+1;
			level_temp[man_y][man_x]=1;
			printelement(man_x,man_y,1);
			level_temp[man_y][man_x+1]=5;
			printelement(man_x+1,man_y,5);						  
		}	
	}	 
	else if(level_temp[man_y][man_x+1]==5)
	{	  
		if(level_temp[man_y][man_x+2]==0)
		{
			if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)
			{
				level_temp[man_y][man_x]=4;
				printelement(man_x,man_y,4);
			}
			else
			{
				level_temp[man_y][man_x]=0;
				printelement(man_x,man_y,0);
			}	
			man_x=man_x+1;
			level_temp[man_y][man_x]=1;
			printelement(man_x,man_y,1);
			level_temp[man_y][man_x+1]=3;
			printelement(man_x+1,man_y,3); 						      
		}
		else if(level_temp[man_y][man_x+2]==4)
		{	  
			if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5)
			{
				level_temp[man_y][man_x]=4;
				printelement(man_x,man_y,4);
			}
			else
			{
				level_temp[man_y][man_x]=0;
				printelement(man_x,man_y,0);
			}					      
			man_x=man_x+1;
			level_temp[man_y][man_x]=1;
			printelement(man_x,man_y,1);
			level_temp[man_y][man_x+1]=5;
			printelement(man_x+1,man_y,5); 						  
		}						 
	}					 
	level_suc();	
}
/************************************************
函数名:void put_box()
功能:推箱子游戏规则
入口参数:
返回值:
*************************************************/
void put_box()
{
	uint keyupdate;
	keyupdate=16;	
	if(P1!=0x0f)//若没有这句,有可能在按键扫描后执行while(P1!=0x0f),就得不到按键值,使按键失效
	{
		keyupdate=keys_scan();
		while(P1!=0x0f);	  
	}		
	switch(keyupdate)
	{
		case 0:  key_up();break;				                                 
		case 1:key_down();break;	
		case 2:key_left();break;
		case 3:key_right();break;		
		case 4:
				playing=0;
				startflag=1;
				Timtcount=0;
				TR0=0;
				clc();					
				start_ui();			
				break;	//退出游戏
		case 5:
				
				if(levelg!=8)
					levelg++;
				gamebg(levelg);		  //显示第一关
				Timtcount=0;
				TH0=(65536-50000)/256;
				TL0=(65536-50000)%256;
				tcount=0;
				break;				  //下一关
		case 6:
				
				if(levelg!=0)
				levelg--; 				
				gamebg(levelg);		  //显示第一关
				Timtcount=0;
				TH0=(65536-50000)/256;
				TL0=(65536-50000)%256;
				tcount=0;
				break;                     //上一关

	}
}

void main()
{
	uchar kupdate;
	uchar startflag; 
	int51_timec();               //初始化51
	init_12864();               //初始化12864
	startflag=1;
	playing=0;
	start_ui();

	while(1)
	{
		while(startflag)			 //等待确定键按下
		{
		  	kupdate=16;	
			if(P1!=0x0f)				//若没有这句,有可能在按键扫描后执行while(P1!=0x0f),就得不到按键值,使按键失效
			{
				kupdate=keys_scan();
				while(P1!=0x0f);	  
			}
			switch(kupdate)
			{
				case 4:
						startflag=0;
						playing=1;
						break;
			} 
		}
		
		clc();//清屏 
		levelg=0; 		
		gamebg(levelg);		  //显示第一关 
		Timtcount=0;
		TR0=1;
		while(playing)		  //游戏中...
		{
		 	put_box();	 
		}
		startflag=1;
	}			
}







你可能感兴趣的:((单片机原理与应用)大液晶屏的游戏设计(推箱子))