Добавление и удаление в массив - PullRequest
0 голосов
/ 05 ноября 2018

Я не знал, как это сформулировать, потому что я не знаю, что именно вызывает эту ошибку. Я пытаюсь собрать простой подделку астероидов.

Когда игрок стреляет, новый объект (Bullet) создается с использованием array.push(...). Как только эта пуля выходит за пределы холста (выходит за пределы), она удаляется с помощью 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 (функция, которая создает / удаляет маркеры):

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: []

Спасибо за любые ответы.

Ответы [ 3 ]

0 голосов
/ 05 ноября 2018

Как насчет того, чтобы просто пометить любые пули, которые должны умереть, когда вы сталкиваетесь с ними в вашей петле, с помощью чего-то вроде engine.bullets[i].dead = true; Затем, в конце вне петли, отфильтруйте мертвые пули с помощью engine.bullets = engine.bullets.filter(b => !b.dead);

0 голосов
/ 06 ноября 2018

Проблема заключалась в том, что я переводил контекст, в котором находятся все маркеры, каждый раз, когда создавалась новая пуля. Это означало, что каждая пуля будет удалена на x и y от предыдущей. Это создавало впечатление, будто пули создавались там, где их не должно было быть. «Непредсказуемость» была вызвана тем фактом, что пуля берет на себя вращение игрока, поэтому всякий раз, когда создавалась новая пуля, ее вращение увеличивалось на то, насколько сильно игрок поворачивался до того, как была выпущена новая пуля, поверх вращения предыдущей пули. .

Помещение context.save(); перед переводом / поворотом хитбокса пули и 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 после bullets.splice(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;
            }
        }
    }

Спасибо за все ответы.

0 голосов
/ 05 ноября 2018

Вы используете соединение внутри цикла 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();
...