【GUI】-- 12 贪吃蛇小游戏之让小蛇动起来

GUI编程

04 贪吃蛇小游戏

4.3 第三步:让小蛇动起来(键盘控制)

首先,在构造器中要获取焦点事件、键盘监听事件并加入定时器(定时器定义需要实现ActionListener接口并重写actionPerformed方法):

//构造器
    public GamePanel() {
        init();

        this.setFocusable(true);  //获取焦点事件
        this.addKeyListener(this);  //获取键盘监听事件
        timer.start();  //游戏一开始,定时器就启动

    }

然后,在键盘监听事件中,通过定时器来实现监听(即通过固定的时间进行刷新),并加入对上下左右按键的判断,以实现改变小蛇身体的对应走向:

//键盘监听事件
    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();  //获取键盘按键
        if (keyCode == KeyEvent.VK_SPACE) {
            isStart = !isStart;
            repaint();
        }

        //键盘监听到按键后画上对应方向的蛇头
        if (keyCode == KeyEvent.VK_UP) {
            direction = "U";
        } else if (keyCode == KeyEvent.VK_DOWN) {
            direction = "D";
        } else if (keyCode == KeyEvent.VK_LEFT) {
            direction = "L";
        } else if (keyCode == KeyEvent.VK_RIGHT) {
            direction = "R";
        }
    }

下面对实现ActionListener接口的actionPerformed方法进行重写:

//事件监听需要定时器来实现,即通过固定的时间进行刷新(例如1s=10次)
    @Override
    public void actionPerformed(ActionEvent e) {
        if (isStart) {
            //小蛇身体右移
            for (int i = length - 1; i > 0; i--) {  //后一节身体移动至前一节 snakeX[1] = snakeX[0]
                snakeX[i] = snakeX[i - 1];
                snakeY[i] = snakeY[i - 1];
            }

            //判断蛇头走向
            switch (direction) {
                case "R":
                    snakeX[0] += 25;
                    //边界判断
                    if (snakeX[0] > 850) {
                        snakeX[0] = 25;
                    }
                    break;
                case "L":
                    snakeX[0] -= 25;
                    //边界判断
                    if (snakeX[0] < 25) {
                        snakeX[0] = 850;
                    }
                    break;
                case "U":
                    snakeY[0] -= 25;
                    //边界判断
                    if (snakeY[0] < 75) {
                        snakeY[0] = 650;
                    }
                    break;
                case "D":
                    snakeY[0] += 25;
                    //边界判断
                    if (snakeY[0] > 650) {
                        snakeY[0] = 75;
                    }
                    break;
            }


            repaint();
        }
        timer.start();
    }

综上,GamePanel类中代码如下:

package com.duo.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.Objects;

//游戏的面板
public class GamePanel extends JPanel implements KeyListener, ActionListener {
    //定义蛇的数据结构
    int length;  //小蛇总长
    int[] snakeX = new int[600];  //蛇的X坐标 25*25
    int[] snakeY = new int[500];  //蛇的Y坐标 25*25
    String direction;  //蛇头方向
    boolean isStart = false;  //默认未开始游戏
    //定时器
    Timer timer = new Timer(250, this);  //100ms执行一次
    //构造器
    public GamePanel() {
        init();
        this.setFocusable(true);  //获取焦点事件
        this.addKeyListener(this);  //获取键盘监听事件
        timer.start();  //游戏一开始,定时器就启动
    }
    //初始化方法
    public void init() {
        length = 3;
        snakeX[0] = 100; snakeY[0] = 100;  //脑袋的坐标
        snakeX[1] = 75; snakeY[1] = 100;  //第一节身体的坐标
        snakeX[2] = 50; snakeY[2] = 100;  //第二节身体的坐标
        direction = "R";  //蛇头初始向右
    }
    //绘制静态面板
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);  //起到清屏的作用
        Data.header.paintIcon(this, g, 25, 11);  //将广告栏画入面板
        g.fillRect(25, 75, 850, 600);  //默认的游戏界面(黑色区域)
        this.setBackground(Color.white);
        //将小蛇画入面板中的游戏区域,且蛇头部分需要判断方向
        switch (direction) {
            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;
            case "D":
                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]);
        }
        //绘制当前游戏状态
        if (!isStart) {
            g.setColor(Color.white);
            g.setFont(new Font("宋体", Font.BOLD, 40));
            g.drawString("按下空格开始游戏", 300, 300);
        }
    }
    //键盘监听事件
    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();  //获取键盘按键
        if (keyCode == KeyEvent.VK_SPACE) {
            isStart = !isStart;
            repaint();
        }
        //键盘监听到按键后画上对应方向的蛇头
        if (keyCode == KeyEvent.VK_UP) {
            direction = "U";
        } else if (keyCode == KeyEvent.VK_DOWN) {
            direction = "D";
        } else if (keyCode == KeyEvent.VK_LEFT) {
            direction = "L";
        } else if (keyCode == KeyEvent.VK_RIGHT) {
            direction = "R";
        }
    }
    //事件监听需要定时器来实现,即通过固定的时间进行刷新(例如1s=10次)
    @Override
    public void actionPerformed(ActionEvent e) {
        if (isStart) {
            //小蛇身体右移
            for (int i = length - 1; i > 0; i--) {  //后一节身体移动至前一节 snakeX[1] = snakeX[0]
                snakeX[i] = snakeX[i - 1];
                snakeY[i] = snakeY[i - 1];
            }
            //判断蛇头走向
            switch (direction) {
                case "R":
                    snakeX[0] += 25;
                    //边界判断
                    if (snakeX[0] > 850) {
                        snakeX[0] = 25;
                    }
                    break;
                case "L":
                    snakeX[0] -= 25;
                    //边界判断
                    if (snakeX[0] < 25) {
                        snakeX[0] = 850;
                    }
                    break;
                case "U":
                    snakeY[0] -= 25;
                    //边界判断
                    if (snakeY[0] < 75) {
                        snakeY[0] = 650;
                    }
                    break;
                case "D":
                    snakeY[0] += 25;
                    //边界判断
                    if (snakeY[0] > 650) {
                        snakeY[0] = 75;
                    }
                    break;
            }
            repaint();
        }
        timer.start();
    }
    @Override
    public void keyReleased(KeyEvent e) {}
    @Override
    public void keyTyped(KeyEvent e) {}
}

运行结果如下:

游戏未开始时:

图1

未按方向键,小蛇默认一直向右移动直到边界,满足边界判断条件并重新回到界面左端:

图2

按下下键,小蛇向下移动:

图3

至此,小蛇可根据键盘按键进行对应方向的移动。此时还未加入食物,且当蛇头触碰蛇身时并不会触发游戏失败,这将在下一篇内容中给出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/173671.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

郎酒“掉队”,经销商们能等来春天吗?

文 | 螳螂观察&#xff08;TanglangFin&#xff09; 作者 | 渡过 有“六朵金花”之称的川酒品牌中&#xff0c;五粮液、泸州老窖、舍得、水井坊都已成功上市&#xff0c;只剩下郎酒和剑南春未上市。 与IPO的“掉队”相对应的&#xff0c;是郎酒在冲刺高端、内部管理、渠道管…

【LeetCode刷题-链表】--23.合并K个升序链表

23.合并K个升序链表 方法&#xff1a;顺序合并 在前面已经知道合并两个升序链表的前提下&#xff0c;用一个变量ans来维护以及合并的链表&#xff0c;第i次循环把第i个链表和ans合并&#xff0c;答案保存到ans中 /*** Definition for singly-linked list.* public class List…

SQL基础理论篇(八):视图

文章目录 简介创建视图修改视图删除视图总结参考文献 简介 视图&#xff0c;即VIEW&#xff0c;是SQL中的一个重要概念&#xff0c;它其实是一种虚拟表(非实体数据表&#xff0c;本身不存储数据)。 视图类似于编程中的函数&#xff0c;也可以理解成是一个访问数据的接口。 从…

VPX 插座(VITA46)介绍及应用 (简单介绍)

1. VPX 插座的介绍 VPX是VITA(VME International Trade Association, VME国际贸易协会)组织于2007年在其VME总线基础上提出的新一代高速串行总线标准。VPX总线的基本规范、机械结构和总线信号等具体内容均在ANSI/VITA46系列技术规范中定义。VPX就是基于高速串行总线的新一代总线…

基于Surfer与Voxler数据处理及可视化实践技术应用

Surfer和Voxler分别是美国Golden Software 公司开发的用于二维和三维数据可视化软件&#xff0c;具有强大的数据处理和插值功能&#xff0c;软件主要应用于气象、环境和地质&#xff08;以及生物、医学等&#xff09;等领域。其中Surfer主要用于绘制二维等值线图、三维表面图以…

仪表盘:pyecharts绘制

一、仪表盘 在数据分析中&#xff0c;仪表盘图&#xff08;dashboard&#xff09;的作用是以一种简洁、图表化的方式呈现数据的关键指标和核心信息&#xff0c;以帮助用户快速理解数据的情况&#xff0c;并从中提取关键见解。 仪表盘图通常由多个图表、指标和指示器组成&…

Java —— String类

目录 1. String类的重要性 2. 常用方法 2.1 字符串构造 2.2 String对象的比较 2.3 字符串查找 2.4 转化 1. 数值和字符串转化 2. 大小写转换 3. 字符串转数组 4. 格式化 2.5 字符串替换 2.6 字符串拆分 2.7 字符串截取 2.8 其他操作方法 2.9 字符串常量池 2.9.1 创建对象的思考…

基于安卓android微信小程序的刷题系统

