java贪吃蛇开发总结

    相信每一个java学者在成长的时候都编写过一些小游戏,我花了两天的时间编写了贪吃蛇,这其中当然也参考了别人的代码。对于学者来说,通过这个案例也成长了不少。

  对于面向对象来说,贪吃蛇所包含的类应该有Snake类、Food类、Ground类、GamePanel类(继承JPanel),这些都是属于Entity(实体)类,所以把他们放到一个包下面,Controller类继承KeyAdapter(键盘事件监听类库)实现SnakeListener 接口,可以看出Controller是一个控制蛇和监听键盘事件的类。SnakeGameActivity类包含main函数,是游戏的入口。Global类用于定义面板格局。列入面板的长宽,格子的大小。

 

所有的包以及类

Controller负责控制游戏的开始、蛇的移动以及监听键盘,监听键盘调用了keyPressed键盘事件,判断键盘的输入。

   

  实体类蛇、食物、障碍物通过对象把他们抽象出来,声明它们所具有的属性和方法,比如说:蛇具有移动和改变方向的方法。

 

SnakeLiener(单词错误,是SnakeListener)负责监听蛇每次的移动,具体实现方法见Controller。

Global定义了窗口的宽高以及每块方格的大小。

 

 

整个项目很简单,但对于刚接触编程的人来说在这其中却能学到很多东西。

package com.Leekin.Entity;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.LinkedList;

import com.Leekin.Listener.SnakeLiener;
import com.Leekin.Util.Global;

/**
 * Snake Class 
 * @author Leekin
 *
 */
public class Snake {
    //the Listener for Snake Move
    private SnakeLiener snakeListener;
    //LinkedList
    private boolean life = true;
  private    LinkedList<Point> body = new LinkedList<Point>();
  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 oldDirection,newDirection;
  private Point tail;        //储存尾巴
  public Snake(){
      init();
  }
    
    
    private void init() {
        int x = Global.WIDTH/2;
        int y = Global.HEIGHT/2;
        for(int i = 0;i < 3;i++){
            body.add(new Point(x-1,y));
        }
        this.oldDirection = newDirection= RIGHT;
}


    /**
     * eat mothd
     * 去掉尾巴加头
     * @param food
     */
    public void eatFood(Food food){
        body.add(tail);
    }
    
    /**
     * 
     * 去尾加头
     */
    //move Method
    public void move(){
        tail = body.removeLast();
        int x = body.getFirst().x;
        int y= body.getFirst().y;
        /**
         * 获得新的头部
         * 要判断方向才能确定头部
         * 在初始化构造的时候默认的方向是向右
         * 
         */
        if(this.oldDirection+newDirection != 0)
        this.oldDirection = this.newDirection;
        switch(oldDirection){
        case UP:
            y--;
            if(y<0)y=Global.HEIGHT - 1;
            break;
        case DOWN:
            y++;
            if(y >= Global.HEIGHT) y = 0;
            break;
        case LEFT:
            x--;
            if(x<0)x=Global.WIDTH-1;
            break;
        case RIGHT:
            x++;
            if(x>=Global.WIDTH) x=0;
            break;
        }
        body.addFirst(new Point(x,y));
    }

    
    //changedirection method
    public void changeDirection(int direction){
        this.newDirection = direction;
        //this.direction= direction;
        
    }
    
    //DrawMe Method
    public void DrawMe(Graphics g){
        g.setColor(Color.blue);
        for(Point p:body){
            g.fill3DRect(p.x*Global.CELL_SIZE,p.y*
                    Global.CELL_SIZE,  Global.CELL_SIZE,Global.CELL_SIZE,true);
        }
    }
    
    //is eat self method
    public boolean isEatSelf(){
        for(int i = 0; i < body.size();i++){
            if(body.get(i).equals(getHead())){
                return false;
            }
        }
        return false;
    }
    
    public void addSnakeListener(SnakeLiener snakeLiener){
        if(snakeLiener != null)
        this.snakeListener = snakeLiener;    
        
    }
    
    public void start(){
        new SnakeDriver().start();
    }
    //获得蛇头的方法
    public Point getHead(){
        return body.getFirst();
    }
    public void setlife(boolean life){
        this.life = life;
    }
    
