/** * 蛇的一節身體 * @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 數據結構