1、设计报告书 基于 ARM 硬件平台的贪吃蛇游戏 一、 设计题目: 贪吃蛇游戏 二、 设计要求: 在 LCD 屏幕上模拟贪吃蛇游戏。 1. 基本要求 ( 1)起初贪吃蛇蛇身为 1 节,贪吃蛇按照原来的方向行进直到通过按键改变贪吃蛇的行进方向。 ( 2)在教学实验箱上的 LCD 上绘制贪吃蛇,在他们的四周绘制四面墙,蛇身在行进的过程中不能碰到墙壁,碰到则游戏结束,提示是否重新开始,按确认键重新开始。若能保持不碰墙超过 1分钟则完成游戏,提示游戏是否重新开始,按确认键则重新开始。 2. 扩展内容 ( 1)实现贪吃蛇吃食物,食物跟 1节蛇身一样大小,其位置随机产生。在行进的过程中遇到产生的食物会将食物
2、吃掉,蛇身便长一节继续行进。当蛇身长到 6 节便提示游戏完成,屏幕显示祝贺,同时整个过程中 8段数码管会显示蛇身的长度。 ( 2)可用键盘按键选择游戏难度,难度通过设定蛇身的行进速度和游戏完成时蛇身的长 度确定。 三、 设计思路: ( 1) 验所需硬件: Embest 仿真器, Embest S3CEV40 实验箱, PC机 。 ( 2) 本次实验所需用到的硬件模块: LCD(用来显示 蛇的移动以及吃食物、撞墙等过程 );键盘(用来控制 贪吃蛇的上下左右移动以及游戏中的难度,蛇游动的快慢和蛇身体长度的设定); LED 七段数码管(用于显示现阶段蛇身体的节数,初始为一节)。 ( 3) 因为本次实
3、验要使 LCD 显示,并通过键盘产生中断控制 贪吃蛇 的运动状态和速度,所以本次实验主要同到的 .c 文件主要是 keyboard.c、 lcd.c、 8led.c和 main.c,主要在这几个文件上进行编程。本次实验的关键是如何在 LCD 中显示 蛇并且需要实现蛇的移动,以及蛇吃到食物之后 如何实现 蛇身增长一段以及如何用键盘产生中断控制蛇的移动方向、 速度 以及蛇身节数的上限值 。 四、 软件实现: 本次设计主要是考察我们对于 LCD 模块以及键盘中断的认识程度,刚开始的设想是 本 次贪吃蛇的 设计需要创建两个 流程 任务, 一个是键盘按下控制蛇的移动另一个是键盘没有按下贪吃蛇按照初始状态
4、移动。 任务流程和任务状态切换如下图。具体的任务流程和任务所要完成的功能如下: 在系统启动后,同时创建两个任务,任务一和任务二。任务一主要功能是等待键盘消息,有键盘消息的时候判断是什么键盘,并对相应的变量重新 赋值。任务二主要功能是控制并在屏幕上显示蛇的移动,并完成对游戏等级 和其他相关参数的记录和显示。任务一为主任务,在创建任务的时候,赋给它的优先级别比任务二高,所以任务一优先运行,任务二处于就绪状态,因为任务一主要是等待键盘消息,在无键盘消息的时 候,任务一被挂起,这时候任务二进入运行状态。这就是本次设计的主要框架。 程序主流程图: 是否有键盘消息 任务一挂起 任务一,任务二就绪 任务二挂
5、起 任务一运行 任务二运行 主任务流程图: 主要功能是等待键盘消息,有键盘消息的时候判断是 那个键按下来控制方向、难度、重启 并对相应的变量重新赋值。 等待键盘消息 是否有键盘按下 判断是哪个按键 否 上 如果蛇现在的方向是左或者右就把方向改成向上 下 如果蛇现在的方向是左或者右就把方向改成向下 左 如果蛇现在的方向是上或者下就把方向改成左 右 如果蛇现在的方向是上或者下就把方向改成右 增加贪吃蛇移动速度 RESET 增加蛇身体长度上限值 (初始上限为 4 节) 是 任务二流程图: 主要功能是控制并在屏幕上显示蛇的移动,并完判定蛇是否撞墙或者撞到自身 和其他相关参数的记录和显示。 初始化 游戏
6、是否结束 是 否 调用食物产生程序 根据 direction 变量移动蛇 是否吃到 食物 否 是 蛇的节数加 1 Node+1 节数是否到上限 是否要产生食物 否 是 是否按下重启键 显示结束画面 否 五、模块功能 : ( 1)主 函数以及初始化 : void Main(void) sys_init(); /* Initial 44B0Xs Interrupt,Port and UART */ _Link(); /* Print Misc info */ Test_Keyboard(); /*初始化 */ Lcd_Test(); mysnake.life=0; /*活着 */ mysnake.
7、direction=1; /*方向往右 */ mysnake.x0=100;mysnake.y0=100; /*蛇头 坐标 */ mysnake.x1=110;mysnake.y1=100; mysnake.node=2; /*蛇身初始为两节 */ myfood.x=50; /*食物初始坐标 */ myfood.y=150; DrawK(); /*开始画面画围墙生成小蛇 */ GamePlay(); /*玩游戏具体过程 */ ( 2)子程序画围墙: void DrawK(void) Lcd_Draw_Box(10,10,310,230,GREEN); /*画围墙 */ ( 3)游戏过程: vo
8、id GamePlay(void) while(1) if(reset=1) /*设定重启按键 */ Lcd_Test(); mysnake.life=0; /*活着 */ mysnake.direction=1; /*方向往右 */ mysnake.x0=100;mysnake.y0=100; /*蛇头 */ mysnake.x1=110;mysnake.y1=100; mysnake.node=2; myfood.x=50; myfood.y=150; reset=0; flag=0; DrawK(); /*开始画面画围墙生成小蛇 */ while(!flag) /*在没有按键的情况下 ,
9、蛇自己移动身体 */ if(mysnake.life=1) /*以上两种判断以后 ,如果蛇死就跳出内循环,重新开始 */ break; if(myfood.yes=1) /*需要出现新食物 */ myfood.x=randomnumber()%250+10; myfood.y=randomnumber()%180+10; while(myfood.x%10!=0) /*食物随机出现后必须让食物能够在整格内 ,这样才可以让蛇吃到 */ myfood.x+; while(myfood.y%10!=0) myfood.y+; myfood.yes=0; /*画面上有食物了 */ if(myfood.
10、yes=0) /*画面上有食物了就要显示 */ Lcd_Draw_Box(myfood.x,myfood.y,myfood.x+10,myfood.y-10,RED); if(mysnake.node=2) Digit_Led_Test(); for(i=mysnake.node-1;i0;i-) /*蛇的每个环节往前移动 ,也就是贪吃蛇的关键算法 */ mysnake.xi=mysnake.xi-1; mysnake.yi=mysnake.yi-1; /*1,2,3,4 表示右 ,左 ,上 ,下四个方向 ,通过这个判断来移动蛇头 */ switch(mysnake.direction) ca
11、se 1: mysnake.x0+=10;break; case 2: mysnake.x0-=10;break; case 3: mysnake.y0-=10;break; case 4: mysnake.y0+=10;break; /*从蛇的第四节开始 判断是否撞到自己了,因为蛇头为两节,第三节不可能拐过来 */ for(i=3;i300|mysnake.y0220) /*蛇是否撞到墙壁 */ GameOver(); /*本次游戏结束 */ mysnake.life=1; /*蛇死 */ if(mysnake.life=1) /*以上两种判断以后 ,如果蛇死就跳出内循环,重新开始 */ b
12、reak; if(mysnake.x0=myfood.x /消除食物 mysnake.xmysnake.node=-20;mysnake.ymysnake.node=-20; /*新的一节先放在看不见的位置 ,下次循环就取前一节的位置 */ mysnake.node+; /*蛇的身 体长一节 */ myfood.yes=1; /*画面上需要出现新的食物 */ Digit_Led_Test(); /*led 灯显示蛇身节数 */ /*实现贪吃蛇的身体增加 */ Lcd_Draw_Box(mysnake.xmysnake.node-1,mysnake.ymysnake.node-1, mysnak
13、e.xmysnake.node-1+10,mysnake.ymysnake.node-1-10,WHITE); for(i=0;i=L) /*控制蛇身长度上限 */ Congra(); mysnake.life=1; switch(con) /*控制运动方向 */ case 3: /上 if(mysnake.direction!=4)/*判断是否往相反的方向移动 */ mysnake.direction=3; break; case 1: /左 if(mysnake.direction!=2) mysnake.direction=1; break; case 2: /右 if(mysnake.
14、direction!=1) mysnake.direction=2; break; case 4: /下 if(mysnake.direction!=3) mysnake.direction=4; break; ( 4)游戏结束模块: void GameOver(void) Lcd_Clr(); /*清屏 */ Lcd_DspAscII8x16(140,120,GREEN-55,“GAME OVER“);/*显示 */ if (con = 0xf) /*判断是否按下重启键 */ return 0; ( 5)游戏胜利模块: void Congra(void) mysnake.life=1;/*蛇
15、死 */ Lcd_Clr(); /*清屏 */ Lcd_DspAscII8x16(140,120,GREEN-55,“WIN!“);/*显示 */ ( 6)延时程序: int ii,jj; if (ms0;i-) /*蛇的每个环节往前移动 ,也就是贪吃蛇的关键算法 */ mysnake.xi=mysnake.xi-1;/把前一点的坐标给后一点/ mysnake.yi=mysnake.yi-1; /*1,2,3,4 表示右 ,左 ,上 ,下四个方向 ,通过这个判断来移动蛇头 */ switch(mysnake.direction) case 1: mysnake.x0+=10;break; ca
16、se 2: mysnake.x0-=10;break; case 3: mysnake.y0-=10;break; case 4: mysnake.y0+=10;break; 擦除 蛇尾: Lcd_Draw_Box(mysnake.xmysnake.node-1,mysnake.ymysnake.node-1, mysnake.xmysnake.node-1+10,mysnake.ymysnake.node-1-10,WHITE); 增长蛇身: for(i=0;imysnake.node-1;i+) Lcd_Draw_Box(mysnake.xi,mysnake.yi,mysnake.xi+1
17、0,mysnake.yi-10,GREEN); 2、食物的产生: 食物的产生主要还是通过坐标画出一个矩形框,本次实验我的通过一个随机算法来产生一个食物的坐标,来产生食物。 食物的产生主要要注意食物产生之前,我们必须要判断画面上面是已经存在食物,如有已经存在食物了,就不再产生食物,如果食物被蛇吃到了,那就要重新画上食物。本设计是中设置了变量 myfood.yes,在每次循环都 依次 判断myfood.yes 的值,通过 myfood.yes 的值来判断要不要画出食物。 myfood.yes的值为 0 表示 已存在食物 ,为 1 表示 需要画食物 。在蛇吃到食物后 myfood.yes的值要被赋值
18、 1, 画完食物后重新赋值 ,0。另外还要保证食物不能超出蛇的活动界面,并要保证食物能被蛇吃到,所以需要指定食物坐标的范围,被通过舍去食物坐标个位的方法保证食物坐标是整十,这样就能被蛇吃到。本设计用一个矩形方框来代表食物,所以通过上面介绍的方法产生食物坐标后,对应在该坐标的位置画上一个矩形方框。 if(myfood.yes=1) /*需要出现新食物 */ myfood.x=randomnumber()%250+10; myfood.y=randomnumber()%180+10; while(myfood.x%10!=0) /*食物随机出现后必须让食物能够在整格内 ,这样才可以让蛇吃到 */
19、myfood.x+; while(myfood.y%10!=0) myfood.y+; myfood.yes=0; /*画面上有食物了 */ if(myfood.yes=0) /*画面上有食物了就要显示 */ Lcd_Draw_Box(myfood.x,myfood.y,myfood.x+10,myfood.y-10,RED); 3、判断蛇是否吃到食物: 判断蛇是否吃到食物的方法比较简单,只要判断蛇头的 X、 Y 坐标是否同时和食物的坐标的 X、 Y 一样 。吃到食物后改变响应的游戏参数,并要让蛇的节数多一节,这时候要让变量 mysnake.node 加 1, 并且还要对蛇补画上一节,本设计采用补上蛇头的方法,要注意根据此时蛇的运动方向来确定新蛇头的坐标。另