在Javascript游戏中同时处理KeyEvents

时间:2016-06-23 17:37:27

标签: javascript javascript-events html5-canvas

我在Javascript中使用RPG并且正在为主播放器设置控件,但是我遇到了一些关于keyEvent处理的问题。此代码控制玩家移动和动画。我认为,出现问题的地方是,如果游戏在已经存在另一个keydown的同时注册了keydown,然后第一个键上升,则sprite暂停(isMoving属性基本上停止移动和动画,当它为false时)。 / p>

// For example:
// I hold W. Sprite begins moving up.
// While holding W, I begin to hold D. Sprite begins moving right.
// I release W. Sprite should keep going right, but pauses momentarily when the
// keyup is registered

var move = function(e) {

    xavier.isMoving = true;

    switch(e.keyCode)
    { 
        case 87: xavier.direction = 'up';    break; //W
        case 65: xavier.direction = 'left';  break; //A
        case 68: xavier.direction = 'right'; break; //D
        case 83: xavier.direction = 'down';  break; //S 
    };
};
var wait = function(e) {
    xavier.isMoving = false;
};    
window.addEventListener("keydown", move, false);
window.addEventListener("keyup", wait, false);

有没有更好的方法来设置控件,以便我的游戏可以同时处理多个键?

此外,当按下mac命令键时,精灵会移动。不知道为什么。预先感谢您的帮助。这是我在StackOverflow上的第一个问题。希望没关系。

4 个答案:

答案 0 :(得分:1)

您需要将关键事件与动画或主游戏循环取消关联。关键时刻,keyup事件是IO事件,不应该处理游戏逻辑,它们可以无论如何进入,你可能有很多帧之间,每个帧上应用逻辑只是浪费处理,更糟糕的是如果你有更多的逻辑参与玩家可能会错过逻辑事件,因为关键事件已经进行而没有主循环处理新位置。对于鼠标和触摸事件也是如此,您应该只记录事件并在游戏中处理它们。

// define keys and an array to keep key states
// global key log;
var keyState = [];
const KEY_UP = 38;
const KEY_DOWN = 40;
const KEY_LEFT = 37;
const KEY_RIGHT = 39;


// create a logging function
const keyEventLogger =  function (e) {  keyState[e.keyCode] = e.type == 'keydown';}
window.addEventListener("keydown", keyEventLogger);
window.addEventListener("keyup", keyEventLogger);


// define something to move
var player = {y : 100, x: 100};
const MOVE_SPEED = 2;

// in the main loop;
function update(timer) {
    if (keyState[KEY_UP]) {
        player.y -= MOVE_SPEED;
    } 
    if (keyState[KEY_DOWN]) {
        player.y += MOVE_SPEED;
    }
    if (keyState[KEY_LEFT]) {
        player.x -= MOVE_SPEED;
    }
    if (keyState[KEY_RIGHT]) {
        player.x += MOVE_SPEED;
    }
    requestAnimationFrame(update);

}
requestAnimationFrame(update);

答案 1 :(得分:0)

当然有。

您需要拥有一个数组和2个事件侦听器,一个用于keydown,另一个用于keyup

每当有人按下按钮时,将id与按钮的keyCode相同的元素设置为true。如果你的数组被称为keys,那么这看起来像这样:

keys[e.keyCode] = true;

然后,每当用户重新按钮时,将与该按钮的keyCode具有相同id的元素设置为false:

keys[e.keyCode] = false;

稍后,您可以检查,如果具有与按钮相同的ID的元素,则在您按下它之后发生特定事件是真的。

答案 2 :(得分:0)

var move = function(e) {

    xavier.isMoving = true;

    switch(e.keyCode)
    { 
        case 87: xavier.direction.up = true;    break; //W
        case 65: xavier.direction.left = true;  break; //A
        case 68: xavier.direction.right = true; break; //D
        case 83: xavier.direction.down = true;  break; //S 
    };
};
var wait = function(e) {
    switch(e.keyCode)
    { 
        case 87: xavier.direction.up = true;    break; //W
        case 65: xavier.direction.left = true;  break; //A
        case 68: xavier.direction.right = true; break; //D
        case 83: xavier.direction.down = true;  break; //S 
    };
    xavier.isMoving = xavier.direction.up ||
      xavier.direction.left || xavier.direction.right ||
      xavier.direction.down;
};    
window.addEventListener("keydown", move, false);
window.addEventListener("keyup", wait, false);

答案 3 :(得分:0)

这是一个解决方案,可以跟踪向下(方向)的键,并在释放第二个键时返回另一个向下(方向)的键。这两个函数非常相似,它们组合成一个:



var xavier = {};
xavier.isMoving = false;
xavier.stack = [];
xavier.direction = '';
xavier.directions = {
    87: 'up',    //W
    65: 'left',  //A
    68: 'right', //D
    83: 'down',  //S 
};

var move = function(e) {
    // get direction from mapping: key -> direction
    var direction = xavier.directions[e.keyCode];
    if (!direction) return; // not a move-key
    var i = xavier.stack.indexOf(direction);
    if (e.type === 'keydown' && i === -1) {
        // If this key was not yet down, but is pressed, 
        // then add the direction to the list
        xavier.stack.push(direction);
    } else if (e.type === 'keyup' && i !== -1) {
        // If this key was down, but is released, 
        // then remove the direction from the list
        xavier.stack.splice(i, 1);
    }
    xavier.direction = xavier.stack.length ? xavier.stack[xavier.stack.length-1]
                                           : '';
    xavier.isMoving = xavier.direction !== '';
    // Test for this snippet only:
    document.body.textContent = xavier.direction;
};

window.addEventListener("keydown", move, false);
window.addEventListener("keyup", move, false);

Click here (to focus) and press/release ASQW keys




请注意,理论上这可以支持任意数量的键,但实际上键盘通常仅限于可以关闭的数字。超过此限制后,不会生成任何关键事件。