【问题标题】:How to properly use setTimeout with immediately invoked function?如何正确使用 setTimeout 和立即调用的函数?
【发布时间】:2016-01-03 06:21:22
【问题描述】:

我正在制作一个游戏,如果玩家从顶部击中敌人,在 1 秒后(即显示死亡动画),敌人将拼接出阵列。

一个一个地杀死一个敌人时效果很好,但是当两个敌人同时被杀死时,就会出现问题。

例如,如果敌人在被击杀时位于阵列的 2 号和 3 号位置。拼接后,位置3就到了位置2。
第二个接头不起作用,因为位置已经改变。

是否有对此或其他方法的修复,或者我的逻辑完全无效。

   for (var i = 0; i < enemies.length; i++) {
     var collWithPlayer= that.collisionCheck(enemies[i], player);

         if (collWithPlayer == 't') { //kill enemies if collision is from top
          enemies[i].state = 'dead';
          player.velY = -((player.speed));

          score.totalScore += 1000;
          score.updateTotalScore();

          //immediately-invoked function for retaining which enemy died
          (function(i){
            setTimeout(function() { //show squashed enemy for a brief moment then splice
              enemies.splice(i, 1);
            }, 1000);
          })(i);

【问题讨论】:

  • IMO 您不应该为此使用 setTimeout。我无法判断这是否是您正在做的基于浏览器/DOM 的事情,但如果是这样,我建议您通过 css 使用过渡效果,这样您就不会仅仅为了效果而延迟 javascripts 处理。这将使您的数组准确,您将不需要这个猴子补丁

标签: javascript arrays iife


【解决方案1】:

所以我所做的是在敌人数组上使用过滤器函数,它返回一个新数组,其中只包含还活着的敌人,或者只是死了一会儿。

可以通过对象上的“decay”属性在“dead”和“remove”之间创建延迟。您可以在每个游戏刻更新/增加此衰减属性的值。

// inside a gametick loop

var enemyCollisions = [];

enemies = enemies.filter(function (item) {
  collisionWithPlayer = that.collisionCheck(item, player);
  
  if (collisionWithPlayer === 't') {
    item.state = 'dead';
    item.decay = 0;
    
    enemyCollisions.push({
      direction: collisionWithPlayer,
      with: item
    });
  }
  
  if (typeof item.decay === 'number') {
    item.decay = item.decay + 1;
  }
  
  return (item.state !== 'dead' && item.decay > 62);
});


enemyCollisions.forEach(function (item) {
  if (item.direction === 't') {
    player.velY = -((player.speed));

    score.totalScore += 1000;
    score.updateTotalScore();
  } else {
    //TODO deal with collisions other then 't'
  }
});

【讨论】:

    【解决方案2】:

    使用反向 for 循环。

    for (var i = enemies.length; i--;){
       // your stuff here
       // hopefully the timeout isn't necessary, or this still has a chance of not working, considering race conditions
       enemies.splice(i, 1);
    }
    // if it is, do the timeout outside of the for loop
    

    这样,当你拼接时,你在你身后而不是你前面拼接。

    【讨论】:

    • 根据我设置的逻辑,超时是必要的,这就是它出现错误的原因。如果没有超时前向循环也可以工作。是的,即使在反向循环中,问题仍然存在,因为“敌人”可能会被任何命令杀死
    【解决方案3】:

    你也可以像下面这样过滤数组。

    function myfunc(){
      var enemies = [1,2,3,4,5];
      var elementToRemove = 3;
      enemies = enemies.filter(function(val){
        return (val !== elementToRemove ? true : false);
      },elementToRemove);
      alert('[' + enemies.join(' , ') + ']');
     }
    &lt;button id="btn" onclick="myfunc();"&gt;Go&lt;/button&gt;

    【讨论】:

      【解决方案4】:

      您可以简单地捕获实际的 enemies[i] 对象而不是 i,以便在事后显示完成后从数组中正确删除它,无论当时的索引是什么:

      (function(e){
          setTimeout(function(){
              enemies.splice(enemies.indexOf(e), 1);
          }, 1000);
       })(enemies[i]);
      

      【讨论】:

        猜你喜欢
        • 2020-01-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-22
        • 1970-01-01
        • 2015-02-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多