使用 $().keydown 平滑平铺游戏角色移动

Smooth tiled game character movement with $().keydown

我想在我的 tile 游戏中实现角色移动,这样它就不会向服务器发送大量关键事件。目前我已经使用 setInterval 限制了发送的事件数量。

我的想法有问题:

  1. 如果玩家没有在正确的时间点击按键,移动可能无法正常工作

  2. 连续点击一个键(例如向右箭头),只会在 setInterval 拾取事件时发送键事件。这让它看起来有问题。

我的代码很好:

  1. 如果您只需要按住钥匙,它就能完美运行。

  2. 同时按住两个键可以沿对角线移动。代码存储正在按下的键。

可能有帮助的事情:

  1. 与其限制关键事件,不如去抖动效果更好。我只是不希望玩家乱按按键以比按住按键时移动得更快。 (我在去抖代码方面没有取得多大成功)

这是我的代码的精简基本示例:http://jsfiddle.net/empXx/66/

var canvas = document.getElementById('c'),
    ctx = canvas.getContext("2d"),
    tileSize = 10;
var holdingUp = false;
var holdingDown = false;
var holdingLeft = false;
var holdingRight = false;
var cx = 150;
var cy = 150;

$(document).keydown(function(e) {
    if(e.which==37) { holdingLeft = true; }
    if(e.which==38) { holdingUp = true; }
    if(e.which==39) { holdingRight = true; }
    if(e.which==40) { holdingDown = true;  }
});
$(document).keyup(function(e) {
    if(e.which==37) { holdingLeft = false; }
    if(e.which==38) { holdingUp = false; }
    if(e.which==39) { holdingRight = false; }
    if(e.which==40) { holdingDown = false; }
});

ctx.fillRect(150, 150, tileSize, tileSize);
setInterval(function() {
    if(holdingUp) {
        cls();
        ctx.fillRect(cx, cy - tileSize, tileSize, tileSize);
        cy -= tileSize;
    } else if(holdingDown) { 
        cls();
        ctx.fillRect(cx, cy + tileSize, tileSize, tileSize);
        cy += tileSize;
    }
    if(holdingLeft) {
        cls();
        ctx.fillRect(cx - tileSize, cy, tileSize, tileSize); 
        cx -= tileSize;
    } else if(holdingRight) {
        cls();
        ctx.fillRect(cx + tileSize, cy, tileSize, tileSize);
        cx += tileSize;
    }
}, 120);

function cls() { ctx.clearRect(0, 0, canvas.width, canvas.height); }

我怎样才能让这个游戏交互更流畅,让用户更愉快,同时减少垃圾邮件?

感谢 John S 的原始修复。我稍微修改了代码以使其更好。目前,如果用户同时按住左右键,播放器将不会移动。这是一个比根据按下键的顺序处理键优先级更简单的解决方案。我还做到了 upCount/downCount 等在 holdUp 和 holdDown 处于活动状态时无法更改。左右运动相同。

简单的 jsfiddle 与基本知识 here

使用此代码实现的生产游戏+反spam/cheat检测是here

JSFiddle 代码,按照 SO 的要求:

var canvas = document.getElementById('c'),
    ctx = canvas.getContext("2d"),
    tileSize = 10;
var holdingUp = false;
var holdingDown = false;
var holdingLeft = false;
var holdingRight = false;
var cx = 150;
var cy = 150;

var upCount = 0;
var downCount = 0;
var leftCount = 0;
var rightCount = 0;

$(document).keydown(function(e) {
    if(e.which==37 && !holdingLeft) { holdingLeft = true; leftCount++; }
    if(e.which==38 && !holdingUp) { holdingUp = true; upCount++; }
    if(e.which==39 && !holdingRight) { holdingRight = true; rightCount++; }
    if(e.which==40 && !holdingDown) { holdingDown = true; downCount++;  }
});
$(document).keyup(function(e) {
    if(e.which==37) { holdingLeft = false; }
    if(e.which==38) { holdingUp = false; }
    if(e.which==39) { holdingRight = false; }
    if(e.which==40) { holdingDown = false; }
});

ctx.fillRect(150, 150, tileSize, tileSize);
setInterval(function() {
    if(!(holdingUp && holdingDown)) {
        if((upCount > 0) || holdingUp) {
            if (upCount > 0) { upCount--; }
            cls();
            ctx.fillRect(cx, cy - tileSize, tileSize, tileSize);
            cy -= tileSize;
        } else if((downCount > 0) || holdingDown) { 
            if (downCount > 0) { downCount--; }
            cls();
            ctx.fillRect(cx, cy + tileSize, tileSize, tileSize);
            cy += tileSize;
        }
    } else {
        downCount = upCount = 0;
    }
    if(!(holdingLeft && holdingRight)) {
        if((leftCount > 0) || holdingLeft) {
            if (leftCount > 0) { leftCount--; }
            cls();
            ctx.fillRect(cx - tileSize, cy, tileSize, tileSize); 
            cx -= tileSize;
        } else if((rightCount > 0) || holdingRight) {
            if (rightCount > 0) { rightCount--; }
            cls();
            ctx.fillRect(cx + tileSize, cy, tileSize, tileSize);
            cx += tileSize;
        }
    } else {
        leftCount = rightCount = 0;
    }
}, 120);

function cls() { ctx.clearRect(0, 0, canvas.width, canvas.height); }