貪吃蛇的java代碼分析(二)


  1. 代碼剖析

貪吃蛇是一款十分經典的小游戲,對初入coding的朋友來說,拿貪吃蛇這樣一個案例來練手十分合適,並不高的難度和成功后的成就感都是學習所必須的。下面我將依照我當時的思路,來逐步分析實現的整個過程。

讓我們逐一分析。首先,整個游戲最基本的元素是地圖。在java中用於繪圖的類是swing和awt,在這里主要用到swing類。swing中用於窗口顯示的類有JFrame及其子類。JFrame可以直接添加組件,但其本質是將組件添加到JFrame中的一個默認面板里,為了代碼清晰,我會使用JPanel面板來繪制全部的動畫,之后再將面板添加到JFrame窗體之中即可。

我們可能會疑惑於貪吃蛇的蛇身,它是由什么組成的?如何實現移動?我們可以把貪吃蛇的蛇身理解成一個集合,它有固定的起始元素,代表游戲一開始時的蛇身。當貪吃蛇吃到點時,集合就添加一個元素,蛇的長度就加一。那么,集合中的元素是什么呢?要理解這個問題,首先得關注蛇身移動所處的環境。在JFrame窗體中,是由X、Y軸坐標對位置進行區分。貪吃蛇的蛇身可以看做是一個一個聯系緊密的點,在坐標軸上顯示出來。每當朝某個方向移動時,蛇的坐標就按照某個規律變化。例如,我們操控貪吃蛇向上移動時,蛇的全體坐標的Y軸就減一;如果蛇的第一個坐標與蛇身的某個坐標重合,就代表貪吃蛇碰到自己;如果蛇的第一個坐標碰到了邊界,蛇就撞牆。這就是貪吃蛇的本質。 
我們來建立建立蛇身上每一個點的對象,蛇身就是由一個一個這樣的對象所組成的:

public class snakeNode { private int x; private int y; private String color; public snakeNode() {}; public snakeNode(int x, int y, String color) { this.x = x; this.y = y; this.color = color; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int Y) { this.y = y; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } 這串代碼表示蛇身上的每一個點,通過建立snakeNode的對象,指定不同的X軸和Y軸的值,就能組成一個蛇身。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

接下來我們要給每一個蛇身上的點設置范圍,因為貪吃蛇有移動范圍的限制,超過某個距離或者長度,就會越界導致游戲的終止。經過考慮,我們將范圍設置在:

public class mainMap extends JPanel { private int width = 20; private int length = 30; private int unit = 20; } 上面的代碼定義了一個面板類,我們之后的操作都要在上面進行。類中定義了變量width和length。我們將蛇身的移動范圍限制在X軸上0~20,Y軸上0~30,至於變量unit,稍后再進行分析。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

接着,我們需要一個集合,用來存儲蛇身上的各個點。我們需要定義一個變量,用來表示隨機出現的點(貪吃蛇的目標),並且定義一個變量Length用來表示蛇的長度。代碼如下:

public class mainMap extends JPanel { private final int width = 20; private final int length = 30; private final int unit = 20; private ArrayList<snakeNode> snake = new ArrayList<>(); private snakeNode newNode = new snakeNode(0,0,Color.WHITE); private int Length; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

定義類的成員變量之后,我們開始定義構造方法,這樣在構造mainMap的對象后程序就會開始運行。我們需要在構造方法中給集合添加一些元素,代表初始蛇身,也需要使用一個方法,用來創造隨機點。代碼如下:

public mainMap() {
    snake.add(new snakeNode(width/2,length/2,Color.RED); snake.add(new snakeNode(width/2,length/2+1,Color.BLUE); snake.add(new snakeNode(width/2,length/2+2,Color.GREY); Length = snake.size(); createNode(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

createNode是創造隨機點的方法,讓我們思考一下:創造隨機點有哪些要求?首先,隨機點的范圍肯定不能超出限制,否則游戲將無法繼續;其次,隨機點不能出現在蛇身上,也就是隨機點的坐標不能和蛇身體上的任意坐標相同,否則就會出現BUG。按照此要求,我們創作出代碼如下:

public void createNode() { int newX = 0; int newY = 0; boolean flag = true; while(flag){ X = new Random().nextInt(width); Y = new Random().nextInt(length); for(int x = 0; x < Length; x++) { if(snake.get(x).getX() == newX && snake.get(x).getY() == newY) { flag = true; break; } flag = false; } } Color color = new Color(new Random().nextInt(255),new Random().nextInt(255),new Random().nextInt(255)); newNode.setX(newX); newNode.setY(newY); newNode.setColor(color); } 這個方法隨機產生0~width,0~length的隨機數,通過循環判斷是否與蛇身的點重合來產生隨機點,同時產生隨機的顏色,這里使用了Color的構造方法,不清楚的話可以通過API來查詢。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

接下來是我們進行游戲中至關重要的一點,就是對蛇的移動進行控制。我們使用“wsad”或者鍵盤上的“上下左右”來控制蛇身的移動變化。這其中的原理想必很多人都能馬上想到:監聽器。這里我們要設置監聽器的對象不再是一個按鈕,一個標簽,而是整個面板。我們要對整個面板增加一個鍵盤監聽器,用來監聽自己在鍵盤上的動作。這里我們統一一下,用”↑↓←→”來控制方向。當我們使用鍵盤捕捉到相應的動作后,該如何繼續呢?該如何編寫事件的處理?

我們來翻閱一下API。查看API中的KeyListener,我們可以查到KeyEvent,他有靜態的常量用來表示鍵盤上相應的點觸。VK_UP代表上箭頭,VK_DOWN代表下箭頭,VK_LEFT代表左箭頭,VK_RIGHT代表右箭頭。我們馬上可以聯想到:通過getKeyCode方法獲取到鍵盤事件,和四個常量進行比較,如果符合,就可以按照對應的方向調用方法,來移動蛇身。我們可以定義一個Move()方法,並且定義一個變量direction代表方向,通過對direction不同的賦值傳遞給Move(),來對蛇身產生不同的移動效果。接下來貼代碼:

public mainMap() { snake.add(new snakeNode(width/2,length/2,Color.RED); snake.add(new snakeNode(width/2,length/2+1,Color.BLUE); snake.add(new snakeNode(width/2,length/2+2,Color.GREY); Length = snake.size(); createNode(); this.addKeyListener(new KeyAdaper() { public void KeyPressed(KeyEvent e) { int direction = 0; switch(e.getKeyCode()) { case KeyEvent.VK_UP: direction = 1; break; case KeyEvent.VK_DOWN: direction = -1; break; case KeyEvent.VK_LEFT: direction = 2; break; case KeyEvent.VK_RIGHT: direction = -2; break; default: break; } Move(direction); } }); } //通過按下不同的方向鍵,我們得到了不同的direction變量,接下來我們定義一個Move()方法,傳遞direction變量來控制坐標的移動,從而得到蛇身變化的效果。 public void Move(int direction) { int firstX = snake.get(0).getX(); int firstY = snake.get(0).getY(); switch(direction) { case 1: firstY--; break; case -1: firstY++; break; case 2: firstX--; break; case -2: firstX++; break; default: break; } for(int x = 0; x < Length; x++) { if(snake.get(x).getX()==firstX&&snake.get(x).getY()==firstY) { Dead("不好意思,您碰到自己啦~~~~!!!!"); } }//這個方法遍歷蛇身集合中的每一個元素,拿出X軸和Y軸的值進行比較,來保證蛇頭的第一個點沒有觸碰到蛇身的其他點。如果碰到了,就調用Dead()方法結束游戲,Dead()方法隨后定義 if(firstX < 0 || firstX > width - 1 || firstY < 0 || firstY > length -1) { Dead("不好意思,您撞牆啦"); }//很簡單,判斷蛇頭的坐標有沒有超出界限 for(int x = Length - 1; x >0; x--) { snake.get(x).setX(snake.get(x-1).getX()); snake.get(x).setY(snake.get(x-1).getY()); } snake.get(0).setX(firstX); snake.get(0).setY(firstY); }//這段代碼從后往前遍歷集合,把最后一個集合的X軸和Y軸賦值為前一個元素的X軸和Y軸,把移動后的firstX和firstY坐標賦值給第一個元素,那么蛇身的整體位置就進行了變化,也就可以達到蛇身移動的效果了。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

通過以上代碼,我們已經初步搭建了貪吃蛇的基本邏輯框架。我們造出了蛇身,設置了按鍵后的蛇身移動的規律,也設置了蛇移動的范圍。我們先給出總覽的代碼,這樣有助於查漏補缺:

public class mainMap extends JPanel { private final int width = 20; private final int length = 30; private final int unit = 20; private ArrayList<snakeNode> snake = new ArrayList<>(); private snakeNode newNode = new snakeNode(0,0,Color.WHITE); private int Length; public mainMap() {//這是構造方法 snake.add(new snakeNode(width/2,length/2,Color.RED); snake.add(new snakeNode(width/2,length/2+1,Color.BLUE); snake.add(new snakeNode(width/2,length/2+2,Color.GREY); Length = snake.size(); createNode();//這是創造隨機點的方法 this.addKeyListener(new KeyAdaper() {//這是設置鍵盤事件的方法 public void KeyPressed(KeyEvent e) { int direction = 0; switch(e.getKeyCode()) { case KeyEvent.VK_UP: direction = 1; break; case KeyEvent.VK_DOWN: direction = -1; break; case KeyEvent.VK_LEFT: direction = 2; break; case KeyEvent.VK_RIGHT: direction = -2; break; default: break; } Move(direction); } }); } } public void Move(int direction) {//這是移動蛇身的方法 int firstX = snake.get(0).getX(); int firstY = snake.get(0).getY(); switch(direction) { case 1: firstY--; break; case -1: firstY++; break; case 2: firstX--; break; case -2: firstX++; break; default: break; } for(int x = 0; x < Length; x++) { if(snake.get(x).getX()==firstX&&snake.get(x).getY()==firstY) { Dead("不好意思,您碰到自己啦~~~~!!!!"); } } if(firstX < 0 || firstX > width - 1 || firstY < 0 || firstY > length -1) { Dead("不好意思,您撞牆啦"); } for(int x = Length - 1; x >0; x--) { snake.get(x).setX(snake.get(x-1).getX()); snake.get(x).setY(snake.get(x-1).getY()); } snake.get(0).setX(firstX); snake.get(0).setY(firstY); } public void createNode() {//這是創造隨機點的方法 int newX = 0; int newY = 0; boolean flag = true; while(flag){ X = new Random().nextInt(width); Y = new Random().nextInt(length); for(int x = 0; x < Length; x++) { if(snake.get(x).getX() == newX && snake.get(x).getY() == newY) { flag = true; break; } flag = false; } } Color color = new Color(new Random().nextInt(255),new Random().nextInt(255),new Random().nextInt(255)); newNode.setX(newX); newNode.setY(newY); newNode.setColor(color); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96

以上就是我們共同完成的步驟,如果全部實現並且加以理解,那么其實整個貪吃蛇的整體思路基本已經是掌握了。但這並沒有結束,我們還有許多的細節問題需要完成。我將在下一節中繼續來完成剩下的部分,包括蛇的定時移動,吃掉點的方法,已經畫出蛇的樣子。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM