手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏07游戏输入管理

简介: 手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏07游戏输入管理

项目源码


项目源码


输入管理

package managers;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class InputManager implements KeyListener {
    private static InputManager singleton = null;
    protected InputManager() {
    }
    public static InputManager getInstance() {
         if(singleton==null) {
              singleton = new InputManager();
         }
         return singleton;
    }
    private int[] keys = new int[256];
    private boolean[] key_state_up = new boolean[256];
    private boolean[] key_state_down = new boolean[256];
    private boolean keyPressed = false;
    private boolean keyReleased = false; 
    private char keyChar;
    @Override
    public void keyTyped(KeyEvent e) {
    }
    public void keyPressed(KeyEvent e) {
        if( e.getKeyCode() >= 0 && e.getKeyCode() < 256 ) {
            keys[e.getKeyCode()] = (int) System.currentTimeMillis();
            key_state_down[e.getKeyCode()] = true;
            key_state_up[e.getKeyCode()] = false;
            keyPressed = true;
            keyReleased = false;
        }
    }
    public char getKeyChar(){
        return keyChar;
    }
    public void keyReleased(KeyEvent e) {
        if( e.getKeyCode() >= 0 && e.getKeyCode() < 256 ) {
            keys[e.getKeyCode()] = 0;
            key_state_up[e.getKeyCode()] = true;
            key_state_down[e.getKeyCode()] = false;
            keyChar = e.getKeyChar();
            keyPressed = false;
            keyReleased = true;
        }
    }
    public boolean isKeyDown( int key ) {
        return key_state_down[key];
    }
    public boolean isKeyUp( int key ) {
        return key_state_up[key];
    }
    public boolean isAnyKeyDown() {
        return keyPressed;
    }
    public boolean isAnyKeyUp() {
        return keyReleased;
    }
    public void update() {
        key_state_up = new boolean[256];
        keyReleased = false;
    }
}

InputManager类实现KeyListener接口,监听keyPressed键按下事件和keyReleased键释放事件。

接下来我们在game主循环中就可以调用isKeyDown和isKeyUp方法来查询是否某个键被按下或释放。并且我们在每一次游戏循环中

都需要调用update方法重新分配key_state_up数组,这样可以保证每次循环最多检测到一次isKeyUp。

下面是一个测试类。


InputManager测试类

package main;
import managers.InputManager;
import java.awt.*;
import java.awt.event.*;
/**
 * This is just a simple test example for the input manager snippet. It is
 * just a simple frame and a threaded loop that runs about every 16 milliseconds
 * or so which is 62.5 times per second.
 */
public class InputManagerTest extends Frame implements Runnable {
    // The test input manager
    private final InputManager input;
    // Used to only start the looping thread once.
    private boolean             isTestLoopRunning   = false;
    /**
     * Add the InputManager as the KeyListener to the Frame.
     */
    public InputManagerTest() {
        input = InputManager.getInstance();
        this.addKeyListener(input);
        this.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentShown(ComponentEvent e) {
                startTestLoop();
            }
        });
    }
    /**
     * Starts a new thread using this class as the Runnable instance for that
     * thread.
     */
    public void startTestLoop() {
        //only want to run once.
        if (!isTestLoopRunning) {
            (new Thread(this)).start();
            isTestLoopRunning = true;
        }
    }
    /**
     * The meat of the test to check and make sure the input manager is working
     * correctly.
     */
    @Override
    public void run() {
        System.out.println("Start Test Loop");
        //use this to test how many times the loop detects a key is down
        int count = 0;
        //run while the frame is showing
        while (this.isShowing()) {
            // run test cases
            if (input.isAnyKeyDown()) {
                System.out.println("Some key is down");
            }
            if (input.isAnyKeyUp()) {
                System.out.println("Some key is up");
            }
            if(input.isKeyDown(KeyEvent.VK_SPACE)) {
                ++count;
                System.out.println("Spacebar is down");
            }
            if(input.isKeyUp(KeyEvent.VK_SPACE)) {
                System.out.println("Spacebar is up");
                System.out.format("Spacebar detected down %d times\n", count);
                count = 0; //reset the counter
            }
            input.update();
            try {
                Thread.sleep(16);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } // just do a constant 16 milliseconds
        }
        System.out.println("End Test Loop");
    }
    /**
     * Main method to use to run the test from, it creates a basic awt frame and
     * displays the frame.
     * 
     * @param args Command line arguments.
     */
    public static void main(String[] args) {
        final Frame frame = new InputManagerTest(); //create our test class.
        // set a default size for the window, basically just give it some area.
        frame.setSize(640, 480);
        frame.setLocationRelativeTo(null); // centers window on screen
        // Need to add this to handle window closing events with the awt Frame.
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent arg0) {
                frame.setVisible(false);
                frame.dispose();
                System.exit(0);
            }
        });
        // show the frame
        frame.setVisible(true);
    }
}

该类不详细解释了,执行InputManagerTest,按一下空格键,得到以下输出:

