狂神说贪吃蛇小游戏的实现

狂神说的贪吃蛇 游戏

帧,如果时间片足够小,就是动画,一秒30帧 60帧,连起来就是动画,拆开就是静态的图片!

键盘监听

定时器timer


实现思路

  1. 将素材引入

  2. 创建一个窗口,导入头部图片

  3. 绘制一个850 * 900像素的游戏区域

  4. 导入贪吃蛇的头部(上下左右)和身体图片

  5. 导入食物素材用随机数方法让它在游戏区域内生成

  6. 创建空格的监听事件

  7. 判断失败的状态

首先创建一个java项目,在项目里我们创建开始游戏类(StartGame)和游戏界面类(GamePanel)还有存放外部数据的类(data)

StartGame类的代码

//游戏的主体启动类
public class StartGame {
    public static void main(String[] args) {
        //1.绘制一个静态窗口 JFrame
        JFrame frame = new JFrame("贪吃蛇小游戏");
        //设置界面大小
        frame.setBounds(10,10,900,720);
        frame.setResizable(false); // 窗口大小则不可以改变
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // 用户单击窗口的关闭按钮时程序执行的操作退出
​
        //2.面板 JPanel
        frame.add(new GamePanel()); // 新建一个对象添加游戏区域
        frame.setVisible(true);
​
    }
}

GamelPanel类的代码

各种变量的定义

public class GamePanel extends JPanel implements KeyListener, ActionListener {// 初始化
    int length; // 蛇的长度
    int[] snakeX = new int[700]; // 蛇的坐标X
    int[] snakeY = new int[600]; // 蛇的坐标Y
    String state; // R:右 L:左 U:上 D:下
    boolean isStart = false; // 游戏是否开始
    Timer timer = new Timer(300, this); //定时器
    int foodX; // 定义食物的坐标
    int foodY;
    Random random = new Random();
    boolean isFail = false; // 死亡判断
    int score; // 分数
}

写一个构造器方法实现初始化方法

注意setFocusable方法为将此 Component 的焦点状态设置为指定值。此值覆盖 Component 的默认焦点状态。

public GamePanel() {
        init();
        // 获取键盘的监听事件
        this.setFocusable(true);
        this.addKeyListener(this); // 让当前游戏区域实现键盘监听事件
        timer.start(); // 让时间动起来
    }

初始化

//初始化
    public void init() {
        length = 3;
        snakeX[0] = 110;
        snakeY[0] = 100;
        snakeX[1] = 85;
        snakeY[1] = 100;
        snakeX[2] = 60;
        snakeY[2] = 100;
        state = "R";
        foodX = 25 + 25 * random.nextInt(34); // 随机数范围为25 + 850的随机数
        foodY = 75 + 25 * random.nextInt(24); // 随机数范围为75 + 600的随机数
        int score = 0; // 默认积分为0分
    }

继承了JPanel需要重写painComponent方法

有一个类继承了了jpanel,然后在里面重写了paintcompaint,以实现设置jpanel中背景图的目的重写是为了将图片重新描绘在面板中

// 画板:画界面,画蛇
    //Grapics : 画笔
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g); //清屏
        this.setBackground(Color.WHITE);
​
        // 绘制头部的广告栏
        data.header.paintIcon(this, g, 25, 11);
​
        // 绘制游戏区域
        g.fillRect(25, 75, 850, 600);
​
        // 画一条小蛇
        switch (state) {
            case "R":
                data.right.paintIcon(this, g, snakeX[0], snakeY[0]);
                break;
            case "L":
                data.left.paintIcon(this, g, snakeX[0], snakeY[0]);
                break;
            case "U":
                data.up.paintIcon(this, g, snakeX[0], snakeY[0]);
                break;
            default:
                data.down.paintIcon(this, g, snakeX[0], snakeY[0]);
                break;
        }
        for (int i = 1; i < length; i++) {
            data.body.paintIcon(this, g, snakeX[i], snakeY[i]);
        }
        data.food.paintIcon(this, g, foodX, foodY); // 画随机的食物

实现keyListener接口要重写键盘的监听事件

//接收键盘的输入:监听
    @Override
    public void keyPressed(KeyEvent e) {
        // 键盘按下,未释放
        // 获取按下的键盘是哪个键
        int key = e.getKeyCode();
​
        if (key == KeyEvent.VK_SPACE) { // 如果按下的是空格键
            // 如果按下的是空格重新开始游戏
            if (isFail == true) { // 失败,游戏重新再来
                isFail = false;
                init(); // 重新初始化游戏
            } else {
                isStart = !isStart;
            }
            repaint(); //刷新界面
        }
        // 键盘控制方向
        if (key == KeyEvent.VK_LEFT) {
            state = "L";
        } else if (key == KeyEvent.VK_RIGHT) {
            state = "R";
        } else if (key == KeyEvent.VK_UP) {
            state = "U";
        } else if (key == KeyEvent.VK_DOWN) {
            state = "D";
        }
    }
    @Override
    public void keyTyped(KeyEvent e) {
        // 键盘按下,弹起:敲击
    }
