Проблема в вашем 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