← На главную
Серия руководств

Шаг 8. Урон врагу

Создание Tower Defense с PIXI • Шаг 8 из 12

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;
    }
    // ...
}