Javascript 向数组中添加和删除

Javascript 向数组中添加和删除,javascript,arrays,push,splice,Javascript,Arrays,Push,Splice,我不知道该怎么说,因为我不知道到底是什么导致了这个错误。我正试着制作一个简单的小行星仿制品 当玩家射击时,将使用array.push…创建一个新的对象子弹。。。。一旦此项目符号超出画布范围,将使用array.splice…删除它 问题是子弹以不可预测的方式移动。我不知道如何使用它,所以下面是完整的代码,包括html/css: 按住空格键几秒钟进行拍摄,您将清楚地看到问题。您也可以使用A/D旋转,W前进 以下是我认为正在发生的事情。只要数组中屏幕上只有一个项目符号,代码就可以正常运行。这意味着要么

我不知道该怎么说,因为我不知道到底是什么导致了这个错误。我正试着制作一个简单的小行星仿制品

当玩家射击时,将使用array.push…创建一个新的对象子弹。。。。一旦此项目符号超出画布范围,将使用array.splice…删除它

问题是子弹以不可预测的方式移动。我不知道如何使用它,所以下面是完整的代码,包括html/css: 按住空格键几秒钟进行拍摄,您将清楚地看到问题。您也可以使用A/D旋转,W前进

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

展示项目符号构造函数及其方法:

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创建/删除项目符号的功能:

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);
                }
            }
        }
数组声明如下:项目符号:[]


谢谢您的回答。

您正在for循环中使用拼接。删除元素索引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的东西标记它们,怎么样;然后,在循环外的末端,使用engine.bullets=engine.bullets.filterb=>过滤掉死子弹!b、 死亡

问题是每次创建新项目符号时,我都在翻译所有项目符号所在的上下文。这意味着每一颗子弹都会从上一颗子弹移动x和y。这让人觉得子弹是在不该出现的地方制造出来的。这种不可预测性是由子弹承担玩家的旋转这一事实造成的,因此每当创建一个新子弹时,它的旋转都会增加玩家在新子弹发射前的旋转量,而不是上一个子弹的旋转量

保存上下文;在平移/旋转项目符号的hitbox和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();
    }
}
其他人提到我使用的是array.splice;在for循环中。这使得当一个项目符号i被删除时,在i+1之后的项目符号被向后移动一个索引i。所以那颗子弹基本上被跳过了

有时当我看到一颗子弹被删除时,我会注意到这一点——它们跳到了前面

解决方案是将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;
            }
        }
    }

感谢您提供的所有答案。

在for循环中,每次阵列缩短时,都需要注意阵列的长度。因此,您可能会考虑将bullets.length指定给一个变量,在循环的条件中使用该变量,然后每次从其数组中删除一个bullet项时递减该变量。谢谢您的回答,但事实证明,这不是问题所在。我试着把context.save;语境恢复;到项目符号发生平移/旋转的位置。现在没有了issues@JanProcházka你应该把它作为一个答案,并标记为正确的-尤其是如果你知道为什么这是正确的答案,并能解释它!切勿在正向回路中使用接头。当通过拼接移除第i个元素时,从i+1到最后一个元素的所有元素都向左移动,并且它们的索引分别改变。这就是为什么你会有不可预测的行为。谢谢你的建议,但实际上我不需要走那么远。我只是在子弹之后做这个,I-=1。I,1;。这将设置for循环1的索引,并解决了它在没有它的情况下工作的一个小错误