Java學習總結之貪喫蛇項目程序編寫(一)

之前寫了程序分析,接下來進入程序編寫,這次寫程序跟之前的項目不一樣,之前是新增一個功能,就根據這個功能新增一部分內容,而這次有了程序分析,我打算即使還沒有加入新功能,也預留好新功能需要的各種屬性和方法,即使某個方法還沒有實現,也會在應該調用它的地方以註釋的形式加入調用語句。

V0.1:這個版本主要是繪製界面。根據程序設計中的屬性和方法,實現如下:

SnakeFrame.java

import java.awt.*;
import java.awt.event.*;

public class SnakeFrame
{
 public static void main(String[] args){
  new SnakeWindow("Snake").launch();
 }
}

class SnakeWindow extends Frame
{
 public static final int WINDOW_W = 800;
 public static final int WINDOW_H = 600;
 public static final int UNIT_SIZE = 20;
 public static final int SPEED = 1000;//刷新速度

 //private Snake snake = null;
 //private Bean bean = null;

 public SnakeWindow(String s){
  super(s);
 }

 public void launch(){
  setLocation(100,100);
  setSize(WINDOW_W,WINDOW_H);
  setBackground(Color.GRAY);
  addWindowListener(new WindowAdapter(){
   public void windowClosing (WindowEvent e){
    System.exit(0);
   }
  });
  addKeyListener(new KeyMonitor());
  setVisible(true);

  new Thread(new PaintThread()).start();
 }

 public void paint(Graphics g){
  Color c = g.getColor();
  g.setColor(Color.DARK_GRAY);
  for(int i = 1; i < WINDOW_H/UNIT_SIZE ; i++) {
   g.drawLine(0,UNIT_SIZE * i,WINDOW_W ,UNIT_SIZE * i);
  }
  for (int i = 1; i < WINDOW_W/UNIT_SIZE ; i++ )
  {
   g.drawLine(UNIT_SIZE * i, 0, UNIT_SIZE * i, WINDOW_H);
  }
  g.setColor(c);
 }

 class KeyMonitor extends KeyAdapter
 {
  public void keyPressed (KeyEvent e){
   //snake.keyPressed(e);
  }
 }
 
 class PaintThread implements Runnable
 {

  repaint();
  public void run() {
   while(true){
    repaint();
    try{
     Thread.sleep(SPEED);
    }catch (InterruptedException e){
     e.printStackTrace();
    }
   }
  }

 }
}

 

V0.2:這個版本里先把比較容易實現的豆類加入進去,另外,爲了培養一個良好的習慣,從這個版本開始加入各種註釋,有些地方有些失誤,給private 也加上了文檔註釋

在實現豆類的時候,發現用座標產生一個豆並不是特別方便,因爲有可能產生在界面的兩個格子之間,所以我改換x,y爲豆所在格子的行列,row、column

比較複雜的是產生新豆方法newBean(),這裏需要添加一個隨機數產生器,用來隨機產生新豆的位置,同時還要判斷新位置是否爲空,只有空位置才能添加新豆。若是一時不好實現,我們可以暫時先空着,僅僅聲明該方法。

根據程序分析設計中的豆類描述,寫好豆類之後,再在主類中添加豆類對象,修改paint方法,加入豆類的draw方法。具體代碼如下:

SnakeFrame.java

import java.awt.*;
import java.awt.event.*;

public class SnakeFrame
{
 public static void main(String[] args){
  new SnakeWindow("Snake").launch();
 }
}

class SnakeWindow extends Frame
{
 /**
  * 窗口寬度
  */
 public static final int WINDOW_W = 800;
 /**
  * 窗口高度
  */
 public static final int WINDOW_H = 600;
 /**
  * 正方形單元格邊長
  */
 public static final int UNIT_SIZE = 20;
 /**
  * 界面行數
  */
 public static final int ROWS = WINDOW_H/UNIT_SIZE;
 /**
  * 界面列數
  */
 public static final int COLUMNS = WINDOW_W/UNIT_SIZE;
 /**
  * 界面每隔SPEED毫秒刷新一次
  */
 public static final int SPEED = 1000;//刷新速度

