添加和删除数组
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;
}
}
}
谢谢大家的回答。
我不知道该如何表达,因为我实际上并不知道究竟是什么导致了这个错误。我正在尝试组装一个简单的 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;
}
}
}
谢谢大家的回答。