添加和删​​除数组

Adding and removing to an array

我不知道该如何表达,因为我实际上并不知道究竟是什么导致了这个错误。我正在尝试组装一个简单的 Asteroids 仿制品。

当玩家射击时,使用 array.push(...) 创建一个新对象(子弹)。一旦此项目符号超出 canvas(越界),将使用 array.splice(...);

将其删除

问题是子弹以不可预测的方式移动。我不知道怎么表达所以这是完整的代码(有效,包括 html/css):https://pastebin.com/tKiSnDzX 按住空格键几秒钟(射击),您会清楚地看到问题。也可以使用A/D转弯W前进

这是我认为正在发生的事情。只要屏幕上(数组中)只有一颗子弹,代码就可以正常运行。这意味着要么删除了不正确的元素,要么进入对象构造函数的值在此过程中的某个地方弄乱了。

图表 A(项目符号构造函数及其方法):

function Bullet(x,y,rot,vel) {
    this.x = x;
    this.y = y;
    this.rot = rot;
    this.vel = (vel+5);

    this.move = function() {
        this.x += this.vel*Math.cos(this.rot-Math.PI/2);
        this.y += this.vel*Math.sin(this.rot-Math.PI/2);
    }

    this.draw = function() {
        engine.circle(this.x, this.y, 4, "black");

        var c = engine.canvas.getContext('2d');
        c.translate(this.x, this.y);
        c.rotate(this.rot);
        c.beginPath();
        c.strokeStyle="#00FF00";
        c.strokeRect(-5, -5, 10, 10);
        c.closePath();
        c.stroke();
    }
}

图表 B(creates/deletes 子弹的功能):

shoot: function() {
            if(engine.keyDown.sp == true) {
                if(this.fire > 20) {
                    engine.bullets.unshift(new Bullet(this.x, this.y, this.rot, this.velocity));
                    this.fire = 0;
                } else {
                    this.fire++
                }
            }
            for(i = 0; i < engine.bullets.length; i++) {
                engine.bullets[i].move();
                engine.bullets[i].draw();
                if(engine.bullets[i].x > engine.canvas.width+5 || engine.bullets[i].x < -5 
                || engine.bullets[i].y > engine.canvas.height+5  || engine.bullets[i].y < -5) {
                    console.log('bullet gone, '+i);
                    engine.bullets.splice(i, 1);
                }
            }
        }

数组声明如下:bullets: []

感谢您的任何回答。

您在 for 循环中使用了 splice。当您删除元素索引 1 时,元素索引 2 变为索引 1,元素索引 3 变为索引 2。但是您的 i 变量已经是 1,因此循环的下一次迭代将转到新索引2。但是新索引2是原来的索引3,原来的索引2被跳过了。链接列表可能会更好地为您服务:

var bulletList = null;
function bullet(){
  this.next = bulletList;//if there was a list, record that
  if (this.next)//and set that one to point back to this
   this.next.prev = this;
  bulletList = this;//place new bullet at start of list
  this.previous = null;

  this.draw = function(){
    //do stuff here
    this.next && this.next.draw();//call next item in the list, if any
    if (shouldIBeRemoved){//placeholder, obviously
      if (this.next && this.prev){//remove from middle of list
        this.prev.next = this.next;
        this.next.prev = this.prev;
      }
      else if (this.next && !this.prev){//remove from beginning of list
        bulletList = this.next;
        this.next.prev = null;
      }
      else if (this.prev && !this.next){//remove from end of list
        this.prev.next = null;
      }
      else if (!this.prev && !this.next){//remove only item in list
        bulletList = null;
      }
    }
  }
}

然后绘制每颗子弹,只需调用:

if (bulletList)
  bulletList.draw();

当你在循环中遇到任何需要死亡的子弹时,用 engine.bullets[i].dead = true; 之类的东西标记它们怎么样?然后,在循环外的最后,用 [=11= 过滤掉死子弹]

问题是每次创建新项目符号时,我都在翻译所有项目符号所在的上下文。这意味着每颗子弹都将远离前一颗子弹 x 和 y。这让子弹看起来像是在不应该出现的地方被制造出来的。 "unpredictability" 是因为子弹会影响玩家的旋转,因此无论何时创建新子弹,它的旋转都会增加,无论玩家在发射新子弹之前旋转了多少,在前一个之上子弹的旋转。

context.save();放在子弹命中框的translation/rotation之前,context.restore();放在它之后完美解决了问题:

Bullet.draw = function() {
    engine.circle(this.x, this.y, 4, "black");
    if(hitbox == true) {
        var c = engine.canvas.getContext('2d');
        c.save();
        c.translate(this.x, this.y);
        //c.rotate(this.rot);
        c.beginPath();
        c.strokeStyle="#00FF00";
        c.strokeRect(-5, -5, 10, 10);
        c.closePath();
        c.stroke();
        c.restore();
    }
}

有人提到我在 for 循环中使用了 array.splice();。这样一来,当项目符号 (i) 被删除时,(i+1) 之后的项目符号将向后移动一个索引 (i)。所以基本上跳过了那个项目符号。

有时我在查看项目符号时会注意到这一点,而其中一个被删除了 - 他们 "jumped" 领先。

解决方案是在 bullets.splice(i, 1); 之后放置 i -= 1。这使得循环的下一次迭代返回一个索引,解决了子弹偶尔出现的卡顿问题:

shoot: function() {
        if(engine.keyDown.sp == true) {
            if(this.fire > 5) {
                engine.bullets.unshift(new Bullet(this.x, this.y, this.rot, this.velocity));
                this.fire = 0;
            }
        }
        if(this.fire<=5) {
            this.fire++
        }
        for(i = 0; i < engine.bullets.length; i++) {
            engine.bullets[i].move();
            engine.bullets[i].draw();
            if(engine.bullets[i].x > engine.canvas.width+5 || engine.bullets[i].x < -5 
            || engine.bullets[i].y > engine.canvas.height+5  || engine.bullets[i].y < -5) {
                engine.bullets.splice(i, 1);
                i-=1;
            }
        }
    }

谢谢大家的回答。