简体   繁体   English

如何正确使用setTimeout和立即调用的函数?

[英]How to properly use setTimeout with immediately invoked function?

I'm making a game where if the player hits the enemy from top, after 1 sec period,(that is to show dying animation), the enemy will splice out of the array. 我正在做一个游戏,如果玩家在1秒钟后从顶部击中敌人(即显示垂死的动画),则敌人会从阵列中拼接出来。

It works fine while killing each enemy one by one, but when two enemies get killed at the same time, a problem occurs. 在逐个杀死每个敌人的同时,它运作良好,但是当同时杀死两个敌人时,就会出现问题。

For example, if the enemies were in position 2 and 3 of the array when killed. 例如,如果敌人被杀死时位于阵列的第2和第3位。 After splicing it, the position 3 comes to position 2. 拼接后,位置3到达位置2。
The second splice doesn't work as the position is already changed. 第二个接头不起作用,因为位置已更改。

Is there a fix to this or a different method, or is my logic just plain invalid. 是否有针对此方法或其他方法的修复程序,还是我的逻辑完全无效?

   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);

So what I did was use a filter function on the enemy array that returns a new array containing only enemies that are still alive, or have only been dead for a little while. 因此,我所做的就是在敌人数组上使用过滤器函数,该函数返回一个新数组,其中仅包含仍存活或仅死了一段时间的敌人。

Creating a delay between 'dead' and 'remove' can be done with a 'decay' property on an object. 可以在对象上使用“ decay”属性来在“ dead”和“ remove”之间创建延迟。 You can update/increase the value of this decay-property on every game-tick. 您可以在每个游戏标记上更新/增加此衰减属性的值。

 // 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' } }); 

Use a reverse for loop. 使用反向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

That way, when you splice, you splice behind you instead of in front of you. 这样,当您进行拼接时,您将拼接在自己的后面而不是前面。

You could also filter the array like below. 您还可以如下过滤数组。

 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(' , ') + ']'); } 
 <button id="btn" onclick="myfunc();">Go</button> 

You could simply capture the actual enemies[i] object instead of i to remove it correctly from the array once the post-mortem dislay is done no matter what the index will be at that time: 您可以简单地捕获实际的enemies[i]对象而不是i ,以便在完成事后派发处理后立即将其从数组中正确删除,无论当时的索引是什么:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM