JavaGUI 20 随机生成食物&&检测自身碰撞&&积分系统

8.4 随机生成食物&&检测自身&&积分系统


8.4.1 随机生成食物

我们在写随机生成食物之前,要学习一个 Math下面的方法,叫做 radom()。

Math.radom() * 最大范围数 就可以取到 0 ~ 最大范围数的 随机双浮点数数字!切记,返回的是双浮点数字,而并非 整数,如果你要求的是整数!请用 int 进行强转。

  • 我们知道,X 轴方向的格子 是 850 / 25 = 34个
  • 我们知道,Y 轴方向的格子 是 600 / 25 = 24个

所以我们可以 先随机的取 x轴和y轴的 第几个格子,然后再计算坐标值,这样就可以获取到 随机的食物坐标了!

foodX = 25 + ((int)(1+Math.random()*(34))) * 25;
foodY = 75 + ((int)(1+Math.random()*(24))) * 25;
  • 如果 蛇头坐标和现在食物坐标相同

那么就证明,我们要进行 吃 食物的操作。

  1. 蛇身长度 + 1
  2. 把所有坐标往后移动一位,把食物坐标当作蛇头的坐标,进行坐标的更新!
 if(snakeX[0] == foodX && snakeY[0] == foodY)
            {
                //更新蛇身
                length++;//蛇身 + 1

                for(int i = length -1;i>0;--i)
                {
                    //把所有坐标往后移动一位
                    snakeX[i] = snakeX[i-1];
                    snakeY[i] = snakeX[i-1];
                }
                snakeX[0] = foodX;
                snakeY[0] = foodY;
}
  • 随机生成食物避免与蛇身位置重复
  1. 我们需要有个死循环,来一直检测 现在生成的随机食物坐标是否 不与 蛇身位置重复!
  2. 而检测 是否重复的时候,需要 遍历 所有的蛇身,包括 蛇头的 坐标,所以在死循环的内部,还要嵌套一个 for 循环。
  3. 利用 Lael: 标签跳转,实现 当 有坐标和食物坐标重复时,重新随机生成食物的坐标,再跳转到 死循环的首部,进行重检测。
boolean flag = false;

                Label:while(!flag)
                {
                    for(int i = 0;i<length;++i)
                    {
                        if(snakeX[i] == foodX || snakeY[i] == foodX)
                        {
                            flag = false;
                            foodX = 25 + ((int)(1+Math.random()*(34-1+1))) * 25;
                            foodY = 75 + ((int)(1+Math.random()*(24-1+1))) * 25;
                            continue Label;
                        }
                    }
                    flag = true;
                }
  • 整体代码
//如果吃到了食物,我们就进行随机生成
            if(snakeX[0] == foodX && snakeY[0] == foodY)
            {
                //更新蛇身
                length++;//蛇身 + 1

                for(int i = length -1;i>0;--i)
                {
                    //把所有坐标往后移动一位
                    snakeX[i] = snakeX[i-1];
                    snakeY[i] = snakeX[i-1];
                }
                snakeX[0] = foodX;
                snakeY[0] = foodY;

                //随机再生成一个
                // 850 / 25 = 34    600 / 25 = 24
                foodX = 25 + ((int)(1+Math.random()*(34))) * 25;
                foodY = 75 + ((int)(1+Math.random()*(24))) * 25;
                boolean flag = false;

                Label:while(!flag)
                {
                    for(int i = 0;i<length;++i)
                    {
                        if(snakeX[i] == foodX || snakeY[i] == foodX)
                        {
                            flag = false;
                            foodX = 25 + ((int)(1+Math.random()*(34-1+1))) * 25;
                            foodY = 75 + ((int)(1+Math.random()*(24-1+1))) * 25;
                            continue Label;
                        }
                    }
                    flag = true;
                }


            }

8.4.2 检测自身碰撞

当自身碰撞的时候,就意味着 吃到了自己,那么游戏就会失败!此时 需要 把 isStart = false,再 调用 init() 初始化 函数!让其重新 加载游戏。

需要 做的是,判断 蛇头的坐标是否 与 蛇身的坐标 相等,如果相等 则 为 自身碰撞!

//检测自身碰撞
            for(int i =1;i<length;++i)
            {
                if(snakeX[0] == snakeX[i] && snakeY[i] == snakeY[0])
                {
                    isStart = false;
                    JDialog jDialog = new JDialog();
                    jDialog.setBounds(500,500,400,200);
                    jDialog.setVisible(true);
                    jDialog.setTitle("信息框");
                    JLabel label = new JLabel("这都能吃到自己?你的游戏失败!");
                    Font font = new Font("微软雅黑",Font.PLAIN,20);
                    label.setFont(font);
                    label.setBounds(20,20,400,100);
                    jDialog.setLayout(null);
                    jDialog.add(label);

                    try {
                        add(jDialog);
                    }catch (Exception HH)
                    {
                        init();
                    }
                    init();
                }
            }

