8.1. Столкновение со снарядом
При контакте спрайта снаряда со спрайтом врага нужно уничтожить снаряд и нанести врагу урон. Начнём с отслеживания столкновений спрайтов.
В новом методе processEnemyBulletCollision пройдём все снаряды каждой башни и для каждого проверим, есть ли хотя бы один враг, с которым он сталкивается:
processEnemyBulletCollision() {
this.map.towers.forEach(tower => {
tower.bullets.forEach(bullet => {
const enemy = this.enemies.units.find(unit => bullet.collide(unit.sprite));
if (enemy) {
bullet.remove();
}
});
});
}
update() {
// ...
this.processEnemyBulletCollision();
}
Разработаем collide в классе Bullet:
collide(sprite) {
if (!sprite) {
return;
}
return sprite.containsPoint(this.sprite.getGlobalPosition());
}
8.2. Нанесение урона
Перед уничтожением снаряда нанесём врагу урон:
processEnemyBulletCollision() {
// ...
if (bullet.collide(enemy.sprite)) {
enemy.addDamage(bullet.damage);
bullet.remove();
}
// ...
}
Зададим поле damage класса Bullet значением из конфигурации:
export class Bullet extends EventEmitter {
constructor(tower, enemy) {
// ...
this.damage = this.tower.config.bullet.damage;
}
}
// ...
Реализуем методы addDamage и remove в классе Enemy:
export class Enemy extends Tile {
constructor(config, path) {
// ...
this.hp = this.config.hp;
}
// ...
addDamage(damage) {
this.hp -= damage;
if (this.hp <= 0) {
this.remove();
}
}
remove() {
gsap.killTweensOf(this.sprite);
this.sprite.destroy();
this.sprite = null;
this.emit("removed");
}
}
Возьмём здоровье из конфигурации врага. В addDamage вычтем нужное число здоровья и, если значение не больше нуля, вызовем remove.
В remove сначала остановим твин-анимации gsap. Затем уничтожим спрайт и отправим событие removed:
Подпишемся на это событие в Enemies сразу после создания юнита. При событии удалим его из пула активных юнитов:
createEnemy(i) {
// ...
enemy.once("removed", this.onEnemyRemoved.bind(this, enemy));
}
onEnemyRemoved(enemy) {
this.units = this.units.filter(unit => unit !== enemy);
if (!this.units.length) {
window.setTimeout(this.create.bind(this), this.waveDelay);
}
}
После удаления дополнительно проверяем размер this.units. Если юнитов не осталось, пора создать новую волну, вызвав create с заданной задержкой. Добавим this.waveDelay в конструктор Enemies:
const WaveDelay = 3000;
export class Enemies extends EventEmitter {
constructor(map) {
// ...
this.waveDelay = WaveDelay;
}
// ...
}