当前位置: 代码迷 >> 综合 >> JavaGUI 20 随机生成食物检测自身碰撞积分系统
  详细解决方案

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

热度:56   发布时间:2023-11-24 13:52:08.0

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++;//蛇身 + 1for(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++;//蛇身 + 1for(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 = 24foodX = 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;}//绘制面板,我们游戏中的所有东西,都是用画笔来 画@Overridepublic 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();//我们直接 就把 定时器 开启}//键盘监听事件@Overridepublic void keyTyped(KeyEvent e) {
    }@Overridepublic 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";}}@Overridepublic void keyReleased(KeyEvent e) {
    }@Overridepublic 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() {
    @Overridepublic 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++;//蛇身 + 1for(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 = 24foodX = 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;}}}
}

在这里插入图片描述