Сброс одного массива, влияющий на другой массив

Я не совсем уверен, что здесь происходит. Когда вы стреляете всеми тремя пулями и последняя покидает экран, массив «астероидов» также сбрасывается.

РЕДАКТИРОВАТЬ: это потому, что массив маркеров в конечном итоге соединяется с неопределенным, когда все они покидают экран? Или он вернет базовый пустой массив? Даже тогда это не объясняет, почему массив астероидов также аннулируется. Я также обнаружил, что астероиды даже не начинают падать, если я не выстрелил хотя бы один раз.

Код в редакторе p5web

Что заставляет это происходить? Это первый раз, когда я кодирую что-то настолько большое, разумное по объему кода, но я старался использовать по большей части очевидные имена переменных.


person Cameron Campos    schedule 07.08.2019    source источник
comment
Пожалуйста, укажите свой код в самом вопросе. Внешние ссылки могут изменяться со временем, делая вопрос неактуальным для будущих посетителей. См. как задать вопрос.   -  person ggorlen    schedule 07.08.2019
comment
Слишком много кода, и я подумал, что размещение лишнего кода в ваших сообщениях - это плохо ...   -  person Cameron Campos    schedule 07.08.2019
comment
Да, вы правы, поэтому идея состоит в том, чтобы создать что-то, что называется минимальным воспроизводимым примером, который требует немного усилие создать. Но в процессе сокращения кода вы можете сами обнаружить проблему. Я знаю, что это звучит неубедительно, но это своего рода стандарт для сообщения об ошибках и обращения за помощью с кодом. Я смотрю на ваш код и не уверен, что полностью понимаю проблему, но я дам вам знать, если увижу что-нибудь.   -  person ggorlen    schedule 07.08.2019
comment
Я чувствую тебя, хорошо, что само по себе это, наверное, удар в штаны, который мне нужен, лол   -  person Cameron Campos    schedule 07.08.2019
comment
Перемещено в основную ветку   -  person Cameron Campos    schedule 07.08.2019
comment
Это старый и решенный вопрос, но все же стоит перенести соответствующий код в сам вопрос для потомков - он может помочь кому-то еще в будущем. Я не могу сделать это для OP из-за this и это.   -  person ggorlen    schedule 22.08.2019


Ответы (1)


Проблема в вашем asteroids классе:

check(bullets) {
    for (let i = 0; i < bullets.length; i++) {
        if (dist(bullets[i].x, bullets[i].y, this.pos.x, this.pos.y) < this.r) {
            return false;
        } else {
            return true;
        }
    }
}

Если нет пуль для проверки, эта функция неявно возвращает undefined, что принимается как ложное вызывающим кодом, который немедленно уничтожает астероид, как если бы он столкнулся с пулей.

Кроме того, если есть пули, которые нужно проверить, и первый из них не сталкивается, цикл преждевременно прерывается с else { return true; }, возможно, пропуская столкновения.

Измените его на:

check(bullets) {
    for (let i = 0; i < bullets.length; i++) {
        if (dist(bullets[i].x, bullets[i].y, this.pos.x, this.pos.y) < this.r) {
            return false;
        }
    }

    return true; // no collisions (or bullets.length === 0)
}

Сказав это, имя функции check довольно неясно. Я бы переименовал его в collidesWith(bullets) и инвертировал логическое значение - имеет смысл сказать «правда, да, мы столкнулись с пулей», чем «ложь, да, мы действительно столкнулись с пулей». Мы также можем использовать конструкцию цикла for ... of. Это дает нам:

collidesWith(bullets) {
    for (const bullet of bullets) {
        if (dist(bullet.x, bullet.y, this.pos.x, this.pos.y) < this.r) {
            return true;
        }
    }

    return false;
}

Вы можете сократить это до:

collidesWith(bullets) {
  return bullets.some(e => dist(e.x, e.y, this.pos.x, this.pos.y) < this.r);
}

Точно так же я бы изменил bullet.check() на bullet.outOfBounds() или аналогичный.

Еще один совет: выполните итерацию в обратном порядке по любым массивам, из которых вы планируете вырезать текущий элемент:

for (let j = asteroids.length - 1; j >= 0; j--) {
   // code that could call `.splice(j, 1)`
}

В противном случае после склейки ваш цикл пропустит элемент, и вы можете пропустить столкновение.

Незначительный дизайнерский нюанс, но player.controls() кажется странным - почему проигрыватель должен отвечать за прослушивание нажатий клавиш? Я бы прослушал функцию keyPressed() и отправил бы изменения, чтобы обновить позицию игрока оттуда. Я бы также разделил draw на более мелкие функции. Но это второстепенные дизайнерские решения, поэтому всего вышеперечисленного достаточно, чтобы начать работу.

Вот первая версия функции draw, скорректированная для соответствия измененным логическим значениям:

function draw() {
  background(0);
  scene();

  if (tick <= 0) {
    if (asteroids.length < asteroidsLimit) {
      asteroids.push(new Asteroid());
    }

    tick = 60;
  }

  for (let i = asteroids.length - 1; i >= 0; i--) {
    if (asteroids[i].collidesWith(bullets)) {
      asteroids.splice(i, 1);
    } 
    else {
      asteroids[i].update();
      asteroids[i].display();
    }
  }

  for (let i = bullets.length - 1; i >= 0; i--) {
    if (bullets[i].outOfBounds()) {
      bullets.splice(i, 1);
    } 
    else {
      bullets[i].update();
      bullets[i].display();
    }
  }

  image(ship, player.x, player.y);
  player.controls();
  tick--;
}
person ggorlen    schedule 07.08.2019