[苦逼程序员成长之路]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();

    }

}
原文地址:https://www.cnblogs.com/djavachen/p/3641764.html