貪吃蛇
Cell 是數據格子,是數據結構
Worm 是核心數據和算法的封裝,包括爬行,碰撞,吃食物等
TestCase 是核心業務數據的測試案例,必須嚴格實現通過
Wormstage 1 是蛇的繪製面板,還充當了軟件流程控制器的
作用:控制定時任務處理,和鍵盤輸入流程控制creepTo()!
Jframe 只是窗口容器。將Wormstage 顯示出來。
源代碼下載:http://download.csdn.net/download/u012234452/9327291
結構圖
1、Cell.java
package com.feike.worm;
/** 一個單元格子 */
public class Cell {
private int x;
private int y;
public Cell() {
}
public Cell(int x, int y) {
super();
this.x = x;
this.y = y;
}
public String toString() {
return "["+x+","+y+"]";
}
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;
}
}
2、Worm.java
package com.feike.worm;
import java.util.Arrays;
/** 貪吃蛇 */
public class Worm {
public static final int DEFAULL_LENGTH = 12;
private Cell[] cells;
public static final int UP = 1;
public static final int DOWN = -1;
public static final int LEFT = 2;
public static final int RIGHT = -2;
/** 蛇當前的運行方向 */
private int currentDirection;
public Worm() {
cells = new Cell[DEFAULL_LENGTH];
for(int i=0;i<cells.length;i++){
cells[i] = new Cell(i,0);//[0,0][1,0][2,0][3,0]...
}
/**給蛇一個默認的爬行方向 */
currentDirection = DOWN;
}
public boolean contains(int x,int y){
for(int i= 0;i<cells.length;i++){
Cell node = cells[i];
if(node.getX()==x && node.getY()==y){
return true;
}
}
return false;
}
/**
* 1)計算currentDirection與direction的和,
* 如果是0表示方向了,就結束方法返回,不進行任何動作
* 2)currentDirection = Direction 改變當前方向,
* 作爲下次運行的方向
* 3)判斷當前頭節點的座標和食物對象的座標一致
* 如果一致說明吃到食物了
* 4)如果吃到食物,就將cells數組進行擴容
* 將cells數組內容的每個元素向後移動。
* 5)將新頭節點插入的頭位置cells[0] = newHead
* 6)返回是否吃到食物
*/
public boolean creep(int direction,Cell food){
if(currentDirection + direction ==0){
return false;//反向了,不進行任何動作
}
currentDirection = direction;
Cell head = createHead(direction);
/*
boolean eat = false;
if(head.getX()==food.getX() &&
head.getY()==food.getY()){
eat = true;
}*/
boolean eat = head.getX()==food.getX() &&
head.getY()==food.getY();
if(eat){
//如果吃了 就擴容
cells = Arrays.copyOf(cells, cells.length+1);
}
for(int i=cells.length-1;i>=1;i--){
cells[i] = cells[i-1];
}
cells[0] = head;
return eat;
}
/** 重載一下方便使用 看當前方向*/
public boolean creep(Cell food){
return creep(currentDirection,food);
}
/** 爬 */
public void creep(){
for(int i=cells.length-1;i>=1;i--){
cells[i] = cells[i-1];
}
cells[0] = createHead(currentDirection);
}
/** 看當前方向是否會碰撞*/
public boolean hit(){
return hit(currentDirection);
}
/** 檢查是否撞牆或撞到自己*/
public boolean hit(int direction){
System.out.println("方向(2): "+direction);//檢查方向
Cell head = createHead(direction);
System.out.println(head);//檢查頭座標位置
if(currentDirection + direction ==0){
return false;//反向了,不進行任何動作
}
if(head.getX()<0 || head.getX()>=WormStage.COLS ||
head.getY()<0 || head.getY()>WormStage.ROWS){
//if(true)這撞在牆上了,返回true
return true;
}
for(int i=0;i<cells.length-1;i++){
Cell node = cells[i];
if(node.getX()==head.getX() &&
node.getY()==head.getY()){
return true;
}
}
return false;
}
/** 頭節點的移動*/
private Cell createHead(int direction){
int x = cells[0].getX();
int y = cells[0].getY();
switch (direction) {
case DOWN: y++; break;
case UP: y--; break;
case LEFT: x--; break;
case RIGHT: x++; break;
}
return new Cell(x,y);
}
/** Worm.java */
public Cell[] getCells(){
// return cells;
//下面這專業點
return Arrays.copyOf(cells, cells.length);
}
public String toString() {
return Arrays.toString(cells);
}
}
3、WormStage.java
package com.feike.worm;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.security.PublicKey;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
public class WormStage extends JPanel{
/** 行數*/
public static final int ROWS = 35;
/** 列數*/
public static final int COLS = 35;
/** 格子大小 10個像素大小*/
public static final int CELL_SIZE = 10;
private Worm worm;
private Cell food;
public WormStage() {
worm = new Worm();
food = createFood();
}
/** 生成一個食物
* 1 生成隨機數x,y
* 2 檢查蛇是否包含x,y
* 2.1 如果包含 返回 1
* 3 創建食物節點。
* */
private Cell createFood(){
int x;
int y;
Random r = new Random();
do{
x = r.nextInt(COLS);
y = r.nextInt(ROWS);
}while(worm.contains(x,y));
return new Cell(x,y);
}
public String toString(){
return "worm:"+worm+"\nfood:"+food;
}
/** 重寫繪圖方法*/
public void paint(Graphics g){
//填充背景色
g.setColor(Color.DARK_GRAY);
g.fillRect(0, 0, getWidth(), getHeight());
//繪製食物
g.setColor(Color.RED);
g.fill3DRect(CELL_SIZE*food.getX(),
CELL_SIZE*food.getY(), CELL_SIZE, CELL_SIZE, true);
//繪製蛇
g.setColor(Color.GREEN);
Cell[] cells = worm.getCells();
for(int i=0;i<cells.length;i++){
Cell node = cells[i];
g.fill3DRect(CELL_SIZE*node.getX(),
CELL_SIZE*node.getY(), CELL_SIZE, CELL_SIZE, true);
}
}
public static void main(String[] args) {
//啓動軟件 WormStage.java
JFrame frame = new JFrame("貪吃蛇");
WormStage pane = new WormStage();
frame.setLayout(null);// 取消窗口的默認佈局,取消自動充滿
frame.add(pane);// 窗口添加面板
pane.setSize(CELL_SIZE*COLS, CELL_SIZE*ROWS);//面板大小
pane.setLocation(50, 50);//面板位置
frame.setSize(450, 480);//設置窗口的大小
pane.setBorder(new LineBorder(Color.black));//添加邊框
frame.setLocationRelativeTo(null);//frame居中
frame.setVisible(true);//顯示窗口
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pane.action();//啓動蛇的運行
}
/**行爲 */
private void action(){
/* worm.creep(food);
swing JPanel 中聲明的方法,會盡快的啓動重繪功能,
儘快調用paint(g)方法繪製界面
repaint();*/
Timer timer = new Timer();
timer.schedule(new TimerTask(){
public void run(){
//爬行控制邏輯
if(worm.hit()){
worm = new Worm();
food = createFood();
}else{
boolean eat = worm.creep(food);
if(eat){
food = createFood();
}
}
worm.creep(food);
repaint();
}
}, 0,1000/7);
//this 就是當前舞臺面板
this.requestFocus();//獲得焦點
this.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e){
//key 代表哪個按鍵被按下!
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_UP: //上箭頭按下
creepTo(Worm.UP);
break;
case KeyEvent.VK_DOWN: //下箭頭按下
creepTo(Worm.DOWN);
break;
case KeyEvent.VK_LEFT: //左箭頭按下
creepTo(Worm.LEFT);
break;
case KeyEvent.VK_RIGHT: //右箭頭按下
creepTo(Worm.RIGHT);
break;
}
}
});//addKeyListener
}//action()
/** 爬行控制方法,在按鍵按下時調用*/
private void creepTo(int direction){
if(worm.hit(direction)){
worm = new Worm();
food = createFood();
}else {
boolean eat = worm.creep(direction,food);
if(eat){
food = createFood();
}
}
repaint();
}
}//wormStage
下面代碼是用作測試用的
1、TestCase.java
package com.feike.test;
import org.junit.Test;
import com.feike.worm.*;
/**
* test 測試
* test 案例
*
*/
public class TestCase {
@Test //來自JUnit的註釋標記,用於執行測試方法
public void testWormInit(){
System.out.println("測試Worm構造器");
Worm worm = new Worm();
System.out.println(worm);
}
@Test
public void testWormContains(){
System.out.println("測試Worm包含算法");
Worm worm = new Worm();
System.out.println(worm.contains(2, 0));//true
System.out.println(worm.contains(5, 6));//false
}
@Test
public void testWormStage(){
System.out.println("創建舞臺實例");
WormStage stage = new WormStage();
System.out.println(stage);
}
@Test
public void testCreep(){
System.out.println("爬行測試");
Worm worm = new Worm();
System.out.println(worm);
worm.creep();
System.out.println(worm);
}
@Test
public void testCreepForFood(){
System.out.println("檢查食物的爬行");
Worm worm = new Worm();
Cell food = new Cell(1,2);
System.out.println(worm.creep(Worm.DOWN, food));
System.out.println(worm);
System.out.println(worm.creep(Worm.DOWN, food));
System.out.println(worm);
System.out.println(worm.creep(Worm.RIGHT, food));
System.out.println(worm);
}
@Test
public void testHit(){
System.out.println("碰撞測試");
Worm worm = new Worm();
Cell food = new Cell(10,10);
System.out.println(worm);
System.out.println(worm.creep(Worm.DOWN, food));
System.out.println(worm);
System.out.println(worm.creep(Worm.DOWN, food));
System.out.println(worm);
System.out.println(worm.hit(Worm.LEFT));//true
System.out.println(worm.hit(Worm.RIGHT));//false
System.out.println(worm.creep(Worm.RIGHT, food));
System.out.println(worm);
System.out.println(worm.creep(Worm.RIGHT, food));
System.out.println(worm);
System.out.println(worm.creep(Worm.UP, food));
System.out.println(worm);
System.out.println(worm.hit(Worm.UP));//true
}
}
2、Test.java
package com.feike.test;
import com.feike.worm.Worm;
/**
* 測試默認創建的貪吃蛇對象
*
*/
public class Test {
public static void main(String[] args) {
Worm worm = new Worm();
System.out.println(worm);
}
}
3、JFrameDemo.java
package com.feike.test;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;// Frame 相框,框架
import javax.swing.JPanel;// panel 面板
import javax.swing.border.LineBorder;
/** 顯示窗口 與 繪圖 */
public class JFrameDemo {
public static void main(String[] args) {
JFrame frame = new JFrame("窗口");
Stage pane = new Stage();
frame.setLayout(null);// 取消窗口的默認佈局,取消自動充滿
frame.add(pane);// 窗口添加面板
pane.setSize(10 * 35, 10 * 35);//面板大小
pane.setLocation(50, 50);//面板位置
frame.setSize(450, 480);//設置窗口的大小
pane.setBorder(new LineBorder(Color.black));//添加邊框
frame.setLocationRelativeTo(null);//frame居中
frame.setVisible(true);//顯示窗口
//在Swing中如下代碼可以實現對鍵盤事件的監聽,
//也就是獲得到底那個鍵盤按鍵被按下了
pane.requestFocus();//使pane獲取輸入“焦點”,
//也就是使pane變成鍵盤輸入的目標
//pane.addKeyListener(new KeyListener(){
//繼承KeyAdapter比實現KeyListener 更加簡潔。
//在pane上添加鍵盤事件的監聽,獲得到底哪個按鍵被按下
pane.addKeyListener(new KeyAdapter(){
//在按鍵按下的時候執行的方法
public void keyPressed(KeyEvent e) {
System.out.println("hi"+e.getKeyCode());
}
/*//在按鍵釋放的時候執行
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}*/
});
}
}
class Stage extends JPanel{
/** 重寫了 默認的繪圖方法*/
public void paint(Graphics g){//paint
g.setColor(Color.darkGray);//深灰色
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.RED);
g.fill3DRect(50, 50, 30, 20, true);
}
}