Java 小游戏-贪吃蛇

Java 在学习 面向对象阶段 对一个小游戏 贪吃蛇项目的分析与理解

开发文档:有两个对象 :贪吃蛇对象 和 食物(方块) 对象

  • 食物(Cell)对象
    • 有两个私有成员变量坐标
      • x(横坐标)
      • y(纵坐标)
  • 贪吃蛇(Worm)对象 
    • 有五个静态成员变量
      • DEFAULT_LENGTH 默认贪吃蛇的长度
      • UP 向上
      • DOWN 向下
      • LEFT 向左
      • RIGHT 向右 
    • 私有 变量 currentDirection 当前的运行方向
    • 私有 方块数组

  贪吃蛇对象动作有 移动 和 碰撞(撞墙 、撞自己、以及吃食物)

  • 移动 
  • 碰撞 
    • 食物 刷新时 判断 是否和 蛇对象 位置重复  
    • 撞墙  判断赦对象的头部坐标 是否碰撞到围墙
    • 撞自己  遍历自己身体的数组 和头部坐标 判断是否碰撞
    • 吃食物  也就是头部 碰撞到食物对象

Cell  食物 格子类 代码

 1 public class Cell {
 2     private int x;
 3     private int y;
 4 
 5     public Cell() {
 6     }
 7 
 8     public Cell(int x, int y) {
 9         this.x = x;
10         this.y = y;
11     }
12 
13     public int getX() {
14         return x;
15     }
16 
17     public void setX(int x) {
18         this.x = x;
19     }
20 
21     public int getY() {
22         return y;
23     }
24 
25     public void setY(int y) {
26         this.y = y;
27     }
28 
29     public String toString() {
30         return "[" + x + "," + y + "]";
31     }
32 }

Worm贪吃蛇 类代码

  1 public class Worm {
  2     public static final int DEFAULT_LENGTH = 12;
  3 
  4     private Cell[] cells;
  5 
  6     public static final int UP = 1;
  7     public static final int DOWN = -1;
  8     public static final int LEFT = 2;
  9     public static final int RIGHT = -2;
 10 
 11     private int currentDirection;
 12 
 13     public Worm(){
 14         cells = new Cell[DEFAULT_LENGTH];
 15         for (int i = 0; i < cells.length; i++) {
 16             cells[i] = new Cell(i,0);
 17         }
 18         currentDirection = DOWN;
 19     }
 20 
 21     public boolean contains(int x,int y){
 22         for (int i = 0; i < cells.length; i++) {
 23             Cell node = cells[i];
 24             if (node.getX() == x && node.getY() == y) {
 25                 return true;
 26             }
 27         }
 28         return false;
 29     }
 30 
 31     /**
 32      * 1) 计算currentDirection与direction的和, 如果是0表示反向了, 就结束方法返回, 不进行任何动作
 33      * 2)currentDirection = direction 改变当前的方向, 作为下次运行的方向 3) 判断当前头节点的坐标与食物对象的坐标一致
 34      * 如果一致说明是吃到食物了 4) 如果吃到食物, 就将cells数组进行扩容 将cells数组内容的每个元素向后移动. 5)
 35      * 将新头节点插入的头位置cells[0]=newHead 6) 返回是否吃到食物
 36      */
 37     public boolean creep(int direction,Cell food){
 38         if(currentDirection + direction == 0){
 39             return false;
 40         }
 41         currentDirection = direction;
 42         Cell head = createHead(direction);
 43         boolean eat = head.getX() == food.getX() && head.getX() == food.getY();
 44         if(eat){
 45             cells = Arrays.copyOf(cells,cells.length + 1);
 46         }
 47         for (int i = cells.length-1; i >= 1; i--) {
 48             cells[i] = cells[i - 1];
 49         }
 50         cells[0] = head;
 51         return eat;
 52     }
 53     public boolean hit(){
 54         return hit(currentDirection);
 55     }
 56     public boolean hit(int direction){
 57         if(currentDirection + direction == 0){
 58             return false;
 59         }
 60         Cell head = createHead(direction);
 61         if(head.getX() <0 || head.getX()>=WormStage.COLS || head.getY() < 0 || head.getY() >= WormStage.ROWS){
 62             return true;
 63         }
 64         for (int i = 0; i < cells.length-1; i++) {
 65             Cell node = cells[i];
 66             if(node.getX() == head.getX() && node.getY() == head.getY()){
 67                 return true;
 68             }
 69         }
 70         return false;
 71     }
 72     public boolean creep(Cell food){
 73         return creep(currentDirection,food);
 74     }
 75     public void creep(){
 76         for (int i = cells.length-1; i >=1 ; i--) {
 77             cells[i] = cells[i-1];
 78         }
 79         cells[0] = createHead(currentDirection);
 80     }
 81     private Cell createHead(int direction){
 82         int x = cells[0].getX();
 83         int y = cells[0].getY();
 84         switch (direction){
 85             case DOWN:
 86                 y++;
 87                 break;
 88             case UP:
 89                 y--;
 90                 break;
 91             case LEFT:
 92                 x--;
 93                 break;
 94             case RIGHT:
 95                 x++;
 96                 break;
 97         }
 98         return new Cell(x,y);
 99 
100     }
101     public Cell[] getCells(){
102         return Arrays.copyOf(cells,cells.length);
103     }
104     /**
105     *  重写toString()
106     */
107     @Override
108     public String toString() {
109         return Arrays.toString(cells);
110     }
111 }

