01贪吃蛇课程设计报告.docx
- 文档编号:30331300
- 上传时间:2023-08-13
- 格式:DOCX
- 页数:18
- 大小:21.61KB
01贪吃蛇课程设计报告.docx
《01贪吃蛇课程设计报告.docx》由会员分享,可在线阅读,更多相关《01贪吃蛇课程设计报告.docx(18页珍藏版)》请在冰豆网上搜索。
01贪吃蛇课程设计报告
贪吃蛇课程设计报告
一.详细设计2
1.属性解释2
2.初始化坐标:
2
3.调用线程2
4.具体功能实现:
3
4.1.移动功能的实现:
3
4.2.吃食物功能实现:
4
4.3.判断游戏是否结束的功能实现:
6
4.4.画图方法的实现7
4.5.监听键盘动作:
8
5.界面的设计:
9
5.1进入程序界面设计9
5.2第2个界面的设计:
10
5.3第3个界面设计:
10
二.字符设备驱动程序实现11
三.总结:
12
一.详细设计
1.属性解释
用1个2维数组snake[200][2]存放蛇身坐标,第2维是0的时候代表横坐标,为1的时候为纵坐标。
第1维数字代表蛇身方块的数字,例如snake[0][0]就代表蛇头的横坐标snake[1][1]就代表第2个方块的总坐标。
snakeNum为蛇的长度(以方格为单位)。
SNAKEWIDTH为方格大小。
direction;为移动方向,zhangai0x,zhangai1x,zhangai2x,zhangai3x,zhangai0y,zhangai1y,
zhangai2y,zhangai3y,为障碍物的坐标。
foodx,foody为食物的坐标。
isPaused为判定是否是暂停状态,true为暂停false为非暂停。
A为难度系数,a可以为1,2,3。
1的时候最难,3的时候最简单。
SLEEP_TIME为系统沉睡时间,其值越小速度越快。
2.初始化坐标:
isPaused=true;//设置游戏开始为暂停状态
snakeNum=7;//设置蛇身长度7个方格
//循环依次初始化蛇身没个方格的坐标,蛇头的坐标为(100,40)
for(inti=0;i { snake[i][0]=100-SNAKEWIDTH*i; snake[i][1]=40; } //初始化移动方向为向右 direction=DIRECTION_RIGHT; //初始化食物坐标 foodX=100; foodY=100; //初始化障碍物的坐标,其位置环绕挡住食物, zhangai0x=foodX+4*a; zhangai0y=foodY+4*a; zhangai1x=foodX+4*a; zhangai1y=foodY-4*a; zhangai2x=foodX-4*a; zhangai2y=foodY+4*a; zhangai3x=foodX-4*a; zhangai3y=foodY-4*a; 3.调用线程 thread=newThread(this); thread.start(); while(isRun)//开始时间 { if(! isPaused) { eatFood();//吃食物 move(direction);//移动 if(gameover)//如果游戏结束 { isRun=false; restart(); break; } b=! b;//闪烁控制 } repaint();//重新画图 Thread.sleep(SLEEP_TIME); } 开始创建并执行线程,如果没有暂停就执行eatFood();move(direction);然后判断游戏是否结束,然后重新画图repaint();然后等待SLEEP_TIME时间继续循环。 4.具体功能实现: 4.1.移动功能的实现: privatevoidmove(intdirection) { //除蛇头外的蛇身坐标移动 for(inti=snakeNum-1;i>0;i--) { snake[i][0]=snake[i-1][0]; snake[i][1]=snake[i-1][1]; } //蛇头坐标的移动 switch(direction) { caseDIRECTION_UP: snake[0][1]=snake[0][1]-SNAKEWIDTH; break; caseDIRECTION_DOWN: snake[0][1]=snake[0][1]+SNAKEWIDTH; break; caseDIRECTION_LEFT: snake[0][0]=snake[0][0]-SNAKEWIDTH; break; caseDIRECTION_RIGHT: snake[0][0]=snake[0][0]+SNAKEWIDTH; break; } } 坐标移动的总体思想: 1.蛇身的移动: 移动的时候,后面的方格要到前面方格的位置,也就是要让后面的方格的坐标变成前面方格的坐标。 即把前面方格的坐标赋值给后面的方格坐标。 就是让最后方格的坐标变成倒数第2个方格的坐标,倒数第2个方格坐标变成倒数第3个方格坐标,依次类推直到第2个方格变成第1个方格的坐标。 这样我们循环都最后还没有第1个方格的坐标,所以我们另将蛇头的坐标赋值。 2.蛇头的移动: 这和蛇当前移动的方向有关,以向上移动为例,那蛇头的坐标应该横坐标不变,纵坐标减去方格的长度,因为在屏幕上左上点为(0,0)越往左横坐标越大,越往下纵坐标越大。 所以向上移动纵坐标要减小。 其他方向的坐标运算如上述代码,也不难解释。 注意: 关于蛇身移动的循环for(inti=snakeNum-1;i>0;i--)他是先给后面的值赋值最后循环到正数第2个方格。 开始我想反过来,从第2个开始赋值再循环都最后,实验的时候却和以前的方式运行结果不一样。 移动的时候蛇不管有多长就只能看到2个方格在移动。 后来发现,我这样改是不对的,按照我的思路a[1][0]=a[0][0];a[2][0]=a[1][0];…….仔细看后就发现我把a[0][0]的值赋给a[1][0]又把a[1][0]的值赋给a[2][0],我样有值的覆盖,也就是我让蛇身的所有方格的值全是a[0][0]的,再家上蛇头移动后蛇头的新坐标,屏幕上就只有2个方格了。 4.2.吃食物功能实现: privatevoideatFood(){ //判别蛇头是否和食物重叠 if(snake[0][0]==foodX&&snake[0][1]==foodY){ snakeNum++; generateFood(); } } /** *产生食物 *说明: 食物的坐标必须位于屏幕内,且不能和蛇身重合 */ privatevoidgenerateFood() { while(true) { foodX=Math.abs(random.nextInt()%(width-SNAKEWIDTH+1)) /SNAKEWIDTH*SNAKEWIDTH; foodY=Math.abs(random.nextInt()%(height-SNAKEWIDTH+1)) /SNAKEWIDTH*SNAKEWIDTH; zhangai0x=foodX+4*a; zhangai0y=foodY+4*a; zhangai1x=foodX+4*a; zhangai1y=foodY-4*a; zhangai2x=foodX-4*a; zhangai2y=foodY+4*a; zhangai3x=foodX-4*a; zhangai3y=foodY-4*a; booleanb=true; for(inti=0;i { if(foodX==snake[i][0]&&snake[i][1]==foodY) { b=false; break; } } if(b) { break; } } } 该功能的总体思路: 如果蛇头的坐标和食物的坐标一样,也就是吃到了食物,蛇的长度+1并且产生新的食物。 生成食物的方法: 随机生成新的坐标赋值给食物坐标。 并要保证随机生成的坐标在屏幕内而且随机生成的食物坐标不能和蛇身重合。 生成新的食物后,在食物周围生成新的障碍物坐标。 随机产生食物坐标的方法: foodX=Math.abs(random.nextInt()%(width-SNAKEWIDTH+1)) /SNAKEWIDTH*SNAKEWIDTH; 说来惭愧直到现在我还是不明白为什么经过这样的运算后得到的坐标就一定在屏幕内。 但我至少知道这样的运算可以得到必在屏幕内的坐标。 4.3.判断游戏是否结束的功能实现: publicbooleanisGameOver(){ //边界判别 if(snake[0][0]<0||snake[0][0]>(width-SNAKEWIDTH)|| snake[0][1]<0||snake[0][1]>(height-SNAKEWIDTH)){ returntrue; } //碰到自身 for(inti=4;i { if(snake[0][0]==snake[i][0] &&snake[0][1]==snake[i][1]) { returntrue; } } //碰到障碍 if(snake[0][0]==zhangai0x&&snake[0][1]==zhangai0y) { returntrue; } if(snake[0][0]==zhangai1x&&snake[0][1]==zhangai1y) { returntrue; } if(snake[0][0]==zhangai2x&&snake[0][1]==zhangai2y) { returntrue; } if(snake[0][0]==zhangai3x&&snake[0][1]==zhangai3y) { returntrue; } returnfalse; } 该功能的思路也简单: 蛇撞到屏幕边缘游戏结束,蛇碰到自身游戏也要结束,蛇碰到障碍还是要结束游戏。 在判断边界的时候为什么是snake[0][0]>(width-SNAKEWIDTH)呢? 因为其坐标是方格左上顶点的坐标,当蛇头的左上顶点与屏幕右面相隔方格边长的时候,其实蛇头已经碰到屏幕的右边。 4.4.画图方法的实现 protectedvoidpaint(Graphicsg){ //清屏 g.setColor(0xffffff);//画笔设置成白色 g.fillRect(0,0,width,height);//把整个屏幕都绘制成白色 g.setColor(0);//把画笔再设置成黑色 //绘制蛇身 for(inti=0;i g.fillRect(snake[i][0],snake[i][1],SNAKEWIDTH,SNAKEWIDTH); } g.fillRect(zhangai0x,zhangai0y,SNAKEWIDTH,SNAKEWIDTH); g.fillRect(zhangai1x,zhangai1y,SNAKEWIDTH,SNAKEWIDTH); g.fillRect(zhangai2x,zhangai2y,SNAKEWIDTH,SNAKEWIDTH); g.fillRect(zhangai3x,zhangai3y,SNAKEWIDTH,SNAKEWIDTH); //绘制食物 if(b){ g.fillRect(foodX,foodY,SNAKEWIDTH,SNAKEWIDTH); } if(isGameOver()) { g.drawString("GameOver",60,60,Graphics.TOP|Graphics.LEFT); } } 总体思路: 首先清空屏幕内的内容,然后画出当前的蛇,食物,障碍物,因为该方法是在线程中被循环调用的。 每隔SLEEP_TIME就被执行1次,在循环中以为其他方法的调用,蛇,食物,障碍物的坐标是在变化的,这样在不停的绘画新坐标的过程中,就形成了动画效果。 1.清空屏幕内容的方法: 因为我们想画的蛇的颜色是黑色,我们先把画笔设置成白色,然后把整个屏幕都绘制成白色,因为没画东西的时候屏幕也是百的,这样我们看到屏幕中就什么也没有了。 然后我们再把画笔设置成黑色,画将要画的内容。 2.绘制方格的方法: 利用fillRect(a,b,c,d)方法进行绘制。 a,b为方格的左上顶点坐标,c为以(a,b)为顶点的长度,d为高度,画完的结果就是以(a,b)为左上顶点,c为长度d为高度的矩形被画笔添满颜色,因为我们设置的画笔颜色为黑色,所以我们看到的是全黑的方格。 3.在屏幕中显示字体的方法: drawString("GameOver",60,60,Graphics.TOP|Graphics.LEFT)第1个参数为要写字的内容,第2,3个参数是显示的坐标位置,第4个参数是用来确定原点,这我也是从网上查到的。 在Graphics类里publicstaticfinalintLEFT=4;publicstaticfinalintTOP=16;还有其他类似的值都是2的N次方。 这样做的目的就在于,当两个或多个锚点定位方式通过位与的方法计算后,根据这个计算得到的和可以还原回参与位与计算的各个数值,从而得到有几种锚点定位方式,然后J2ME根据还原回的值来设置锚点的位置。 4.食物闪现: 在绘画食物的时候 if(b) { g.fillRect(foodX,foodY,SNAKEWIDTH,SNAKEWIDTH); } 只有b是真值的时候才画方格,也就是b是假值的时候是不画的。 这样做是因为在线程中每循环1次就执行1次b=! b;这样b的值在真与假之间来回变化,食物也在屏幕中出现,不出现,出现,不出现,这样就形成了食物闪烁的效果。 与障碍形成对比,使用户看的更方便。 4.5.监听键盘动作: publicvoidkeyPressed(intkeyCode){ intaction=this.getGameAction(keyCode); //改变方向 switch(action){ caseUP: if(direction! =DIRECTION_DOWN){ direction=DIRECTION_UP; } break; caseDOWN: if(direction! =DIRECTION_UP){ direction=DIRECTION_DOWN; } break; caseLEFT: if(direction! =DIRECTION_RIGHT){ direction=DIRECTION_LEFT; } break; caseRIGHT: if(direction! =DIRECTION_LEFT){ direction=DIRECTION_RIGHT; } break; caseFIRE: //暂停和继续 isPaused=! isPaused; break; } } 用getGameAction(keyCode)方法获取当前对键盘的操作,以上为例 caseUP: if(direction! =DIRECTION_DOWN) { direction=DIRECTION_UP; } break; 首先想要蛇移动的方向变成上,要判断当前蛇的移动方向是否是向下,因为当蛇是向下移动的时候,不能让蛇变成向下移动,所以要想蛇想上移动,要先判断蛇当前移动的方向不是向下。 5.界面的设计: 5.1进入程序界面设计 执行程序首先进入的界面进入游戏和退出游戏的选择。 如果进入进入第2个界面,如果退出就退出程序。 privateTextBoxtextbox;//定义匡 privateCommandenter;//定义按狃 privateCommandexit; enter=newCommand("Enter",Command.OK,1);//设置按狃信息 exit=newCommand("Exit",Command.OK,1); textbox=newTextBox("SnakeGame","",40,0);//设置文本匡 textbox.addCommand(enter);//添加按钮到匡里 textbox.addCommand(exit); textbox.setCommandListener(this);//监听 publicvoidcommandAction(Commandarg0,Displayablearg1) { if(arg0==enter) { display.setCurrent(textbox2); } if(arg0==exit) { destroyApp(false); notifyDestroyed(); } } 5.2第2个界面的设计: 选择难度(简单,普通,高难)然后进入相应的难度游戏 TextBoxtextbox2; Commandjiandan; Commandputong; Commandgaonan; jiandan=newCommand("jiandan",Command.OK,1); putong=newCommand("putong",Command.OK,1); gaonan=newCommand("gaonan",Command.OK,1); textbox2=newTextBox("nanduxuanze","",40,0); textbox2.addCommand(jiandan); textbox2.addCommand(putong); textbox2.addCommand(gaonan); textbox2.addCommand(exit); textbox2.setCommandListener(this); if(arg0==gaonan) { displayable.setA (1); display.setCurrent(displayable); } if(arg0==putong) { displayable.setA (2); display.setCurrent(displayable); } if(arg0==jiandan) { displayable.setA(3); display.setCurrent(displayable); } 5.3第3个界面设计: 在游戏中可以修改游戏难度,游戏结束的时候可以重新游戏,可以随时推出游戏。 privateCommandrestart; restart=newCommand("Restart",Command.OK,1); displayable.addCommand(gaonan);//displayable是执行游戏类的对象 displayable.addCommand(putong); displayable.addCommand(jiandan); displayable.addCommand(restart); displayable.addCommand(exit2); displayable.setCommandListener(this); //想要重新游戏,就想设置当前游戏结束,重新初始化数据即restart()方法,然后在开始游戏 if(arg0==restart) { displayable.setGameOver(); displayable.restart(); display.setCurrent(displayable); } 其中display=Display.getDisplay(this);然后对display对象使用display对象是获取当前Display的信息,我们可以理解成display对象现在盛放的是1个像框 SnakeCanvasdisplayable=newSnakeCanvas();SnakeCanvas类中是相关于游戏本身的程序 Displayable对象现在可以理解成盛放的是相片内容 display.setCurrent(displayable); 这样我们就可以理解成把相片里的内容放进像框里。 二.字符设备驱动程序实现 实验题目: 字符设备驱动程序 实验目的: 实现嵌入式Linux系统下的字符设备驱动程序,要求动态生成设备号,并在测试程序中,通过超级终端分行显示数0-39,可参考demo驱动程序实验过程。 上述过程需在板子端进行,执行动态加载驱动,并通过超级终端监视测试程序运行结果。 实验过程: 1.打开虚拟机,新建终端,找到demo文件 Up-techpxa270--exp---drives---01….--找到demo文件 2.输入以下命令videmo.cvidemotest.c,可以查看目录,修改输入数字的个数和方式,里面有个错误,就是主设备号那没有返回值,需要修改。 修改方法只需要把上面那的返回代码,一样的写1遍。 3.输入命令make生成.o文件。 4.连接好扳子,打开超级终端。 5.挂载虚拟机那边的up-techpxa270文件,我机器虚拟机IP为192.168.0.123 挂载到mnt目录下。 具体命令: mount–onolock192.168.0.123: /up-techpxa270//mnt 6.mnt--exp---drives---01….--找到demo.o文件 1.创建目录mkdir/dev/demo 2.创建节点mknod/dev/democ2540 3.加载驱动insmoddemo.ko 4.执行程序./demotest 即可完成实验要求,显示出0到39的数字。 三.总结: 我想要写出好的程序,需要我们有扎实的基础,这样遇到一些基本算法的时候可能就会游刃有余了。 在编程是我们要有丰富的想象力。 不要拘泥于固定的思维方式,遇到问题的时候要多想几种解决问题的方案,试试别人从没想过的方法。 丰富的想象力是建立在丰富的知识的基础上,所以我们要通过多的途径来帮助自己建立较丰富的知识结构。 在编程是我们碰到了很多的困难,这就需要我们多与别人交流。 三人行必有我师,也许在一次和别人不经意的谈话中,就可以迸出灵感的火花。 在编程的过程中我们也看到了有良好的编程风格是十分重要的,至少在时间效率上就体现了这一点。 养成良好的习惯,代码的缩进编排,变量的命名规则要始终
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 01 贪吃 课程设计 报告