JAVA实现贪吃蛇游戏的实践记录(二)

  • 一、功能扩展报告
  • 二、预期功能展望
  • 三、程序代码展示



一、功能扩展报告

  • 使蛇体能够发生移动
  • 按键控制蛇体的转向
  • 游戏的启止控制
  • 食物的随机生成
  • 吃到食物蛇体增长
  • 吃到食物获得积分
  • 头撞到身体后失败
  • 蛇体的边界判断

二、预期功能展望

  • 问题优化:
  1. 优化蛇体死亡展示
  2. 限制蛇体转向
  • 功能补充:
  1. 蛇初始出现的随机性
  2. 增设食物种类
  3. 增设失败种类
  4. 设置自定义图标

三、程序代码展示

1:程序的入口

StartGame.java

代码如下:

package snakegame2;

import javax.swing.*;

//程序启动
public class StartGame2 {
    public static void main(String[] args) {
        //绘制静态窗口
        JFrame frame = new JFrame("贪吃蛇小游戏");
        //设置界面的宽高
        frame.setSize(965, 655);
        //屏幕中央弹出
        frame.setLocationRelativeTo(null);
        //窗口大小固定
        frame.setResizable(false);
        //关闭窗口时退出程序
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        //添加游戏面板
        frame.add(new GamePanel2());
        //设置窗体可见
        frame.setVisible(true);
    }
}

2:程序的主体

GamePanel.java

代码如下:

package snakegame2;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

//游戏面板
public class GamePanel2 extends JPanel implements KeyListener, ActionListener {

    //一、基本属性

    //定义蛇
    int length; //蛇体长度
    int[] snakeX = new int[800]; //蛇的坐标
    int[] snakeY = new int[800];
    String order; //方向,"R"(右),"L"(左),"U"(上),"D"(下);

    //定义食物
    int foodX; //食物的坐标
    int foodY;
    //实例化Random对象
    Random random = new Random();

    boolean isStart; //开始判断(默认暂停)
    boolean isFail; //死亡判断(默认存活)

    //初始化定时器
    Timer timer = new Timer(100, this);

    //设置积分系统
    int score; //积分
    int f = 50; //50分

    //二、初始化操作

    //定义构造器
    public GamePanel2() {
        init(); //调用初始化方法
        //获取键盘监听事件
        this.setFocusable(true); //对窗口设置键盘焦点
        this.addKeyListener(this); //添加监听器
        //启动定时器
        timer.start();
    }

    //定义初始化方法
    public void init() {

        length = 3; //初始化蛇长(3节)
        score = 0; //积分清零

        snakeX[0] = 100; //初始化蛇位置
        snakeY[0] = 75;
        snakeX[1] = 75;
        snakeY[1] = 75;
        snakeX[2] = 50;
        snakeY[2] = 75;

        order = "R"; //初始化蛇头方向

        //随机生成食物位置
        foodX = 25 + 25 * random.nextInt(36);
        foodY = 50 + 25 * random.nextInt(22);
    }

    //三、画板部分:执行绘制操作

    @Override
    protected void paintComponent(Graphics g) {

        //画界面
        super.paintComponent(g); //清屏操作
        this.setBackground(Color.white); //设置背景颜色

        //绘制游戏区域
        g.setColor(Color.black);
        g.fillRect(25, 50, 900, 550);

        //画积分
        g.setColor(Color.black); //设置字体颜色
        g.setFont(new Font("微软雅黑", Font.BOLD, 25));
        g.drawString("分数:" + (score) + "分", 770, 25);

        //根据当前的方向(order)画蛇头
        switch (order) {
            case "R":
                Data2.right.paintIcon(this, g, snakeX[0], snakeY[0]);
                break;
            case "L":
                Data2.left.paintIcon(this, g, snakeX[0], snakeY[0]);
                break;
            case "U":
                Data2.up.paintIcon(this, g, snakeX[0], snakeY[0]);
                break;
            case "D":
                Data2.down.paintIcon(this, g, snakeX[0], snakeY[0]);
                break;
        }

        //画蛇身
        for (int i = 1; i < length; i++) {
            Data2.body.paintIcon(this, g, snakeX[i], snakeY[i]);
        }

        //画食物
        Data2.food.paintIcon(this, g, foodX, foodY);

        //交互设置

        //游戏开始提示语句(游戏暂停时)
        if (!isStart) {
            g.setColor(Color.white);
            g.setFont(new Font("微软雅黑", Font.BOLD, 25));
            g.drawString("按空格键开始游戏", 370, 340);
        }

        //游戏结束提示语句(游戏失败时)
        if (isFail) {
            g.setColor(Color.white);
            g.setFont(new Font("微软雅黑", Font.BOLD, 25));
            g.drawString("游戏结束,本次得分:" + (score) + "分,按空格键重新开始", 230, 340);
        }
    }

