/** * 蛇的一节身体 * @author jiladeyouxiang@qq.com * */ class Body{ /** 蛇的身体的绘制的横坐标 */ private int x; /** 蛇的身体的绘制的纵坐标 */ private int y; /** * 构造一个蛇的身体节点 * @param x 绘制的横坐标 * @param y 绘制的纵坐标 */ public Body(int x, int y){ this.x = x; this.y = y; } /** * 绘制一个蛇身体的一个节点 * @param g */ public void drawMe(Graphics g){ //得到画笔原来的颜色 Color c = g.getColor(); //给画笔设置新的颜色 g.setColor(Color.BLUE); //根据当前蛇的身体节点的起始横纵坐标绘制该节点 g.fill3DRect(x, y, BODY_SIZE, BODY_SIZE, true); //将画笔的颜色复原 g.setColor(c); } }至于为何要采用内部类的形式呢,这里孤狼简单的说明一下。Java中,类的引用有3种方式,分别是外部类,内部类和匿名类的方式,对于那种不少文件中都要用到的类,咱们通常采用外部类的方式(即新建一个类的方式来实现);对于那种只须要在本类中使用的类来讲,就像在本例子中,蛇的身体只有蛇会引用到,其余类不须要创建对其的引用,这时候咱们适合使用内部类,而且内部类有一个好处就是能够直接引用本身外面的类的属性和方法;至于匿名类呢就是咱们有时候不太关心类的具体信息,而更专一于给类的某些方法或者参数进行设置时,咱们会采用匿名类的方式,最典型的例子就是咱们给监听器实现咱们本身的方法。
接下来,咱们来想一下咱们的蛇应该用什么数据结构来设计。这个问题就要想到咱们游戏的具体的玩法,要完成贪吃蛇游戏,最关键的问题就是处理蛇移动的问题。那么咱们怎么用代码来模拟蛇的移动呢?请看下面的一张图:
上面的呢是咱们蛇初始的位置,下面的蛇是移动后的位置。第一种想法呢是咱们最容易想到的,就是把咱们的蛇的全部节点都向右挪动一个步长,可是这种方法咱们以为不是最好的方法。因而咱们有了第二种方法,蛇向前移动一步能够当作是咱们先去掉蛇的尾巴,再在新的位置添加上一个新的蛇头(即咱们先删除1号节点,而后再在4号位置添加上新的蛇头),这样呢咱们就完成了蛇的一次移动。
决定了蛇的运动算法以后,也就决定了咱们描述蛇的数据结构,LinkedList就是不二的选择。这都源于LinkedList的特性,LinkedList给咱们提供了addFirst(),removeFirst(),addLast(),removeLast()这四个正好符合咱们需求的方法。有了这些铺垫,咱们就能够来看代码了: java
package com.gulang.snake.entity; import java.awt.Color; import java.awt.Graphics; import java.util.LinkedList; import com.gulang.snake.view.GameView; /** * 蛇的对象 * @author jiladeyouxiang@qq.com * */ public class Snake { /** 蛇的一节身体的大小 */ public static final int BODY_SIZE = 30; /** 蛇前进的步长,即移动一次前进的距离 */ public static final int STEP = BODY_SIZE; /** 蛇前进的方向,向上 */ public static final int DIR_UP = 0; /** 蛇前进的方向,向下 */ public static final int DIR_DOWN = 1; /** 蛇前进的方向,向左 */ public static final int DIR_LEFT = 2; /** 蛇前进的方向,想右 */ public static final int DIR_RIGHT = 3; /** 蛇当前前进的方向 */ private int direction; /** 蛇的身体 */ private LinkedList<Body> snakeBody = new LinkedList<Body>(); /** * 初始化一条蛇 */ public Snake(){ //初始化蛇最开始前进的方向为向右 direction = DIR_RIGHT; //咱们将蛇的第一节身体初始化在游戏窗口的中央 int startX = (GameView.WINDOW_WIDTH - BODY_SIZE) / 2; int startY = (GameView.WINDOW_HEIGHT - BODY_SIZE) / 2; //初始化蛇的身体,即向body链表中添加数据,咱们初始化蛇的初始节点为3个 for(int i = 0; i < 3; i++){ //逐个的计算出蛇的每个节点的位置 Body body = new Body(startX - i * BODY_SIZE, startY); snakeBody.add(body); } } /** * 将蛇绘制在游戏的窗口上 * @param g */ public void drawMe(Graphics g){ for(int i = 0; i < snakeBody.size(); i++){ snakeBody.get(i).drawMe(g); } } /** * 蛇的一节身体 * @author jiladeyouxiang@qq.com * */ class Body{ /** 蛇的身体的绘制的横坐标 */ private int x; /** 蛇的身体的绘制的纵坐标 */ private int y; /** * 构造一个蛇的身体节点 * @param x 绘制的横坐标 * @param y 绘制的纵坐标 */ public Body(int x, int y){ this.x = x; this.y = y; } /** * 绘制一个蛇身体的一个节点 * @param g */ public void drawMe(Graphics g){ //得到画笔原来的颜色 Color c = g.getColor(); //给画笔设置新的颜色 g.setColor(Color.BLUE); //根据当前蛇的身体节点的起始横纵坐标绘制该节点 g.fill3DRect(x, y, BODY_SIZE, BODY_SIZE, true); //将画笔的颜色复原 g.setColor(c); } } }理解了Snake类之中的内容后,咱们再修改一下GameView中的paint()方法以后,咱们就能够看到咱们项目的运行效果了,依旧,直接看代码:
/** * 绘制界面的方法 */ @Override public void paint(Graphics g) { //绘制蛇的对象 snake.drawMe(g); }固然,在调用以前,不要忘了在GameView的构造方法中初始化snake对象,咱们从新写了一个initGameData()的方法来初始化和游戏数据相关的内容。代码以下:
/** * 初始化和游戏相关的数据 */ private void initGameData() { //构造蛇的对象 snake = new Snake(); }至此,咱们就看到了咱们的Snake了,见下图:
是否是感受有点像样了?不过如今咱们的蛇还不会动,在下一篇博文中,咱们将让咱们的蛇动起来。那么今天就到这吧,下次再见啦。 算法
我把代码都放在迅雷快传上了,你们奔走相告吧,这里给出连接,一篇博文对应一个项目文件,你们直接导入工程就能够运行:
http://kuai.xunlei.com/d/nNdkCUf1HBXTUAQA44e 数据结构