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