主程序WormStage 代码

public class WormStage extends JPanel {
    public static final int ROWS = 35;
    public static final int COLS = 35;
    public static int CELL_SIZE = 10;
    public static Image background;
    public static Image foodImage;
    public static Image cellImage;

    private Worm worm;
    private Cell food;

    public WormStage(){
        //如下加载图片的方法,知道即可,图片必须与WormStage.java
        //在同一个包中!
        background = Toolkit.getDefaultToolkit().
                getImage("WormImg/bg.png");
        foodImage = Toolkit.getDefaultToolkit().
                getImage("WormImg/food.png");
        cellImage = Toolkit.getDefaultToolkit().
                getImage("WormImg/cell.png");
        worm = new Worm();
        food = createFood();
    }
    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);
    }
    @Override
    public String toString() {
        return "worm:" + worm + "\nfood:" + food;
    }

    @Override
    public void paint(Graphics g) {
        // 填充背景色
        g.drawImage(background, 0, 0, null);
        // 绘制食物
        g.translate(54, 49);
        g.drawImage(foodImage,
                CELL_SIZE * food.getX(), CELL_SIZE * food.getY(), null);
        // 绘制蛇
        Cell[] cells = worm.getCells();
        for (int i = 0; i < cells.length; i++) {
            Cell node = cells[i];
            g.drawImage(cellImage,
                    CELL_SIZE * node.getX(), CELL_SIZE * node.getY(), null);

        }
    }
    public static void main(String[] args) {
        // 启动软件 WormStage.java
        JFrame frame = new JFrame("贪吃蛇");
        WormStage pane = new WormStage();// 面板
        frame.add(pane);// 窗口添加面板
        frame.setSize(470, 480);// 设置窗口的大小
        frame.setLocationRelativeTo(null);// frame居中
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pane.action();// 启动蛇的运行
    }
    private void action() {
        // worm.creep(food);
        // repaint();//swing JPanel 中声明的方法,会尽快的启动
        // 界面的重绘功能,尽快调用paint(g) 方法绘制界面
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                // 爬行控制逻辑
                if (worm.hit()) {
                    worm = new Worm();
                    food = createFood();
                } else {
                    boolean eat = worm.creep(food);
                    if (eat) {
                        food = createFood();
                    }
                }
                repaint();
            }
        }, 0, 1000 / 7);
        // this 就是当前舞台面板
        this.requestFocus();
        this.addKeyListener(new KeyAdapter() {
            @Override
            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();
    }
}

 

posted @ 2022-10-19 18:09  心宽体胖李小二  阅读(137)  评论(0)    收藏  举报