【问题标题】:Check for key presses faster than game loop比游戏循环更快地检查按键
【发布时间】:2017-03-22 17:44:47
【问题描述】:

我有一个名为Activity 的类,它扩展了JPanel

我的问题是我希望Activity 每 1000 毫秒运行一次游戏循环(更新其字段和 GUI 等),但始终检查(以响应)按键。

private final BitSet keys = new BitSet(256);
...

public void keyPressed(final KeyEvent e) {
    keys.set(e.getKeyCode()); 
}

public void keyReleased(final KeyEvent e) {
    keys.clear(e.getKeyCode());
}

...

public void actionPerformed(ActionEvent e) {
  processKeys(); // Checks keys
  processData(); // Main game loop
  repaint();     // Draws game components
}

目前,该类将按键存储在 BitSet 中,并且每 1000 毫秒,actionPerformed() 会查看按下的按键(例如按下右箭头的右侧移动玩家位置),处理主游戏循环的内容(例如结束边界被击中时的游戏),并按该顺序重新绘制屏幕。

问题是我必须在计时器触发之前按下一个键才能检测到它,否则它将在调用processKeys() 时从BitSet 中删除。不过,我仍然希望游戏循环每 1000 毫秒运行一次。

我都考虑过

  1. 同时创建 2 个计时器 -- 1000 毫秒用于游戏循环,1 毫秒用于按键分析
  2. 将定时器设置为 1 毫秒,并使用类字段来跟踪定时器触发。每次开火时检查按键,仅在fires % 1000 == 0 时运行游戏循环/重绘

我不确定 #1 是否会产生性能问题或导致计时器差异,我很确定 #2 是不可靠的,因为当我尝试过时,该字段通常不会准确达到 1000 或 2000 等。

解决办法是什么?

【问题讨论】:

    标签: java swing user-interface timer


    【解决方案1】:

    正如您似乎发现的那样,由于按下键和处理它之间的延迟很长,因此有可能在处理之前从您的BitSet 中删除该键。

    相反,有两个BitSets,一个用于按下,一个用于释放键,在处理完这些键之后,从“按下的键”集中删除“释放的键”集中的所有项目,重置“释放键”设置并继续。

    当然,这假设您要处理在进程循环之间的 1 秒延迟期间键入的任何键。

    另一种选择可能是实时处理关键事件,将它们的效果应用于某种“更改状态”,当流程循环发生时,可以将其应用于实际模型,但相当于同一件事

    【讨论】:

    • 感谢您的回答。我将尝试您列出的第一个选项。至于第二个选项,我曾经这样做过,但根据answer here 和它下面的那个,我的印象是这是一种糟糕的事件处理实践。所以这不是真正的“同一件事”,对吧?
    猜你喜欢
    • 1970-01-01
    • 2014-04-24
    • 1970-01-01
    • 1970-01-01
    • 2014-01-21
    • 1970-01-01
    • 2022-12-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多