麻烦JS中的逻辑运算符

时间:2014-06-27 21:34:53

标签: javascript canvas logical-operators

我正在尝试编写一个简单的2D平台游戏而且我无法让我的玩家对象双跳 - 或者更确切地说,我不能让他不去。当按下向上箭头或空格键时,无论如何都会触发双跳。我是一个JS新手所以我认为这与我使用逻辑运算符有关,但我可能是错的。这是代码:

(function() {
    var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
    window.requestAnimationFrame = requestAnimationFrame;
})();

var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    width = 500,
    height = 200,
    player = {
        x : width/2,
        y : height - 5,
        width : 5,
        height : 5,
        speed : 3,
        velX : 0,
        velY : 0,
        jumping : false,
        jumping_twice : false
    };
    keys = [],
    friction = 0.8,
    gravity = 0.3;

canvas.width = width;
canvas.height = height;

function update(){
    if (keys[38] || keys[32]) {
        // up arrow or space
        if (!player.jumping) {
            player.jumping = true;
            player.velY = -player.speed*2;
            console.log("Player is jumping");
        } 
        else if (!player.jumping_twice) {
            player.jumping_twice = true;
            player.velY = -player.speed;
            console.log("Player is jumping twice");
        }
    }
    if (keys[39]) {
        // right arrow
        if (player.velX < player.speed) {
            player.velX++;
        }
    }
    if (keys[37]) {
        // left arrow
        if (player.velX > -player.speed) {
            player.velX--;
        }
    }

    player.velX *= friction;
    player.velY += gravity;

    player.x += player.velX;
    player.y += player.velY;

    if (player.x >= width-player.width) {
        player.x = width-player.width;
    } else if (player.x <= 0) {
        player.x = 0;
    }

    if (player.y >= height-player.height) {
        player.y = height - player.height;
        player.jumping = false;
        player.jumping_twice = false;
    }

    ctx.clearRect(0,0,width,height);
    ctx.fillStyle = "red";
    ctx.fillRect(player.x, player.y, player.width, player.height);
    requestAnimationFrame(update);
}

window.addEventListener("load", function(){
    update();
})

document.body.addEventListener("keydown", function(e) {
    keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function(e) {
    keys[e.keyCode] = false;
});

3 个答案:

答案 0 :(得分:1)

这是因为update()在按住跳转键的同时多次运行;在释放密钥之前,一个接一个地满足这两个条件。您可以执行检查并在keydown处理程序中跳转角色以解决此问题,但最好将角色的更改保留在主循环中(在您的情况下为update())。为此,您需要一个额外的变量来确定玩家是否可以根据键状态的变化实际跳跃 - 当键被释放时,玩家可以再次跳跃或执行双跳。您可以为player提供一个名为can_jump的新属性,并将其初始设置为true。然后你可以这样做:

if (keys[38] || keys[32]) {
    // up arrow or space
    if (player.can_jump) {
        if (!player.jumping) {
            player.jumping = true;
            player.velY = -player.speed*2;
            player.can_jump = false; // the player can't jump anymore until the key is released
            console.log("Player is jumping");
        } 
        else if (!player.jumping_twice) {
            player.jumping_twice = true;
            player.velY = -player.speed;
            console.log("Player is jumping twice");
        }
    }

在keyup处理程序中:

if (e.keyCode == 32 || e.keyCode == 38) player.can_jump = true;

工作演示:http://jsfiddle.net/5JF69/

另外,请注意,游戏的速度取决于浏览器执行重绘的速度,因为您使用requestAnimationFrame()更新游戏逻辑。

编辑:如果空格键和向上键的状态不需要保持&#34; down&#34;在所有情况下,按键实际上都被按下(当前代码中没有),请参阅@ lordvlad的解决方案。如果您不对这些密钥执行任何其他检查,那肯定会更好。

答案 1 :(得分:1)

@rhino完全正确的解释。我有另一个解决方案。处理完跳转后,重置有关按下跳转键的信息:

keys[32] = keys[38] = false;
requestAnimationFrame(update);

答案 2 :(得分:0)

哈,我实际上是您正在使用的教程代码的作者。

所有的答案都是很好的答案,这就是我亲自做的。

if (keys[38] || keys[32]) {
    // up arrow or space
    if (!player.jumping) {
        player.jumping = true;
        player.velY = -player.speed*2;
        console.log("Player is jumping");
    } 
    else if(player.jumping && !player.jumping_twice) {
        player.jumping_twice = true;
        player.velY = -player.speed;
        console.log("Player is jumping twice");
    }
    keys[38] = keys[32] = false;
}

如果在支票本身中它们是真的,我会把键设置为假。

@lordvlad提出了一个很好的观点,应该有一个与渲染分开的更新周期,但是为了本教程的目的,它实际上只是让用户启动并运行以在屏幕上获取某些内容。在某些时候,我会做出第3部分来打破逻辑。无论如何希望这会有所帮助。

<强> Live Demo