跟着大神学java第十五课,GUI编程(四)

GUI编程

查看上篇内容:
https://blog.csdn.net/weixin_42681553/article/details/121682018

贪吃蛇游戏

制作贪吃蛇需要:

  • 键盘监听
  • 定时器 Timer

思路分析

  1. 定义数据
    • 定义需要用到的属性(游戏是否开始,用来存放小蛇X轴和Y轴坐标的数组,小蛇的长度,小蛇运动的方向,事物的位置)
  2. 画在面板上
    • 根据小蛇长度和运动方向动态变化X轴和Y轴的值并在图片数据中展示头的方向
    • 通过 Graphics 画笔绘制小蛇和食物
  3. 增加监听事件
    1. 键盘监听事件
      • 监听键盘的上下左右和空格键,对应修改方向变量和暂停提示变量
    2. 事件监听事件
      • 判断游戏开始,让小蛇移动(从数组最后一个开始让身体可以移动,头的移动结合方向变量的判断确定变化量)
      • 判断食物的位置,是否和头重合,重合则小蛇长度增加,当前食物消失,并重新生成新的食物
      • 增加判断头是否和身体重合,重合则撞到自己,游戏结束

案例代码

主方法类

public class StartGame {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        //0.1游戏内容放在面板上
        frame.add(new GamePanel());
        frame.setVisible(true); //可见性
        frame.setBounds(100,100,900,720);//窗口大小
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);//关闭窗口
        frame.setResizable(false);//窗口不可变
    }
}

定义图片数据类

public class Data {
    //0.2相对路径定义图片路径
    //上
    public static URL upURL = Data.class.getResource("statics/up.png");	
    public static ImageIcon up = new ImageIcon(upURL);
    //下
    public static URL downURL = Data.class.getResource("statics/down.png");
    public static ImageIcon down = new ImageIcon(downURL);
    //左
    public static URL leftURL = Data.class.getResource("statics/left.png");
    public static ImageIcon left = new ImageIcon(leftURL);
    //右
    public static URL rightURL = Data.class.getResource("statics/right.png");
    public static ImageIcon right = new ImageIcon(rightURL);
    //身体
    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);
}

主要方法实现类

package com.kuang.snake;

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;

//游戏的面板,继承面板,实现监听类(不需要额外写class监听类)
public class GamePanel extends JPanel implements KeyListener, ActionListener {
    //0.3定义静态的蛇(长度,头,身体等初始属性)
    int length;     //蛇的长度
    int[] snakeX = new int[600];       //蛇的 X 坐标长度
    int[] snakeY = new int[600];       //蛇的 Y 坐标长度
    String direction;       //小蛇运动的方向

    boolean isStart;        //游戏开始 or 暂停
    boolean isFail;        //游戏是否失败
    int score;              //分数

    int foodX;          //食物的 X 坐标
    int foodY;          //食物的 Y 坐标
    Random random;      //用于食物位置的随机值

    //4.0定时器。以毫秒为单位,1000ms = 1s
    Timer timer = new Timer(100,this);

    //2.2构造器,初始化
    public GamePanel() {
        init();
        //3.2获取焦点和键盘事件
        this.setFocusable(true);    //获取鼠标焦点事件
        this.addKeyListener(this);      //获取键盘监听事件,因为实现了键盘监听类,所以不需要 new keylistener
        timer.start();      //游戏加载时就
    }

    //2.1初始化方法
    public void init(){
        length = 3;        //初始身体长度
        snakeX[0]=100; snakeY[0]=100;   //头的坐标
        snakeX[1]=75; snakeY[1]=100;   //头的坐标
        snakeX[2]=50; snakeY[2]=100;   //头的坐标
        direction = "right";   //头的方向
        isStart = false;    //初始游戏暂停
        isFail = false;
        score = 0;

        //4.2食物的坐标,根据随机数生成
        //带参的nextInt(int x)会生成一个范围在0~x(不包含X)内的任意正整数
        random = new Random();
        foodX = 25 + 25*random.nextInt(32);
        foodY = 75 + 25*random.nextInt(24);
    }

    //绘制面板
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);    //清屏,用来展示添加的贪吃蛇
        this.setBackground(Color.WHITE);    //背景

        //1.绘制静态面板
        g.setFont(new Font("微软雅黑",Font.BOLD,20));
        g.drawString("广告位招商进行中!!!", 350,40);
        g.fillRect(25,75,850,600);  //默认的游戏界面

        //绘制分数面板
        g.setColor(Color.green);
        g.setFont(new Font("微软雅黑",Font.BOLD,18));
        g.drawString("分数:"+score, 750,40);

        //4.2绘制食物图标s
        Data.food.paintIcon(this, g, foodX, foodY);
//        //2.3绘制静态小蛇身体
//        Data.body.paintIcon(this,g,snakeX[1],snakeY[1]);
//        Data.body.paintIcon(this,g,snakeX[2],snakeY[2]);
        //动态绘制身体,因为 body 是动态变化,所以通过 for 循环增加身体
        for (int i=1; i<length; i++){
            Data.body.paintIcon(this,g,snakeX[i],snakeY[i]);
        }
        //2.3绘制小蛇头