​
    @Override
    public void keyReleased(KeyEvent e) {
        // 释放某个键
    }

要是想让小蛇动起来需要添加一个定时器,即每过1秒刷新10帧。。。因为我面的for循环除了脑袋都往前移:身体移动即第i节(后一节)的位置变为(i-1:前一节)节的位置!以此每刷新一次帧就会上下左右动起来。

// 定时器,监听时间,帧
    @Override
    public void actionPerformed(ActionEvent e) {
        // 如果游戏处于开始状态
        if (isStart == true && isFail == false) {
            // 右移
            for (int i = length - 1; i > 0; i--) {
                snakeX[i] = snakeX[i - 1]; // 身体移动
                snakeY[i] = snakeY[i - 1];
            }
            // 通过控制方向让头部移动
            if (state.equals("R")) {
                snakeX[0] = snakeX[0] + 25; // 头部移动
                // 边界判断
                if (snakeX[0] > 850) {
                    snakeX[0] = 25;
                }
            } else if (state.equals("L")) {
                snakeX[0] = snakeX[0] - 25;
                if (snakeX[0] < 25) {
                    snakeX[0] = 850;
                }
            } else if (state.equals("U")) {
                snakeY[0] = snakeY[0] - 25;
                if (snakeY[0] < 75) {
                    snakeY[0] = 650;
                }
            } else if (state.equals("D")) {
                snakeY[0] = snakeY[0] + 25;
                if (snakeY[0] > 650) {
                    snakeY[0] = 75;
                }
            }
            // 如果小蛇的头部和食物重合
            if (snakeX[0] == foodX && snakeY[0] == foodY) {
                //长度加一节
                length += 1;
                score += 10;
                // 刷新食物
                foodX = 25 + 25 * random.nextInt(34); // 随机数范围为25 + 850的随机数
                foodY = 75 + 25 * random.nextInt(24); // 随机数范围为75 + 600的随机数
//                snakeX[length - 1] = 999999; // 将增长的身体坐标移除到游戏区域外
//                snakeY[length - 1] = 999999;
                snakeX[length-1] = foodX-1;
                snakeY[length-1] = foodY-1;
            }
​
            // 如果小蛇碰到了身体
            for (int i = 1; i < length; i++) {
                if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
                    isFail = true;
                }
            }
            // 刷新界面
            repaint();
        }
        timer.start(); // 让时间动起来
    }

游戏开始失败和积分系统

// 游戏提示,是否开始
        if (isStart == false) {
            // 画一个文字,String
            g.setColor(Color.WHITE); //设置画笔颜色
            g.setFont(new Font("黑体", Font.BOLD, 40)); //画笔的字体风格
            g.drawString("按空格开始游戏", 300, 300);
        }
​
        // 失败提醒
        if (isFail == true) {
            // 画一个文字,String
            g.setColor(Color.RED);
            g.setFont(new Font("黑体", Font.BOLD, 40));
            g.drawString("游戏失败,按下空格重新开始游戏", 200, 300);
        }
        // 积分系统
        g.setColor(Color.WHITE);
        g.setFont(new Font("黑体", Font.BOLD, 18));
        g.drawString("长度:" + length, 750, 35);
        g.drawString("分数:" + score, 750, 50);
    }

data类的代码

//存入外部数据
public class data {
    // 头部的图片 URL
    public static URL headerURL = data.class.getResource("/statics/header.png");// URL:定位图片的地址
    public static ImageIcon header = new ImageIcon(headerURL); // 预加载图片
​
    // 头部
    public static URL upURL = data.class.getResource("/statics/up.png");
    public static URL downURL = data.class.getResource("/statics/down.png");
    public static URL rightURL = data.class.getResource("/statics/right.png");
    public static URL leftURL = data.class.getResource("/statics/left.png");
    public static ImageIcon up = new ImageIcon(upURL); // 预加载图片
    public static ImageIcon down = new ImageIcon(downURL); // 预加载图片
    public static ImageIcon right = new ImageIcon(rightURL); // 预加载图片
    public static ImageIcon left = new ImageIcon(leftURL); // 预加载图片
​
    // 身体
    public static URL bodyURL = data.class.getResource("/statics/body.png");
    public static ImageIcon body = new ImageIcon(bodyURL); // 预加载图片
​
    // 食物
    public static URL foodURL = data.class.getResource("/statics/food.png");
    public static ImageIcon food = new ImageIcon(foodURL); // 预加载图片
}

谢谢~~~!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值