【问题标题】:Trouble with logical operators in JSJS中逻辑运算符的问题
【发布时间】:2014-06-27 21:34:53
【问题描述】:

我正在尝试编写一个简单的 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;
});

【问题讨论】:

  • 我认为这不是逻辑运算符的问题,而是 requestAnimationFrame 调用下一个更新的速度比您释放跳转键的速度更快。
  • 刚刚检查过了。在requestAnimationFrame(update)之前设置keys[32] = keys[38] = false

标签: javascript canvas logical-operators


【解决方案1】:

@rhino 的解释完全正确。不过我有另一个解决方案。跳转完成后,重置跳转键信息:

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

【讨论】:

    【解决方案2】:

    这是因为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() 更新游戏逻辑。

    编辑:如果空格键和向上键的状态不需要始终保持“向下”,则键实际上被按住(在您当前的代码中没有) ,去寻找@lordvlad 的解决方案。如果您不对这些键执行任何其他检查,那肯定会更好。

    【讨论】:

      【解决方案3】:

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

      所有答案都是好答案,这就是我个人的做法。

      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

      【讨论】:

      • 您已链接到我的演示,这是一个错误吗?我认同。 :D 此外,我认为else if 中的player.jumping 签入是不必要的,因为else if 假定先前的条件尚未满足(因此它隐含地执行与您所做的相同的操作)。
      • @rhino 不,我是说如果玩家没有跳跃,请执行第一个条件。 else if 是如果玩家 正在 跳跃,但玩家跳跃两次尚未设置。如果你检查小提琴它工作正常。
      • 是的,但由于if 检查player.jumping 是否为假,else if(注意else 关键字)假定它为真(第一次检查!player.jumping 有失败,所以player.jumping 必须为真,无需测试)。没有必要执行该检查,因为它已经由 JavaScript 实现隐式完成。我并不是要删除另一个条件!player.jumping_twice,它应该保持原样。无论如何,你的答案仍然链接到我的演示,而不是你的。
      • @rhino 我对你所说的感到困惑,我以为你在说它行不通。我有时喜欢在回答中过于冗长。当有人阅读它时,if/else 检查毫无疑问会发生什么,jumping 可以被删除,但我认为它在可读性方面尚无定论并且不会产生性能成本。我还更新了错误的链接:P
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-21
      • 2013-11-01
      • 2023-02-16
      • 1970-01-01
      • 2021-08-07
      • 2020-09-24
      相关资源
      最近更新 更多