//        Data.right.paintIcon(this,g,snakeX[0],snakeY[0]);   //初始向右
        //动态变换头的方向
        if (direction.equals("right")){
            Data.right.paintIcon(this,g,snakeX[0],snakeY[0]);
        }else if (direction.equals("left")){
            Data.left.paintIcon(this,g,snakeX[0],snakeY[0]);
        }else if (direction.equals("up")){
            Data.up.paintIcon(this,g,snakeX[0],snakeY[0]);
        }else if (direction.equals("down")){
            Data.down.paintIcon(this,g,snakeX[0],snakeY[0]);
        }

        //2.4游戏暂停提示
        if (isStart==false){
            g.setColor(Color.WHITE);
            g.setFont(new Font("楷体 常规",Font.BOLD,40));
            g.drawString("按下空格开始/暂停游戏",250,300);
        }
        //4.3游戏失败判断
        if (isFail){
            g.setColor(Color.red);
            g.setFont(new Font("楷体 常规",Font.BOLD,40));
            g.drawString("游戏失败,点击空格重新开始",250,300);
        }
    }

    //3.1重写监听键盘按压事件
    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();

        if (keyCode == KeyEvent.VK_SPACE){      //按下空格
            if (isFail){        //4.3如果游戏结束时按下空格则从新开始,否则暂停
                this.init();
            }else {
                isStart = !isStart;     //不能写死(isStart = true),否则无法通过监听空格停止,所以取反
            }
            repaint();      //重新绘制面板
        }
        //3.1键盘的上下左右
        if (keyCode == KeyEvent.VK_UP){
            direction = "up";
        }else if (keyCode == KeyEvent.VK_DOWN){
            direction = "down";
        }else if (keyCode == KeyEvent.VK_LEFT){
            direction = "left";
        }else if (keyCode == KeyEvent.VK_RIGHT){
            direction = "right";
        }
    }

    //4.1定时器事件监听(通过固定事件刷新,例:每秒刷新 N 次)
    @Override
    public void actionPerformed(ActionEvent e) {
        //如果游戏是开始状态,就让小蛇动起来
        //需要先判断游戏是否暂停,然后依次移动身体,由尾巴开始,每一个向前移动,然后再移动头的位置
        //若先移动头的位置,则头的原本位置丢失,只记录了新的头的位置,则身体的第一节无法判断向何处移动
        if (isStart && isFail==false){
            //4.2吃食物,头的位置和食物位置重合,则身体长度 +1,并重新生成食物
            for (int i = 0; i < length-1; i++) {
                if (snakeX[i] == foodX && snakeY[i] == foodY){
                    length++;
                    score = (length-3)*5;
                    //食物的坐标,根据随机数生成
                    //带参的nextInt(int x)会生成一个范围在0~x(不包含X)内的任意正整数
                    foodX = 25 + 25 * random.nextInt(34);
                    foodY = 75 + 25 * random.nextInt(24);
                }
            }

            //4.0移动
            for (int i = length-1; i > 0 ; i--) {       //身体等于前一节的值,即可完成向前移动身体
                snakeX[i] = snakeX[i-1];
                snakeY[i] = snakeY[i-1];
            }

            //4.1方向,判断键盘按键
            if (direction.equals("right")){     //判断向右
                snakeX[0] = snakeX[0]+25;       //头的位置 +25 向右移动
                if (snakeX[0] == 875)           //穿越屏幕边界
                    snakeX[0] = 25;
            }else
            if (direction.equals("left")){      //判断向左
                snakeX[0] = snakeX[0]-25;       //头的位置 -25 向左
                if (snakeX[0] == 0)             //穿越屏幕边界
                    snakeX[0] = 850;
            }else
            if (direction.equals("up")){
                snakeY[0] = snakeY[0]-25;       //头的位置 Y 轴 -25向上
                if (snakeY[0] == 50)
                    snakeY[0] = 650;
            }else
            if (direction.equals("down")){
                snakeY[0] = snakeY[0]+25;       //头的位置 Y 轴 +25向下
                if (snakeY[0] == 675)
                    snakeY[0] = 75;
            }

            //4.3判断游戏失败,注释 for 循环即可成为无敌版
            for (int i = 1; i < length; i++) {
                if (snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i]){
                    isFail = true;
                }
            }
            repaint();      //重新绘制
        }
        timer.start();      //定时器启动
    }
    //以下是未使用到的键盘重构
    @Override
    public void keyReleased(KeyEvent e) { }
    @Override
    public void keyTyped(KeyEvent e) { }
}

总结

GUI编程

  • 定义
  • AWT
    • 组件
    • 容器
    • 面板
    • 事件监听
    • 文本框监听
    • 画图类paint(g)
    • 鼠标监听器
    • 窗口监听器
    • 键盘监听器
  • Swing
    • 容器
    • 面板(可带有滚动条)
    • label
      • 普通标签
      • 图片标签
      • 图像标签
    • 按钮
      • 普通按钮
      • 图片按钮
      • 单选框
      • 多选框
    • 列表
      • 下拉框
      • 列表框
    • 文本框
      • 普通文本框
      • 密码框
      • 文本域
  • 贪吃蛇
    • 定时器
    • 面板绘制
    • 键盘监听
    • 事件监听
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值