• [苦逼程序员成长之路]3、贪吃蛇游戏


      贪吃蛇游戏,参考着游戏功能文档写的,有些算法参考了现成的游戏代码,有些算法和想法也是自己想的和设计的,下面先说明下自己对这个游戏的想法:

       游戏有三个类:

        Cell:格子类,用语组成格子和食物,因为食物只是一个格子组成,所以不再新建类,new一个Cell代表食物

        Worm:蛇类,实现蛇的基本功能:封装了蛇的动作,包括碰撞检查,吃食物和移动

        WormStage:舞台类,实现整个游戏的功能

        

    下面是完整的代码:

    格子类:

     1 package com;
     2 
     3 import java.awt.Color;
     4 /**格子类,最基本的类*/
     5 public class Cell {
     6     private int row;
     7     private int col;
     8     private Color color;
     9 
    10     public Cell(int row, int col, Color color) {
    11         super();
    12         this.row = row;
    13         this.col = col;
    14         this.color = color;
    15     }
    16 
    17     public int getRow() {
    18         return row;
    19     }
    20 
    21     public void setRow(int row) {
    22         this.row = row;
    23     }
    24 
    25     public int getCol() {
    26         return col;
    27     }
    28 
    29     public void setCol(int col) {
    30         this.col = col;
    31     }
    32 
    33     public Color getColor() {
    34         return color;
    35     }
    36 
    37     public void setColor(Color color) {
    38         this.color = color;
    39     }
    40 
    41     @Override
    42     public String toString() {
    43         return "Cell [row=" + row + ", col=" + col + "]";
    44     }
    45 
    46 }

    Worm类:

      1 package com;
      2 
      3 import java.awt.Color;
      4 import java.util.Arrays;
      5 
      6 /** 蛇体类,封装了蛇的动作,包括检查碰撞,吃食物和移动 */
      7 public class Worm {
      8     /** 移动数据 */
      9     private final int CHANGELEFT = -2;
     10     private final int CHANGERIGHT = 2;
     11     private final int CHANGEDOWN = -1;
     12     private final int CHANGEUP = 1;
     13 
     14     /** 蛇的颜色和蛇的初始长度 */
     15     private Color wormColor;
     16     private Cell[] worm;
     17 
     18     /** 构造器,用于初始化 */
     19     public Worm() {
     20         worm = new Cell[3];
     21         wormColor = Color.red;
     22         for (int i = 0; i < 3; i++) {
     23             worm[i] = new Cell(5 - i, 10, Color.red);
     24         }
     25 
     26     }
     27 
     28     /* get方法,用于别的类中调用worm */
     29     public Cell[] getWorm() {
     30         return worm;
     31     }
     32 
     33     /** 判断碰撞算法 */
     34     public boolean isHit(int changeNum) {
     35         Cell newHead = newHead(changeNum);
     36         /* 如果新头不是蛇的第二节就进行碰撞算法 */
     37         if (newHead.getCol() != worm[1].getCol()
     38                 || newHead.getRow() != worm[1].getRow()) {
     39             /* 看新头是否超出边界,超出则是发生碰撞 */
     40             if (newHead.getCol() < 0 || newHead.getCol() > 49
     41                     || newHead.getRow() < 0 || newHead.getRow() > 49) {
     42                 return true;
     43             }
     44             /* 遍历蛇身,与新头比较,看是否重合,如果重合就是发生碰撞 */
     45             for (Cell cell : worm) {
     46                 if (newHead.getCol() == cell.getCol()
     47                         && newHead.getRow() == cell.getRow()) {
     48                     return true;
     49                 }
     50             }
     51         }
     52 
     53         return false;
     54     }
     55 
     56     /** 蛇的移动,传入两个参数,food表示食物,用于判断是否吃到食物,并返回,changeNum表示移动方向,0表示自动前进 */
     57     public boolean move(Cell food, int changeNum) {
     58         boolean eat = false;
     59         Cell newHead = newHead(changeNum);
     60 
     61         if (newHead.getCol() == food.getCol()
     62                 && newHead.getRow() == food.getRow()) {
     63             worm = Arrays.copyOf(worm, worm.length + 1);
     64 
     65             eat = true;
     66 
     67         }
     68         /*如果新头不是蛇身的第二节,就移动*/
     69         if (newHead.getCol() != worm[1].getCol()
     70                 || newHead.getRow() != worm[1].getRow()) {
     71             for (int i = worm.length - 1; i >= 1; i--) {
     72                 worm[i] = worm[i - 1];
     73             }
     74             worm[0] = newHead;
     75 
     76         }
     77         return eat;
     78 
     79     }
     80     /**根据传入的参数,新生成一个新头,如果是0就是自动前进的新头*/
     81     public Cell newHead(int changeNum) {
     82         Cell newHead = new Cell(-1, -1, wormColor);
     83         Cell head = worm[0];
     84         Cell nextCell = worm[1];
     85 
     86         switch (changeNum) {
     87         case 0:
     88             newHead.setCol(head.getCol() * 2 - nextCell.getCol());
     89             newHead.setRow(head.getRow() * 2 - nextCell.getRow());
     90             break;
     91         case CHANGELEFT:
     92             newHead.setCol(head.getCol() - 1);
     93             newHead.setRow(head.getRow());
     94             break;
     95         case CHANGEDOWN:
     96             newHead.setCol(head.getCol());
     97             newHead.setRow(head.getRow() + 1);
     98             break;
     99         case CHANGEUP:
    100             newHead.setCol(head.getCol());
    101             newHead.setRow(head.getRow() - 1);
    102             break;
    103 
    104         case CHANGERIGHT:
    105             newHead.setCol(head.getCol() + 1);
    106             newHead.setRow(head.getRow());
    107             break;
    108 
    109         }
    110 
    111         return newHead;
    112     }
    113 
    114 }

    WormStage类:

    package com;
    
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.Graphics;
    import java.awt.event.KeyAdapter;
    import java.awt.event.KeyEvent;
    import java.awt.event.KeyListener;
    import java.util.Random;
    
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    /**
     * 游戏的主界面
     * 
     * @author 陈杰
     * 
     */
    public class WormStage extends JPanel {
        /** 食物,因为只有一个食物,所以定义为静态的,以后调用方法修改食物的位置,以节省资源 */
        private static Cell food = new Cell(0, 0, Color.green);;
        /** 舞台的长宽和大小的数据,定义为常量 */
        private static final int ROWS = 50;
        private static final int COLS = 50;
        private static final int SIZE = 10;
        /** 贪吃蛇 */
        private Worm worm = new Worm();
        /** 下面是转向用到的数据 */
        private final int CHANGELEFT = -2;
        private final int CHANGERIGHT = 2;
        private final int CHANGEDOWN = -1;
        private final int CHANGEUP = 1;
        /** 分数:已经吃掉的食物总数 */
        public static int score = 0;
        /** 游戏的状态,并没有设置暂停 */
        private static int state;
        private static final int PLAYING = 0;
        private static final int GAMEOVER = 1;
        private static final String[] State = { "", "GameOver" };
    
        /** 在舞台上,不包括蛇体位置,通过修改col和row随机产生一个食物 */
        private void randomFood() {
            int col;
            int row;
            Random r = new Random();
            /* 在舞台内随机指定一个食物的位置,直到产生的位置不在蛇身上 */
            do {
                col = r.nextInt(COLS);
                row = r.nextInt(ROWS);
            } while (insideWorm(row, col));
            /* 设置食物的位置 */
            food.setCol(col);
            food.setRow(row);
    
        }
    
        /** 判断是否在蛇身上:用于随机产生食物判断 */
        private boolean insideWorm(int row, int col) {
            for (Cell cell : worm.getWorm()) {
                if (cell.getRow() == row && cell.getCol() == col)
                    return true;
            }
    
            return false;
        }
    
        /** 重写paint方法 */
        public void paint(Graphics g) {
            paintStage(g);// 画出背景
            paintFood(g);// 画出食物
            paintWorm(g);// 画出蛇
            paintState(g);// 画出游戏状态
            paintScore(g);// 画出分数
        }
    
        /** 分数的绘制方法 */
        private void paintScore(Graphics g) {
            String str = "得分:" + score;
            String len = "贪吃蛇长度:" + worm.getWorm().length;
            g.setColor(Color.black);
            Font font = g.getFont();
            Font f = new Font(font.getName(), font.getStyle(), 15);
            g.setFont(f);
            g.drawString(str, 325, 540);
            g.drawString(len, 325, 580);
    
        }
    
        /** 游戏状态的绘制方法 */
        private void paintState(Graphics g) {
            g.setColor(Color.white);
            Font font = g.getFont();
            Font f = new Font(font.getName(), font.getStyle(), 60);
            g.setFont(f);
    
            g.drawString(State[state], 100, 200);
        }
    
        /** 蛇的绘制方法 */
        private void paintWorm(Graphics g) {
            /* 利用for循环,遍历蛇的所有组成cell并画出 */
            for (Cell cell : worm.getWorm()) {
                g.setColor(cell.getColor());
                g.fillRect(cell.getCol() * SIZE, cell.getRow() * SIZE, SIZE, SIZE);
                g.setColor(Color.black);
                g.drawRect(cell.getCol() * SIZE, cell.getRow() * SIZE, SIZE, SIZE);
    
            }
    
        }
    
        /** 食物的绘制方法 */
        private void paintFood(Graphics g) {
            g.setColor(food.getColor());
            g.fillRect(food.getCol() * SIZE, food.getRow() * SIZE, SIZE, SIZE);
    
        }
    
        /** 背景的绘制方法 */
        private void paintStage(Graphics g) {
            g.setColor(Color.black);
            g.fillRect(0, 0, 500, 500);
    
            g.setColor(Color.white);
            g.fillRect(0, 500, 500, 100);
            g.setColor(Color.black);
            g.drawRect(0, 500, 499, 99);
            g.drawRect(0, 500, 299, 99);
            Font font = g.getFont();
            Font f = new Font(font.getName(), font.getStyle(), 15);
            g.setFont(f);
            g.drawString("↑←↓→控制移动,[S]重新开始", 20, 540);
            g.drawString("[Q]退出游戏", 30, 580);
    
        }
    
    
        /** 封装移动和转向方法,如果传入0,则前进 */
        private void moveAction(int changeNum) {
            
                
                /* 判断是否发生碰撞 */
                if (worm.isHit(changeNum)) {
                    /* 碰撞就结束游戏 */
                    state = GAMEOVER;
    
                } else {
                    /* 否则,转向并判断是否吃到食物 */
                    if (worm.move(food, changeNum)) {
                        /* 如果吃到就加分并随机产生一个食物 */
                        score++;
                        randomFood();
                    }
                }
            
        }
    
    
        
        /** action方法,整个游戏的控制方法 */
        private void action() throws Exception {
            /* 新建一个蛇 */
            worm = new Worm();
            /* 随机产生一个食物 */
            randomFood();
    
            /* 键盘控制:Q退出游戏;上下左右方向键控制蛇的移动;如果游戏结束,S重新开始游戏 */
            KeyListener l = new KeyAdapter() {
                public void keyPressed(KeyEvent e) {
                    int key = e.getKeyCode();
    
                    if (key == KeyEvent.VK_Q) {
    
                        System.exit(0);
                    }
                    /* 添加return,使得游戏结束,只有S键有效 */
                    if (state == GAMEOVER) {
                        if (key == KeyEvent.VK_S) {
                            restart();
                        }
                        return;
                    }
    
                    switch (key) {
                    case KeyEvent.VK_LEFT:
                        moveAction(CHANGELEFT);
    
                        break;
    
                    case KeyEvent.VK_RIGHT:
                        moveAction(CHANGERIGHT);
    
                        break;
    
                    case KeyEvent.VK_UP:
                        moveAction(CHANGEUP);
    
                        break;
    
                    case KeyEvent.VK_DOWN:
    
                        moveAction(CHANGEDOWN);
    
                        break;
    
                    }
    
                    repaint();
                }
    
            };
            this.addKeyListener(l);
            this.requestFocus();
            /* 死循环控制蛇的自动前进 */
            while (true) {
                if (state == PLAYING) {
                    moveAction(0);
    
                }
    
                repaint();
                Thread.sleep(500);
    
            }
        }
    
        /** 重新开始方法 */
        protected void restart() {
            /* 状态更改为PLAYING,new一个新的蛇,随机产生一个食物 */
            state = PLAYING;
            worm = new Worm();
            randomFood();
    
        }
    
        /** main方法,画出框体,面板并调用action方法启动游戏 */
        public static void main(String[] args) throws Exception {
            JFrame frame = new JFrame();
            WormStage wormStage = new WormStage();
            frame.setSize(500, 600);
    
            frame.add(wormStage);
            frame.setLocationRelativeTo(null);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setUndecorated(true);
            frame.setVisible(true);
            wormStage.action();
    
        }
    
    }
  • 相关阅读:
    Nginx log日志参数详解
    sea.js模块加载工具
    sea.js模块加载工具
    Airbnb React/JSX 编码规范
    4.2 react patterns(转)
    4.1 react 代码规范
    3.5 compose redux sages
    3.3 理解 Redux 中间件(转)
    3.4 redux 异步
    3.1 开始使用 redux
  • 原文地址:https://www.cnblogs.com/djavachen/p/3641764.html
Copyright © 2020-2023  润新知