【问题标题】:How to handle keyup events in main game loop?如何处理主游戏循环中的按键事件?
【发布时间】:2016-09-02 15:01:50
【问题描述】:

我正在用 JavaScript 编写一个简单的游戏,它已经像这样处理基本的键盘输入:

var input = {};
document.onkeydown = function(e) {
    input[e.keyCode] = true;
}
document.onkeyup = function(e) {
    input[e.keyCode] = false;
}

while (!done) {
    handleInput(input);
    update();
    render();
}

现在我需要游戏来处理组合键(例如 CTRL+X)。我希望它仅在keyup 上接受此类组合

编辑:修饰键不需要与“主”键同时全部向上。 /编辑

我想到的两种可能的解决方案是:

  • 公开包含keyup 事件列表的数组(带有“主”键和修饰符的对象)。 handleInput 函数将负责在每次轮询队列时清空队列
  • 跟踪handleInput 中可能的组合键(注意按住的修饰键)并在“主”键上升时触发组合行为(我实际上不太喜欢这样)

您能建议我用一种优雅的方式来扩展当前功能吗?

【问题讨论】:

  • 无论如何,好问题!

标签: javascript keyboard-shortcuts keyboard-events game-loop


【解决方案1】:

试试这个 ;) 当您按下 CTRL + X 并释放其中一个(或两个)时,它会出现一条消息

var map = {17: false, 88: false};
var fire_event = false;

window.addEventListener('keydown', function(e) {
    if (e.keyCode in map) {
        map[e.keyCode] = true;
        if (map[17] && map[88]) {
            fire_event = true;
        }
    }
}, false);

window.addEventListener('keyup', function(e) {
    if (e.keyCode in map) {
        map[e.keyCode] = false;
    }
    if (fire_event) {
        fire_event = false;
        alert('YOU PRESSED CTRL + X');
    }
}, false);

【讨论】:

  • 第一次可以用,但是在我再次按 ctrl+x 组合后它就失败了。
  • 现在试试,我做了一个更改...我没有看到指定为“仅在 keyup 上”。
  • 没有。如果我按CTRL + X + A 并让A 怎么办?或者CTRL + X 然后CTRL + C
【解决方案2】:

您所要做的就是创建upInput 变量,您将在其中存储您的keyup 键。然后,要检查组合是否被按下,您必须检查是否只有CTRL + C(或17、67)变量中的组合,如果它们都是true。然后轻松打印您的消息并重置upInput 变量。

var input = upInput = {};

document.onkeydown = function(e) {
    input[e.keyCode] = true;
    if (JSON.stringify(Object.keys(upInput)) != '["17","67"]')
        upInput = {};
}
document.onkeyup = function(e) {
    var k = e.keyCode;
    input[k] = false;
    if ([17, 67].indexOf(k) > -1)
        upInput[k] = true;
    if (JSON.stringify(Object.keys(upInput)) == '["17","67"]'
            && upInput[17] && upInput[67]) // CTRL + C
        alert('YES!'),
        upInput = {};
}

Demo

希望有帮助!

【讨论】:

  • 嗯...我可以说我不喜欢JSON.stringify(Object.keys(upInput)) == '["17","67"]' 位吗?另外,事件处理程序应该只是更新输入状态,应该由主循环中的handleInput 函数处理(我的问题中的代码是错误的,我要修复它)
  • @MarcoBolis JSON.stringify() 是最快的选择,否则我必须为对象原型制作一个自定义的.contains() 函数。据我所知,您不喜欢在事件侦听器中包含代码吗?那么这是不可能的。此外,您还没有声明 done 变量,因此您的 while 语句在当前代码中毫无意义。
  • 监听器内部的代码没问题,我们只需将 handling 部分取出,然后将其放入handleInput。关于我不喜欢的位,不是关于JSON.stringify(),只是我不相信Object.keys() 会按正确的顺序返回密钥!
  • @MarcoBolis 那么代码有什么问题?顺便说一句,要让键按正确的顺序排列,只需使用 .sort() 函数对它们进行排序:)
  • 既然你已经在检查upInput[17] && upInput[67],为什么不直接检查Object.keys(upInput).length === 2呢?更快、更干净、更快乐 ;-) 你也可以使用数组而不是普通对象,我在想...
【解决方案3】:

我会采用以下方式之一:

  • 检查 handleInput 部分中的组合(您的 第二种方法)
  • 保留最后 X 个键盘事件的列表(其中 X 是最大值 组合序列的长度)并检查此列表是否匹配 任何预定义的组合触发器

【讨论】:

    【解决方案4】:

    试试看是否可行:

    var KEY_QUEUE = [];
    var KEYs = [17, 88];
    
    document.onkeydown = function (e) {
        if (KEY_QUEUE.indexOf(e.keyCode) === -1) {
            KEY_QUEUE.push(e.keyCode);
        }
    };
    
    document.onkeyup = function (e) {
        var index = KEY_QUEUE.indexOf(e.keyCode);
        if ( isSubArray(KEYs, KEY_QUEUE) 
             && KEYs.indexOf(e.keyCode) > -1 ) {
            console.log("You press CTRL + X");
        }
        KEY_QUEUE.splice(index, 1);
    };
    
    function isSubArray(ary, targetAry) {
      return new RegExp(ary.toString()).test(targetAry.toString());
    }
    

    我检查了一些案例,例如Ctrl xx CtrlCtrl x aCtrl a x,它按我的预期工作。但我不确定它是否和你的想法一样。

    【讨论】:

    • 这个解决方案不是要求用户按照准确的顺序释放按键吗?
    • @Marco Bolis,它需要。 Ctrl x 会触发事件,x Ctrl 不会。如果你先按下 x 或 Ctrl,Ctrl a x 将不起作用,但如果你先按下 a 以将 Ctrlx 放在一起,它会起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多