这里就是 添加了 一个 dialog 信息框窗口,显得 更加的 完美!


8.4.3 积分系统

这个其实也很简单哈~ 就是 再画两个 String 字符串 显示 出来。就是 什么 积分系统了。因为 咱们还没学 文件操作呢,所以 存 不了数据。

 //画积分系统
        Color color = g.getColor();
        g.setColor(Color.white);
        Font font = new Font("微软雅黑",Font.PLAIN,18);
        g.setFont(font);
        g.drawString("当前蛇身长度:"+length, 700,50 );
        g.setColor(color);
  • GamePanel 全部代码!
package com.muquanyu.snake;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class GamePanel extends JPanel implements KeyListener, ActionListener {

    //蛇的长度
    int length;
    //蛇头的 X坐标 和 Y坐标
    int[] snakeX = new int[900];
    int[] snakeY = new int[900];
    //蛇头方向
    String snakeDirection = null;
    //游戏当前的状态:开始、停止 默认为 "停止"
    boolean isStart = false;
    //创建一个时钟 进行 监听
    Timer timer = new Timer(100,this);

    //食物的 X坐标 和 Y坐标
    int foodX;
    int foodY;

    //定义积分变量
    int score = 0;

    //初始化
    public void init() {
        //初始化蛇的长度
        length = 3;
        //初始化蛇头 坐标
        snakeX[0] = 125;snakeY[0] = 100;
        //初始化蛇身 坐标
        snakeX[1] = 100;snakeY[1] = 100;
        snakeX[2] = 75;snakeY[2] = 100;
        //蛇头方向
        snakeDirection = "right";
        //初始化食物 坐标
        foodX = 500;
        foodY = 250;

    }

    //绘制面板,我们游戏中的所有东西,都是用画笔来 画
    @Override
    public void paintComponent(Graphics g) {
        //清屏,不会出现闪烁。
        super.paintComponent(g);
        //绘制静态的面板
        this.setBackground(Color.BLACK);
        //第一个参数是画到哪个设备上,那肯定是我们 创建的 面板上呀!
        Data.header.paintIcon(this, g, 25, 11);
        //画积分系统
        Color color = g.getColor();
        g.setColor(Color.white);
        Font font = new Font("微软雅黑",Font.PLAIN,18);
        g.setFont(font);
        g.drawString("当前蛇身长度:"+length, 700,50 );
        g.setColor(color);
        //画游戏区域
        g.fillRect(25, 75, 850, 600);

        //画静态小蛇
        switch(snakeDirection)
        {
            case "right":
                Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);
                break;
            case "left":
                Data.left.paintIcon(this, g, snakeX[0], snakeY[0]);
                break;
            case "up":
                Data.up.paintIcon(this, g, snakeX[0], snakeY[0]);
                break;
            case "down":
                Data.down.paintIcon(this, g, snakeX[0], snakeY[0]);
                break;
            default:break;
        }

        for(int i = 1;i<length;++i)
        {
            Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);
        }

        //游戏状态
        if(!isStart)
        {
            g.setColor(Color.white);
            //设置字体
            Font 微软雅黑 = new Font("微软雅黑", Font.BOLD, 40);
            g.setFont(微软雅黑);
            g.drawString("按下空格开始游戏",300,300);
        }

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

    }

    public GamePanel() {
            init();
            //获得焦点和键盘事件
        this.setFocusable(true);//获得焦点事件
        this.addKeyListener(this);//获得键盘监听事件
        timer.start();//我们直接 就把 定时器 开启

    }

    //键盘监听事件
    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        if(keyCode == KeyEvent.VK_SPACE)
        {
            System.out.println("按下了空格!");
            isStart = !isStart;
            repaint();//开始重画
        }
        if(keyCode == KeyEvent.VK_UP)
        {
            System.out.println("上方向键!");
            snakeDirection = "up";
        }
        if(keyCode == KeyEvent.VK_DOWN)
        {
            System.out.println("下方向键!");
            snakeDirection = "down";
        }
        if(keyCode == KeyEvent.VK_LEFT)
        {
            System.out.println("左方向键!");
            snakeDirection = "left";
        }
        if(keyCode == KeyEvent.VK_RIGHT)
        {
            System.out.println("右方向键!");
            snakeDirection = "right";
        }

    }

    @Override
    public void keyReleased(KeyEvent e) {

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        //如果游戏开始的话
        if(isStart)
        {
            //宽度:850 高度:600

            //检测自身碰撞
            for(int i =1;i<length;++i)
            {
                if(snakeX[0] == snakeX[i] && snakeY[i] == snakeY[0])
                {
                    isStart = false;
                    JDialog jDialog = new JDialog();
                    jDialog.setBounds(500,500,400,200);
                    jDialog.setVisible(true);
                    jDialog.setTitle("信息框");
                    JLabel label = new JLabel("这都能吃到自己?你的游戏失败!");
                    Font font = new Font("微软雅黑",Font.PLAIN,20);
                    jDialog.addKeyListener(new KeyAdapter() {

                        @Override
                        public void keyPressed(KeyEvent e) {
                            super.keyPressed(e);
                            if(e.getKeyCode() == KeyEvent.VK_SPACE)
                            {
                                jDialog.dispose();
                            }
                        }
                    });
                    label.setFont(font);
                    label.setBounds(20,20,400,100);
                    jDialog.setLayout(null);
                    jDialog.add(label);

                    init();
                }
            }



            //如果吃到了食物,我们就进行随机生成
            if(snakeX[0] == foodX && snakeY[0] == foodY)
            {
                //更新蛇身
                length++;//蛇身 + 1

                for(int i = length -1;i>0;--i)
                {
                    //把所有坐标往后移动一位
                    snakeX[i] = snakeX[i-1];
                    snakeY[i] = snakeX[i-1];
                }
                snakeX[0] = foodX;
                snakeY[0] = foodY;

                //随机再生成一个
                // 850 / 25 = 34    600 / 25 = 24
                foodX = 25 + ((int)(1+Math.random()*(34))) * 25;
                foodY = 75 + ((int)(1+Math.random()*(24))) * 25;
                boolean flag = false;

                Label:while(!flag)
                {
                    for(int i = 0;i<length;++i)
                    {
                        if(snakeX[i] == foodX || snakeY[i] == foodX)
                        {
                            flag = false;
                            foodX = 25 + ((int)(1+Math.random()*(34-1+1))) * 25;
                            foodY = 75 + ((int)(1+Math.random()*(24-1+1))) * 25;
                            continue Label;
                        }
                    }
                    flag = true;
                }


            }

            switch(snakeDirection)
            {
                case "right":
                {
                    if(snakeX[0] == 850)
                    {
                        //那就直接让它 从左边 穿过来就行了
                        snakeX[0] = 25;
                    }
                    else{
                        //编程思想的写法,并不是什么高深算法!
                        //我们通过自己画图,也会发现这个 现象
                        //就是 蛇身的每一块 在移动的时候,恰好移动到了 前一个块的坐标!!!
                        //你们 自己画图 观察,就能看出来!那么我们只需要 从 最后一块 开始遍历
                        //然后 让它每次刷新 都 变成 前一块的 坐标不就完事了!!
                        for(int i = length-1;i>0;i--)
                        {
                            snakeX[i] = snakeX[i-1];
                            snakeY[i] = snakeY[i-1];
                        }
                        snakeX[0] = snakeX[0] + 25;
                    }
                    repaint();
                    break;
                }
                case "left":
                {
                    if(snakeX[0] == 25)
                    {
                        snakeX[0] = 850;
                    }
                    else{
                        for(int i = length-1;i>0;i--)
                            {
                                snakeX[i] = snakeX[i-1];
                                snakeY[i] = snakeY[i-1];
                            }
                        snakeX[0] = snakeX[0] - 25;
                    }
                    repaint();
                    break;
                }
                case "up":
                {
                    if(snakeY[0] == 75)
                    {
                        snakeY[0] = 600;
                    }
                    else{
                        for(int i = length-1;i>0;i--)
                        {
                            snakeX[i] = snakeX[i-1];
                            snakeY[i] = snakeY[i-1];
                        }
                        snakeY[0] = snakeY[0] - 25;
                    }
                    repaint();
                    break;
                }
                case "down":
                {
                    if(snakeY[0] == 650)
                    {
                        snakeY[0] = 75;
                    }
                    else{
                        for(int i = length-1;i>0;i--)
                        {
                            snakeX[i] = snakeX[i-1];
                            snakeY[i] = snakeY[i-1];
                        }
                        snakeY[0] = snakeY[0] + 25;
                    }
                    repaint();
                    break;
                }
                default:break;
            }

        }

    }
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值