Start Test Loop
Some key is down
Spacebar is down
Some key is down
Spacebar is down
Some key is down
Spacebar is down
Some key is down
Spacebar is down
Some key is down
Spacebar is down
Some key is down
Spacebar is down
Some key is up
Spacebar is up
Spacebar detected down 6 times
End Test Loop
Process finished with exit code 0

为什么检测到多次isKeyDown事件,而只有一次isKeyUp事件?

注意上面

input.update();


每次循环我们都会调用InputManager的update方法,重新分配key_state_up数组。

我们按下空格键这个短暂的时间,主循环循环了多次,但因为每次我们都重新分配了key_state_up数组,

故检测到多次isKeyDown事件,而只有一次isKeyUp事件。


目录
相关文章
|
2天前
|
缓存 安全 Java
《从头开始学java,一天一个知识点》之:输入与输出:Scanner与System类
你是否也经历过这些崩溃瞬间?三天教程连`i++`和`++i`都说不清,面试时`a==b`与`equals()`区别大脑空白,代码总是莫名报NPE。这个系列就是为你打造的Java「速效救心丸」!每天1分钟,地铁通勤、午休间隙即可学习。直击高频考点和实际开发中的“坑位”,拒绝冗长概念,每篇都有可运行代码示例。涵盖输入输出基础、猜数字游戏、企业编码规范、性能优化技巧、隐藏技能等。助你快速掌握Java核心知识,提升编程能力。点赞、收藏、转发,助力更多小伙伴一起成长!
30 19
|
3天前
|
缓存 安全 Java
《从头开始学java,一天一个知识点》之:字符串处理:String类的核心API
🌱 **《字符串处理:String类的核心API》一分钟速通!** 本文快速介绍Java中String类的3个高频API:`substring`、`indexOf`和`split`,并通过代码示例展示其用法。重点提示:`substring`的结束索引不包含该位置,`split`支持正则表达式。进一步探讨了String不可变性的高效设计原理及企业级编码规范,如避免使用`new String()`、拼接时使用`StringBuilder`等。最后通过互动解密游戏帮助读者巩固知识。 (上一篇:《多维数组与常见操作》 | 下一篇预告:《输入与输出:Scanner与System类》)
33 11
|
9天前
|
Java
课时14:Java数据类型划分(初见String类)
课时14介绍Java数据类型,重点初见String类。通过三个范例讲解:观察String型变量、&quot;+&quot;操作符的使用问题及转义字符的应用。String不是基本数据类型而是引用类型,但使用方式类似基本类型。课程涵盖字符串连接、数学运算与字符串混合使用时的注意事项以及常用转义字符的用法。
|
8天前
|
存储 Java 编译器
课时11:综合实战:简单Java类
本次分享的主题是综合实战:简单 Java 类。主要分为两个部分: 1.简单 Java 类的含义 2.简单 Java 类的开发
|
8天前
|
Oracle Java 关系型数据库
课时37:综合实战:数据表与简单Java类映射转换
今天我分享的是数据表与简单 Java 类映射转换,主要分为以下四部分。 1. 映射关系基础 2. 映射步骤方法 3. 项目对象配置 4. 数据获取与调试
|
6天前
|
搜索推荐 Java Android开发
课时146:使用JDT开发Java程序
在 Eclipse 之中提供有 JDT环境可以实现java 程序的开发,下面就通过一些功能进行演示。 项目开发流程
|
7天前
|
存储 监控 数据可视化
SaaS云计算技术的智慧工地源码,基于Java+Spring Cloud框架开发
智慧工地源码基于微服务+Java+Spring Cloud +UniApp +MySql架构,利用传感器、监控摄像头、AI、大数据等技术,实现施工现场的实时监测、数据分析与智能决策。平台涵盖人员、车辆、视频监控、施工质量、设备、环境和能耗管理七大维度,提供可视化管理、智能化报警、移动智能办公及分布计算存储等功能,全面提升工地的安全性、效率和质量。
|
16天前
|
存储 监控 Java
【Java并发】【线程池】带你从0-1入门线程池
欢迎来到我的技术博客!我是一名热爱编程的开发者,梦想是编写高端CRUD应用。2025年我正在沉淀中,博客更新速度加快,期待与你一起成长。 线程池是一种复用线程资源的机制,通过预先创建一定数量的线程并管理其生命周期,避免频繁创建/销毁线程带来的性能开销。它解决了线程创建成本高、资源耗尽风险、响应速度慢和任务执行缺乏管理等问题。
142 60
【Java并发】【线程池】带你从0-1入门线程池
|
5天前
|
存储 网络协议 安全
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
55 23
|
12天前
|
Java 调度
【源码】【Java并发】【线程池】邀请您从0-1阅读ThreadPoolExecutor源码
当我们创建一个`ThreadPoolExecutor`的时候,你是否会好奇🤔,它到底发生了什么?比如:我传的拒绝策略、线程工厂是啥时候被使用的? 核心线程数是个啥?最大线程数和它又有什么关系?线程池,它是怎么调度,我们传入的线程?...不要着急,小手手点上关注、点赞、收藏。主播马上从源码的角度带你们探索神秘线程池的世界...
81 0
【源码】【Java并发】【线程池】邀请您从0-1阅读ThreadPoolExecutor源码

热门文章

最新文章