    private class SnakeDriver extends Thread{
        @Override
        public void run() {
            while(life){
                move();
                snakeListener.snakeMoved(Snake.this);
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
    
    
    
}

Snake实现逻辑,其中移动速度用线程来控制,Thread.sleep(300);(休眠0.3秒)

 

package com.Leekin.Entity;

import java.awt.Graphics;

import javax.swing.JPanel;

/**
 * Ganme Panel class
 * @author Leekin
 *
 */

public class GamePanel extends JPanel {
    //Initialize object
    private Snake snake;
    private Food food;
    private Ground ground;
    
    //show method
    public void disPlay(Snake snake,Food food,Ground ground){
        this.snake = snake;
        this.food = food;
        this.ground = ground;
        repaint();
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if(snake!=null&&food!=null&&ground!=null){
            snake.DrawMe(g);
            food.DrawMe(g);
            ground.DrawMe(g);
        }
    }
}

 

GamePanel类是JPanel的子类,复写父类的paintComponen方法,是游戏板面的对象。

package com.Leekin.Entity;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Random;

import com.Leekin.Util.Global;

/**
 * Ground class
 * @author Leekin
 *
 */
public class Ground {
        private int[][] rocks = new int[Global.WIDTH][Global.HEIGHT];
        public Ground(){
            for(int y = 0;y< Global.HEIGHT;y++){
                for(int x = 0;x<Global.WIDTH;x++){
                    if(y==0||y==Global.HEIGHT-1)
                        rocks[y][x] = 1;
                    if(x==0||x==Global.HEIGHT-1){
                        rocks[y][x] = 1;
                    }
                }
            }
        }
    //DrawMe
    public void DrawMe(Graphics g){
        g.setColor(Color.orange);
        for(int y = 0;y<Global.HEIGHT;y++){
            for(int x = 0;x<Global.WIDTH;x++){
                if(rocks[y][x] == 1){
                    g.fill3DRect(x*Global.CELL_SIZE, y*Global.CELL_SIZE,
                            Global.CELL_SIZE, Global.CELL_SIZE, true);
                }
            }
        }
    }
    
    /**
     * 设置食物点的位置
     * @return
     */
    public Point getPoint(){
        int x,y;
        do{
         x = new Random().nextInt(Global.WIDTH);
         y = new Random().nextInt(Global.HEIGHT);
        }while(rocks[x][y]==1);
        return new Point(x,y);
    }

    
    //is eat by snake
    public boolean isEatBySnake(Snake snake){
        Point head = snake.getHead();
        for(int x = 0;x<Global.WIDTH;x++){
            for(int y = 0;y<Global.HEIGHT;y++){
                if(rocks[x][y]  == 1 && head.x == x && head.y == y)
                    return true;
            }
        }
        return false;
    }
}

Ground类,数组rocks用于储存障碍物,便用镶套for循环遍历,在用if判断,符合条件的生成边框障碍物。当蛇头的点与障碍物重合时就判定为蛇撞到障碍物,调用gameover的方法。

 

package com.Leekin.Entity;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;

import com.Leekin.Util.Global;

/**
 * Food class
 * @author Leekin
 *
 */
public class Food extends Point {
    
    //DrawMe method
    public void DrawMe(Graphics g){
        g.setColor(Color.green);
        g.fill3DRect(x*Global.CELL_SIZE, y*Global.CELL_SIZE, 
                Global.CELL_SIZE,Global.CELL_SIZE,true );
        
    }
    
    /**
     * is eat by snak
     * 只要判断蛇头的点是否和食物的点重合
     * 得到蛇头
     * @param snake
     * @return
     */
    public boolean isEatBySnak(Snake snake){
        Point head = snake.getHead();
        if(this.equals(head))
            return true;
        return false;
    }
    public void addFood(Point p){
        this.x = p.x;
        this.y= p.y;
    }
}

Food类是point的子类,因为生成的food是一个点。判断是否被蛇吃到的方法是蛇头的点是否和食物的点重合。当吃到蛇就会增加一个方格,同时addFood方法生成新的食物。

整个布局是以左上角的点为(0,0)的坐标,但坐标点与坐标的位置相反,它排列了数组在上面。

posted @ 2015-06-02 22:12  SWordStudio  阅读(1263)  评论(2)    收藏  举报