    //四、监听器部分:执行键盘操作

    @Override
    //键盘按下(未释放)
    public void keyPressed(KeyEvent e) {
        //接收键盘的输入
        int keyCode = e.getKeyCode();

        //若按下了空格键
        if (keyCode == KeyEvent.VK_SPACE) {
            //如果结束,按下空格键重新开始
            if (isFail) {
                isFail = false;
                init(); //重新做初始化
            } else {
                //按下空格键开始/暂停游戏
                isStart = !isStart;
            }
            //刷新(重画)界面
            repaint();
        }

        //('W'/'S'/'A'/'D'键或'up'/'down'/'left'/'right'键)按键控制蛇头转向
        if (keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_A) {
            order = "L";
        } else if (keyCode == KeyEvent.VK_RIGHT || keyCode == KeyEvent.VK_D) {
            order = "R";
        } else if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_W) {
            order = "U";
        } else if (keyCode == KeyEvent.VK_DOWN || keyCode == KeyEvent.VK_S) {
            order = "D";
        }
    }

    //五、定时器部分:执行定时操作

    @Override
    public void actionPerformed(ActionEvent e) {
        //若游戏处于开始状态(且游戏未失败)-->蛇发生移动
        if (isStart && !isFail) {
            //蛇身移动
            for (int i = length - 1; i > 0; i--) {
                snakeX[i] = snakeX[i - 1];
                snakeY[i] = snakeY[i - 1];
            }
            //蛇头移动
            switch (order) {
                case "R":
                    snakeX[0] += 25;
                    break;
                case "L":
                    snakeX[0] -= 25;
                    break;
                case "U":
                    snakeY[0] -= 25;
                    break;
                case "D":
                    snakeY[0] += 25;
                    break;
            }

            //边界判断
            if (snakeX[0] > 900 || snakeX[0] < 25 || snakeY[0] < 50 || snakeY[0] > 575) {
                if (snakeX[0] > 900) {
                    snakeX[0] = 25;
                } else if (snakeX[0] < 25) {
                    snakeX[0] = 900;
                } else if (snakeY[0] < 50) {
                    snakeY[0] = 575;
                } else {
                    snakeY[0] = 50;
                }
            }

            //游戏失败判定

            //蛇头碰到蛇身后失败(循环判定蛇头坐标是否与任一节蛇身重合)
            for (int i = 1; i < length; i++) {
                if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
                    //判定为失败
                    isFail = true;
                    break;
                }
            }

            //蛇吃到食物(坐标重合)后增长/积分
            if (snakeX[0] == foodX && snakeY[0] == foodY) {
                length++; //蛇身长度加一
                score += f; //食物积分

                //重新生成食物位置
                foodX = 25 + 25 * random.nextInt(36);
                foodY = 50 + 25 * random.nextInt(22);
            }
            //刷新(重画)界面
            repaint();
        }
        //启动定时器
        timer.start();
    }

    @Override
    public void keyTyped(KeyEvent keyEvent) {
    }

    @Override
    public void keyReleased(KeyEvent keyEvent) {
    }
}

3:存放图片资源

Data.java

代码如下:

package snakegame2;

import javax.swing.*;
import java.net.URL;

//存放数据
public class Data1 {

    //导入素材图片

	//蛇头图片
    private static final URL upURL = Data2.class.getResource("/resources2/up2.jpg"); //上
    private static final URL leftURL = Data2.class.getResource("/resources2/left2.jpg"); //左
    private static final URL rightURL = Data2.class.getResource("/resources2/right2.jpg"); //右
    private static final URL downURL = Data2.class.getResource("/resources2/down2.jpg"); //下
    public static ImageIcon up = new ImageIcon(upURL);
    public static ImageIcon left = new ImageIcon(leftURL);
    public static ImageIcon right = new ImageIcon(rightURL);
    public static ImageIcon down = new ImageIcon(downURL);
    
    //蛇身图片
    private static final URL bodyURL = Data2.class.getResource("/resources2/body2.jpg");
    public static ImageIcon body = new ImageIcon(bodyURL);
    
    //食物图片
    private static final URL foodURL = Data2.class.getResource("/resources2/food2.jpg");
    public static ImageIcon food = new ImageIcon(foodURL);
}