项目介绍 面试刷题系统的开发过程中&#xff0c;采用B / S架构&#xff0c;主要使用jsp技术进行开发&#xff0c;中间件服务器是Tomcat服务器&#xff0c;使用Mysql数据库和Eclipse开发环境。该面试刷题系统包括会员、答题录入员和管理员。其主要功能包括管理员&#xff1a;个…

芯片IO口不加电阻会怎样?

芯片IO口不加电阻会怎样&#xff1f; 可能会导致以下几个后果&#xff1a; 1.高电流问题&#xff0c;IO口没有电阻限流&#xff0c;当与外部设备直接连接时&#xff0c;就可能会导致过大的电流流过IO口&#xff0c;这就可能损坏IO口&#xff0c;引起短路或烧坏其它电路组件。像…

Spring Boot要如何学习?【云驻共创】

Spring Boot 是由 Pivotal 团队提供的全新框架&#xff0c;其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置。我这里会分享一些学习Spring Boot的方法和干货&#xff0c;包括…

【C++】泛型编程 ⑨ ( 类模板的运算符重载 - 函数声明 和 函数实现 写在同一个类中 | 类模板 的 外部友元函数问题 )

文章目录 一、类模板 - 函数声明与函数实现分离1、函数声明与函数实现分离2、代码示例 - 函数声明与函数实现分离3、函数声明与函数实现分离 友元函数引入 二、普通类的运算符重载 - 函数声明 和 函数实现 写在同一个类中三、类模板的运算符重载 - 函数声明 和 函数实现 写在同…

Java实现windows系统截图

Java提供了一种方便的方式来截取Windows系统的截图。这个过程通常需要使用Java的Robot类来模拟用户的鼠标和键盘输入操作。下面将介绍如何使用Java实现Windows系统截图。 步骤1&#xff1a;导入Robot和AWT包 Java提供了一个Robot类&#xff0c;它可以模拟用户的键盘和鼠标操作…

医疗器械维修售后技术培训与支持的重要性

医疗器械维修售后技术培训与支持的重要性 随着我国医疗器械产业的的高速发展、医疗器械企业的崛起,大量创新医疗器械产品进入医疗机构。但医疗设备在使用和维护过程中,暴露出许多问题和不足,如部分设备故障率较高、临床工程培训不足、售后服务模式整体比较落后等,这影响了医疗…

当前系统并无桌面环境,或无显示器,无法显示远程桌面,您需要自行安装X11桌面环境,或者使用终端文件功能

ToDesk远程遇到的问题如上图&#xff0c;换向日葵直接黑屏&#xff1b; 问题原因 截止发文时间&#xff0c;Todesk只支持X11协议&#xff0c;没有适配最新的Wayland协议&#xff0c;所以我们需要把窗口系统调整为X11才可以。 解决方法 修改配置文件&#xff0c;关闭wayland su…

c# 文件读取和写入

文件写入 using System.Collections.Generic; namespace demo1;/// <summary> /// System.IO下的所有的Stream类是所有数据流的基类 /// 流是用于传输数据的对象&#xff0c;流就是用来传输数据的 /// 数据传输的两种方式&#xff1a;1、数据从外部源传输到程序中&#…

技术互联 创新交流 | 广汽研究院举办技术交流会圆满落幕

技术互联 创新交流 2023年11月1日&#xff0c;同星智能走进广汽研究院技术交流会圆满举行并落下帷幕。本次技术交流会得到广汽研究院相关部门的大力支持&#xff0c;并邀请到多名人员参与&#xff0c;涉及其技术、研发等部门。 本次活动的举办意义重大&#xff0c;目前广汽研究…

如何把A3 pdf 文章打印成A4

1. 用Adobe Acrobat 打开pdf 2 打印 选择海报 进行调整即可如下图,见下面红色的部分。

互联网医院源码搭建部署功能

互联网将医院与患者、医院内部&#xff08;医生、护士、领导层&#xff09;、医院与生态链上的各类组织机构连接起来。以患者为中心&#xff0c;优化医院业务流程&#xff0c;提升医疗服务质量与医院资源能效&#xff0c;让患者通过移动互联网随时随地的享受医院的服务&#xf…

练习八-利用有限状态机进行时序逻辑的设计

利用有限状态机进行时序逻辑的设计 1&#xff0c;任务目的&#xff1a;2&#xff0c;RTL代码&#xff0c;及原理框图3&#xff0c;测试代码&#xff0c;输出波形 1&#xff0c;任务目的&#xff1a; &#xff08;1&#xff09;掌握利用有限状态机实现一般时序逻辑分析的方法&am…

vue3中使用v-html解析后table表格的线不展示

在vue3中使用v-html展示富文本内容时&#xff0c;表格的框线不展示 在使用网上关于 ::v-deep /deep/ 各种用法之后&#xff0c;还是不生效 最后直接在scoped模式下的style&#xff0c;重新建一个&#xff0c;scoped模式会影响内部重新设置表格的样式