1、贪吃蛇游戏背景:蛇引诱夏娃吃了苹果之后,就被贬为毒虫,阴险的象征。 而蛇吃东西是整只动物吞进去的,大概在文艺复兴的时候(好象是那个时候但是不确定)就有人发明的一种游戏,是现在贪吃蛇的前身。后来慢慢的发展就变成了今天的贪吃蛇了、现在贪吃蛇主要应用于手机游戏。本文运用软件工程思想、JAVA面向对象编程、类的封装、抽象类的使用(接口),游戏编码规范遵循MVC模式,循序渐进实现贪吃蛇的相关功能。一 :游戏中的面向对象分析与设计 涉及到几个对象(类) 每个类有什么方法1 . 首先得有个游戏显示面板(GamePanel)类该类有一个方法void display(); /用来显示游戏面板2 . 得有个蛇(S
2、nake)类该类有以下几个方法:void move(); /移动(走一步)void changeDirection(); /改变方向void eatFood(); /吃食物(身体变长)voolean is EatBody();/蛇是否吃到了自己的身体void drawMe();/显示3 . 一个食物类(Food)类该类有以下方法:boolean is SnakeEatFood(Snake); /判断蛇是否吃到了食物4 . 一个背景石头(Ground)类该类有以下方法:Boolean isSnakeEatRock(Snake); /蛇是否吃到了石头此时类之间的关系如下图所示:图1各个类之间的关系
3、二 :编写贪吃蛇游戏中的各个类的主体框架性代码本有序遵循MVC(Model-View-Controller)所以首先建立以上几个实体类并定义相应的包名:liang.snake.entities包下定义Food、Ground、Snake 三个类,再在liang.snake.view包下定义GamePanel类,再在,按照以上说明的各个类具有的方法,写上如下代码:package liang.snake.entities;publicclass Food publicboolean isSnakeEatFood(Snake snake) System.out.println(Snakes eat f
4、ood);returnfalse;publicvoid drawme()System.out.println(Foods drawme publicclass Ground publicboolean isSnakeEatRock()Groundpublicclass Snake publicvoid move()s movepublicvoid changeDirection(int direction)s changeDirectionpublicvoid eatFood()publicboolean isEatBody()s eat bodypublicvoid drawMe()s dr
5、awMepackage liang.snake.view;import java.awt.Graphics;import javax.swing.JPanel;import liang.snake.entities.Food;import liang.snake.entities.Ground;import liang.snake.entities.Snake;publicclass GamePanelextends JPanelprivate Snake snake;private Ground ground;private Food food;publicvoid paintCompone
6、nt(Graphics g) snake.drawMe();ground.drawme();food.drawme();publicvoid display(Snake snake,Ground ground,Food food)this.snake=snake;this.ground=ground;this.food=food;GamePanels displaythis.repaint();三 : 编写Controler类与实现蛇移动的事件监听 由于蛇不能直接操作显示面板(GamePanel)所以这里定义一个监听器SnakeListener:里面定义一个方法:void snakeMove(
7、Snake); 每当蛇移动一步就触发监听器,调用snakeMoved()由Controller去实现监听器的接口,然后由控制器去触发显示面板的事件源,让显示面板完成相应操作。逻辑图如下:图2事件监听建立联系在Snake 中增加蛇的方向常量:publicstaticfinalintUP=1;publicstaticfinalintDOWN=-1;publicstaticfinalintLEFT=2;publicstaticfinalintRIGHT=-2;并添加一个接口:package liang.snake.Listener;publicinterface SnakeListener publ
8、icvoid SnakeMove(Snake snake);Controler 实现SnakeListener接口并处理案件消息:代码如下:package liang.snake.Controller;import java.awt.event.KeyAdapter;import java.awt.event.KeyEvent;import liang.snake.Listener.SnakeListener;import liang.snake.view.GamePanel;publicclass Controller extends KeyAdapter implements SnakeL
9、istenerSnake snake=new Snake();Ground ground=new Ground(); Food food=new Food(); GamePanel gamepanel=new GamePanel();public Controller(Snake snake, Ground ground, Food food, GamePanel gamepanel) this.snake = snake;this.ground = ground;this.food = food;this.gamepanel = gamepanel;publicvoid keyRelease
10、d(KeyEvent e) switch(e.getKeyCode()case KeyEvent.VK_UP :snake.changeDirection(Snake.UP);break;case KeyEvent.VK_DOWN :snake.changeDirection(Snake.DOWN);case KeyEvent.VK_LEFT :snake.changeDirection(Snake.LEFT);case KeyEvent.VK_RIGHT :snake.changeDirection(Snake.RIGHT);publicvoid newgame()snake.start()
11、;publicvoid SnakeMove(Snake snake) gamepanel.display(snake,ground,food);开发到此时,Snake中应该增加监听器,并另启动一个线程来不断调用蛇的move();在Snake中提供一个启动线程的方法,在Snake中增加如下代码:private Set listener=newHashSet(); publicvoid addSnakeListener(SnakeListener l)if(l!=null)this.listener.add(l);publicvoid start()new Thread(new SnakeDriv
12、er().run();并在Run方法中增加for(SnakeListener l: listener)l.SnakeMove(Snake.this);tryThread.sleep(1000); catch (InterruptedException e) e.printStackTrace();四 :编写对各个类进行测试的程序代码构建一个新类Game来测试程序代码:package liang.snake.Game;import java.applet.AudioClip;import java.awt.BorderLayout;import java.io.File;import .Malf
13、ormedURLException;import .URL;import javax.swing.JFrame;import liang.snake.Controller.Controller;publicclass Game publicstaticvoid main(String args) JFrame jf=new JFrame(我的论文 Ground ground=new Ground(); Controller controller=new Controller(snake, ground, food, gamepanel); jf.setDefaultCloseOperation
14、(JFrame.EXIT_ON_CLOSE); jf.setLocation(400, 0); jf.setSize(800, 600); jf.add(gamepanel); jf.addKeyListener(controller); snake.addSnakeListener(controller); jf.setVisible(true); controller.newgame();运行这个带有main()的类,在Eclipse 的Console窗口中可以看到如下信息:s moves displays drawMes drawme这就意味着,当蛇移动一次,就触发监听器,有控制器(co
15、ntroller)给GamePanel发送指令,让它重画,GamePanel中的publicvoid display(Snake snake,Ground ground, Food food)这个方法依次画出几个实体,所以打印出上述信息。到了这一步我们的基本框架打好了,下面开始第5步五 : 蛇的数据结构设计与移动显示 分析:要区分蛇头和蛇尾巴,这就要求这个数据结构是有序的,还要经常访问第一个和最后一个节点,所以LinkedList最合适,因为它有getFirst(),getLast()方法和removeLast()方法蛇下一步移动到哪是由方向控制的,前面已经定义过,蛇透坐标如下图:图3蛇头方向
16、计算新蛇头坐标在Snake的 move()中增加body.removeLast();int x=body.getFirst().x;int y=body.getFirst().y;switch(direction)caseUP: y-;caseDOWN: y+;caseLEFT: x-;caseRIGHT: x+; Point newhead=new Point(x,y);/加头body.addFirst(newhead);并定义 privateintdirection;为了能更方便的维护游戏,这里定义Global类来定义常量如下:package liang.snake.Global;publ
17、icclass Global publicstaticfinalintCELL_SIZE=20;publicstaticintHIGHT=30;publicstaticintWIDTH=30;并修改游戏中窗口大小为:jf.setSize(Global.CELL_SIZE*Global.WIDTH,Global.CELL_SIZE*Global.HIGHT);再加上如下代码,对蛇初始化:public Snake()init();publicvoid init()int x=Global.WIDTH/2;int y=Global.HIGHT/2;int nodenum=3;for(int i=0;
18、inodenum;i+)body.addFirst(new Point(x+,y);this.direction=RIGHT;在蛇的drawMe(Graphics g)中些上如下让蛇显示的代码:这里的画图采用填充3D矩形来实现:for(Point p:body) g.fill3DRect(p.x*Global.CELL_SIZE, p.y*Global.CELL_SIZE, Global.CELL_SIZE, Global.CELL_SIZE, true);画图的规则如下图:图4计算格子坐标和像素坐标此时运行Game类就可以看到蛇显示在面板中了,如图:图5显示面板显示的蛇但是蛇越走越长,是因为
19、没有擦除以前的图像,在GamePanel的paintComponent(Graphics g)中添加如下代码:g.setColor(new Color(0xcfcfcf);g.fill3DRect(0, 0,Global.CELL_SIZE*Global.WIDTH , Global.CELL_SIZE*Global.HIGHT, true);此时蛇就可以正常移动了如图:图6移动中的蛇通过按键改变移动方向,此时的蛇身体节点显示为白色,我们再在蛇的绘制方法中位器指定颜色:代码如下:图7指定颜色后的蛇六 : 试与修正蛇的移动与显示问题 此时的蛇当移动到窗口边界的时候就能走出窗口还有蛇可以穿过自己的
20、身体,这些游戏规则中式不允许的, 下面来修正这些问题,修改Snake中的move()方法如下:首先定义publicintolddirection,newdirection;防止蛇穿过自己身体:/去尾if(olddirection+newdirection!=0)olddirection=newdirection;switch(olddirection)if(y=Global.HIGHT) y=0;if(x=Global.WIDTH)x=0 ;newdirection=direction;并修改蛇的初始化方法如下:olddirection=newdirection=RIGHT;此时就修正了上面的
21、问题,可以运行Game类来测试下七 : 编写与测试表示食物的类并实现吃食物首先在Snake类中添加public Point getHead()returnbody.getFirst();用来获取头结点,然后再Food类中写上如下代码:importjava.awt.Color;import java.awt.Point;import liang.snake.Global.Global;publicclassFoodextends Pointpublicvoid newfood(Point p)this.setLocation(p);returnthis.equals(snake.getHead();publicvoid drawme(Graphics g)g.fill3DRect(this.x*Global.CELL_SIZE,this.y*Global.CELL_SIZE, Global.CELL_SIZE, Global.CELL_SIZE, true);此时就可以画出食物并判断蛇是否吃到了食物,接下来就可以在Controller中处理吃食物的代码,吃了食物我们只要把先前移动去除的尾巴再给加上就实现了蛇吃食物身体变长的效果了,如下:定义Point oldTail;在蛇move()中保存去除的尾巴:oldTail= body.removeLast();在Controller
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1