 //private Snake snake = null;
 private Bean bean = Bean.newBean();
 
 /**
  * 構造方法
  * @param s:標題欄名稱
  */
 public SnakeWindow(String s){
  super(s);
 }

 /**
  * 窗口初始化
  */
 public void launch(){
  setLocation(100,100);
  setSize(WINDOW_W,WINDOW_H);
  setBackground(Color.GRAY);
  addWindowListener(new WindowAdapter(){
   public void windowClosing (WindowEvent e){
    System.exit(0);
   }
  });
  addKeyListener(new KeyMonitor());
  setVisible(true);

  new Thread(new PaintThread()).start();
 }

 /**
  * 窗口繪製方法
  */
 public void paint(Graphics g){
  Color c = g.getColor();
  g.setColor(Color.DARK_GRAY);
  for(int i = 1; i < WINDOW_H/UNIT_SIZE ; i++) {
   g.drawLine(0,UNIT_SIZE * i,WINDOW_W ,UNIT_SIZE * i);
  }
  for (int i = 1; i < WINDOW_W/UNIT_SIZE ; i++ )
  {
   g.drawLine(UNIT_SIZE * i, 0, UNIT_SIZE * i, WINDOW_H);
  }
  bean.draw(g);
  g.setColor(c);
 }

 /**
  * 鍵盤事件監聽器類
  */
 class KeyMonitor extends KeyAdapter
 {
  /**
   * 鍵盤按下時調用該方法
   * @param e:鍵盤事件
   */
  public void keyPressed (KeyEvent e){
   //snake.keyPressed(e);
  }
 }
 
 /**
  * 界面刷新線程類
  */
 class PaintThread implements Runnable
 {

  repaint();
  public void run() {
   while(true){
    repaint();
    try{
     Thread.sleep(SPEED);
    }catch (InterruptedException e){
     e.printStackTrace();
    }
   }
  }

 }
}

Bean.java

import java.awt.*;
import java.util.*;

/**
 * 豆類
 */
public class Bean
{
 /**
  * 豆子的直徑
  */
 public static final int SIZE = 20;
//豆橫座標

 private int row = 0;
 
 // 豆縱座標
 private int column = 0;
 /**
  * 隨機數產生器
  */
 static Random r = new Random();

 /*
  * 私有的構造方法,不許別的類調用
  */
 private Bean(int col, int row){
  this.row = row;
  this.column = col;
 }

 /**
  * 豆的繪製方法
  */
 public void draw(Graphics g){
  Color c = g.getColor();
  g.setColor(Color.GREEN);
  g.fillOval(column * SnakeWindow.UNIT_SIZE, row * SnakeWindow.UNIT_SIZE, SIZE, SIZE);
  g.setColor(c);
 }

 /**
  * 配合eat方法完成檢測
  */
 public Rectangle getRectangle(){
  return new Rectangle(column * SnakeWindow.UNIT_SIZE, row * SnakeWindow.UNIT_SIZE, SIZE, SIZE);
 }
 
 /**
  * 靜態方法,用來產生一個新豆
  */
 public static Bean newBean(){
  Bean b = new Bean(r.nextInt(SnakeWindow.COLUMNS), r.nextInt(SnakeWindow.ROWS));
  //缺省判斷邏輯,該位置是否爲空
  return b;
 }
}

 

V0.3:在這個版本中將蛇類添加進去

蛇類稍微有些麻煩,我們可以先寫出一個靜止不動的蛇,其他動態的方法實現暫時爲空。實現之後再寫move方法動起來,再寫keyPressed方法控制方向,再之後寫eat方法實現喫豆,再之後則是碰撞檢測,撞牆死和撞自己死。寫完方向控制之後的代碼如下:

SnakeFrame.java

import java.awt.*;
import java.awt.event.*;

public class SnakeFrame
{
 public static void main(String[] args){
  new SnakeWindow("Snake").launch();
 }
}

class SnakeWindow extends Frame
{
 /**
  * 窗口寬度
  */
 public static final int WINDOW_W = 800;
 /**
  * 窗口高度
  */
 public static final int WINDOW_H = 600;
 /**
  * 正方形單元格邊長
  */
 public static final int UNIT_SIZE = 20;
 /**
  * 界面行數
  */
 public static final int ROWS = WINDOW_H/UNIT_SIZE;
 /**
  * 界面列數
  */
 public static final int COLUMNS = WINDOW_W/UNIT_SIZE;
 /**
  * 界面每隔SPEED毫秒刷新一次
  */
 public static final int SPEED = 500;//刷新速度
 /**
  * 蛇類對象
  */
 private Snake snake = new Snake();
 /**
  * 豆類對象
  */
 private Bean bean = Bean.newBean();
 
 /**
  * 構造方法
  * @param s:標題欄名稱
  */
 public SnakeWindow(String s){
  super(s);
 }

 /**
  * 窗口初始化
  */
 public void launch(){
  setLocation(100,100);
  setSize(WINDOW_W,WINDOW_H);
  setBackground(Color.GRAY);
  addWindowListener(new WindowAdapter(){
   public void windowClosing (WindowEvent e){
    System.exit(0);
   }
  });
  addKeyListener(new KeyMonitor());
  setVisible(true);

  new Thread(new PaintThread()).start();
 }

 /**
  * 窗口繪製方法
  */
 public void paint(Graphics g){
  Color c = g.getColor();
  g.setColor(Color.DARK_GRAY);
  for(int i = 1; i < WINDOW_H/UNIT_SIZE ; i++) {
   g.drawLine(0,UNIT_SIZE * i,WINDOW_W ,UNIT_SIZE * i);
  }
  for (int i = 1; i < WINDOW_W/UNIT_SIZE ; i++ )
  {
   g.drawLine(UNIT_SIZE * i, 0, UNIT_SIZE * i, WINDOW_H);
  }
  snake.draw(g);
  bean.draw(g);
  g.setColor(c);
 }

 /**
  * 鍵盤事件監聽器類
  */
 class KeyMonitor extends KeyAdapter
 {
  /**
   * 鍵盤按下時調用該方法
   * @param e:鍵盤事件
   */
  public void keyPressed (KeyEvent e){
   snake.keyPressed(e);
  }
 }
 
 /**
  * 界面刷新線程類
  */
 class PaintThread implements Runnable
 {
  public void run() {
   while(true){
    repaint();
    try{
     Thread.sleep(SPEED);
    }catch (InterruptedException e){
     e.printStackTrace();
    }
   }
  }
 }
}

Snake.java

import java.awt.*;
import java.awt.event.*;
import java.util.*;

public class Snake
{
 /**
  * 盛放組成蛇的各個節點
  */
 public LinkedList<Node> nodeList = new LinkedList<Node>();
 /**
  * 蛇頭行進的方向
  */
 private Direction direction = Direction.Left;

 /**
  * 方向枚舉類型
  */
 public enum Direction {Up,Down,Left,Right}

 /**
  * 構造方法
  */
 public Snake(){
  nodeList.addFirst(new Node(19,14));
 }

 /**
  * 自身繪製
  */
 public void draw(Graphics g){
  move();

  Color c = g.getColor();
  g.setColor(Color.GREEN);
  for(int i = 0; i < nodeList.size(); i++){
   Node n = nodeList.get(i);
   n.draw(g);
  }
  g.setColor(c);
 }

 /**
  * 根據方向移動
  */
 public void move() {
  switch(direction){
  case Up :
   nodeList.addFirst(new Node(nodeList.getFirst().getColumn(), nodeList.getFirst().getRow() - 1));
   break;
  case Down :
   nodeList.addFirst(new Node(nodeList.getFirst().getColumn(), nodeList.getFirst().getRow() + 1));
   break;
  case Left :
   nodeList.addFirst(new Node(nodeList.getFirst().getColumn() - 1, nodeList.getFirst().getRow()));
   break;
  case Right :
   nodeList.addFirst(new Node(nodeList.getFirst().getColumn() + 1, nodeList.getFirst().getRow()));
   break;
  }
  nodeList.removeLast();
 }

 public void eat() {
  //
 }

 public void addNode() {
  //
 }

 public void collide () {
  //
 }

 /**
  * 方向鍵按鍵事件的處理,改變移動方向
  */
 public void keyPressed (KeyEvent e) {
  int keyCode = e.getKeyCode();
  switch(keyCode){
  case KeyEvent.VK_UP :
   direction = Direction.Up;
   break;
  case KeyEvent.VK_DOWN :
   direction = Direction.Down;
   break;
  case KeyEvent.VK_LEFT :
   direction = Direction.Left;
   break;
  case KeyEvent.VK_RIGHT :
   direction = Direction.Right;
   break;
  }
 }

 /**
  * 節點類
  */
 class Node
 {
  /**
   * 豆子列座標
   */
  private int row = 0;
  /**
   * 豆子行座標
   */
  private int column = 0;
  /**
   * 豆子行座標
   */
  public static final int SIZE = SnakeWindow.UNIT_SIZE;

  /**
   * 私有的構造方法,不許別的類調用
   */
  public Node(int col, int row){
   this.row = row;
   this.column = col;
  }

  public int getRow(){
   return row;
  }

  public int getColumn() {
   return column;
  }

  /**
   * 節點的繪製方法
   */
  public void draw(Graphics g){
   Color c = g.getColor();
   g.setColor(Color.BLACK);
   g.fillRect(column * SnakeWindow.UNIT_SIZE, row * SnakeWindow.UNIT_SIZE, SIZE, SIZE);
   g.setColor(c);
  }

  /**
   * 配合完成碰撞檢測
   */
  public Rectangle getRectangle(){
   return new Rectangle(column * SnakeWindow.UNIT_SIZE, row * SnakeWindow.UNIT_SIZE, SIZE, SIZE);
  }
 }
}

Bean.java

import java.awt.*;
import java.util.*;

/**
 * 豆類
 */
public class Bean
{
 /**
  * 豆子的直徑
  */
 public static final int SIZE = SnakeWindow.UNIT_SIZE;
 /**
  * 豆子行座標
  */
 private int row = 0;
 /**
  * 豆子列座標
  */
 private int column = 0;
 /**
  * 隨機數產生器
  */
 static Random r = new Random();

 /**
  * 私有的構造方法,不許別的類調用
  */
 private Bean(int col, int row){
  this.row = row;
  this.column = col;
 }

 /**
  * 豆的繪製方法
  */
 public void draw(Graphics g){
  Color c = g.getColor();
  g.setColor(Color.GREEN);
  g.fillOval(column * SnakeWindow.UNIT_SIZE, row * SnakeWindow.UNIT_SIZE, SIZE, SIZE);
  g.setColor(c);
 }

 /**
  * 配合eat方法完成檢測
  */
 public Rectangle getRectangle(){
  return new Rectangle(column * SnakeWindow.UNIT_SIZE, row * SnakeWindow.UNIT_SIZE, SIZE, SIZE);
 }
 
 /**
  * 靜態方法,用來產生一個新豆
  */
 public static Bean newBean(){
  Bean b = new Bean(r.nextInt(SnakeWindow.COLUMNS), r.nextInt(SnakeWindow.ROWS));
  //缺省判斷邏輯,該位置是否爲空
  return b;
 }
}

暫時寫到這,太長換下一篇

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章