Heim > Web-Frontend > js-Tutorial > Angriff auf den am weitesten entfernten Feind (Tower Defense)

Angriff auf den am weitesten entfernten Feind (Tower Defense)

Linda Hamilton
Freigeben: 2024-12-12 12:59:11
Original
501 Leute haben es durchsucht

Im vorherigen Artikel habe ich gezeigt, wie man den am weitesten entfernten Feind mithilfe eines maximalen Heaps effizient verfolgen kann. In diesem Artikel werden wir sehen, wie man das in eine Spielmechanik integriert.

Ereignisgesteuerter Ansatz

Die bestehende Implementierung verwendet eine ereignisgesteuerte Architektur. In diesem Artikel konzentrieren wir uns auf die Feindereignisse. Diese Ereignisse werden Spin-off-Aktionen auslösen.

Jeder Feind kann verschiedene Ereignisse erleben. Nachfolgend finden Sie ein Beispiel für einen Lebenszyklus, den der Feind durchlaufen kann:

Attacking the Furthest Enemy in Range (Tower Defence)

Für den Artikel interessieren mich die beiden Veranstaltungen:

  • feindlich bewegt: Wird abgefeuert, wenn sich die Position eines Feindes ändert.
  • FeindRemoved*: Wird abgefeuert, wenn ein Feind aus dem Spiel entfernt (z. B. besiegt) wird.

(* Ich habe vor, die Ereignisnamen in Zukunft anzupassen, da ein Feind aus verschiedenen Gründen entfernt werden kann.)

Planen

Ich habe ein Ereignismodelldiagramm erstellt, um zu visualisieren, wie verschiedene Ereignisse interagieren. Dies hilft beim Verständnis, wie die Dinge zusammenhängen.

Attacking the Furthest Enemy in Range (Tower Defence)

Für jedes Ereignis habe ich einen Befehl, der es auslöst. (Ein Ereignis ist also das Ergebnis eines Befehls.) In einigen Fällen müssen wir als Ergebnis eines Ereignisses Daten aktualisieren (grüne Haftnotizen zeigen dies). Eine Kombination aller drei zusammen ist ein vertikaler Schnitt.

Mein Fokus wird auf der grünen Haftnotiz „Feinde in Reichweite des Turms“ liegen.

Durchführung

Das Ziel besteht darin, die verfügbaren Feinde zu aktualisieren, wenn sich ein Feind in der Reichweite des Turms befindet, und sie zu entfernen, wenn nicht.

Wir werden mit einer Turmklasse arbeiten. In dieser Klasse haben wir eine Variable zum Speichern von Feinden.

export class Tower implements ITower {
    public enemies = new MaxHeap()

    constructor(id: number, coords: Coordinate) {
        this.id = id
        this.coords = coords

        // listeners will go here...
    }
Nach dem Login kopieren
Nach dem Login kopieren

Durch die Platzierung von Ereignis-Listenern in der Tower-Klasse wird die Logik zentralisiert, wodurch die Notwendigkeit verringert wird, Zuordnungen zwischen Türmen und Feinden aufrechtzuerhalten. Dies erhöht zwar die Komplexität der Klasse, gewährleistet jedoch eine bessere Kapselung und vereinfacht das Debuggen, was vorerst eine einfachere Richtung darstellt.

Aktion: Feinde in Reichweite hinzufügen

Test: Einen Feind hinzufügen

Zuerst schreiben wir einen Test, um zu überprüfen, ob ein Feind in Reichweite zum Feindhaufen des Turms hinzugefügt wird:

it('should add an enemy to the tower when enemy is within range', () => {
    const tower = new Tower(1, { col: 0, row: 1 });
    const enemy = new TinyEnemy();
    enemy.currentPosition = { col: 0, row: 1 };

    triggerEnemyMovedEvent(enemy);

    expect(tower.enemies.length()).toBe(1);
});
Nach dem Login kopieren
Nach dem Login kopieren

Implementierung: Einen Feind hinzufügen

Hier ist die entsprechende Implementierung:

window.addEventListener("enemyMoved", event => {
    const enemy: Enemy = event.detail.enemy;

    if (enemyWithinRange(this, enemy)) {
        this.enemies.insertOrUpdate(enemy.id, enemy.distanceTraveled);
    }
});
Nach dem Login kopieren
Nach dem Login kopieren

Immer wenn „feindMoved“ ausgelöst wird, prüfen wir, ob ein Feind zum Heap hinzugefügt werden soll. Ich habe bereits die Funktion „feindWithinRange“, es geht nur darum, den Aufruf „insertOrUpdate“ hinzuzufügen.


Aktion: Verhindern Sie das Hinzufügen von Feinden außerhalb der Reichweite

Test: Ignorieren von Feinden außerhalb der Reichweite

Als nächstes stellen wir sicher, dass keine Feinde außerhalb der Reichweite des Turms hinzugefügt werden:

export class Tower implements ITower {
    public enemies = new MaxHeap()

    constructor(id: number, coords: Coordinate) {
        this.id = id
        this.coords = coords

        // listeners will go here...
    }
Nach dem Login kopieren
Nach dem Login kopieren

Implementierung: Ignorieren von Feinden außerhalb der Reichweite

Dieses Szenario wird bereits durch unsere frühere Prüfung mit „feindWithinRange“ abgedeckt, daher ist kein zusätzlicher Code erforderlich.


Aktion: Feinde außerhalb der Reichweite entfernen

Test: Einen Feind außerhalb der Reichweite entfernen

Jetzt testen wir, ob Feinde, die die Reichweite verlassen, aus der Sichtbarkeit des Turms entfernt werden:

it('should add an enemy to the tower when enemy is within range', () => {
    const tower = new Tower(1, { col: 0, row: 1 });
    const enemy = new TinyEnemy();
    enemy.currentPosition = { col: 0, row: 1 };

    triggerEnemyMovedEvent(enemy);

    expect(tower.enemies.length()).toBe(1);
});
Nach dem Login kopieren
Nach dem Login kopieren

Implementierung: Entfernen eines Gegners außerhalb der Reichweite

window.addEventListener("enemyMoved", event => {
    const enemy: Enemy = event.detail.enemy;

    if (enemyWithinRange(this, enemy)) {
        this.enemies.insertOrUpdate(enemy.id, enemy.distanceTraveled);
    }
});
Nach dem Login kopieren
Nach dem Login kopieren

Wenn der Feind früher in Reichweite war, können wir ihn entfernen.


Aktion: Einen Gegner aus dem Spiel entfernen

Test: Umgang mit dem Ereignis „feindRemoved“.

Zuletzt stellen wir sicher, dass aus dem Spiel entfernte Feinde auch vom Haufen des Turms entfernt werden:

it('should not add an enemy to the tower if enemy is out of range', () => {
    const tower = new Tower(1, { col: 0, row: 1 });
    const enemy = new TinyEnemy();
    enemy.currentPosition = { col: 0, row: 99 };

    triggerEnemyMovedEvent(enemy);

    expect(tower.enemies.length()).toBe(0);
});
Nach dem Login kopieren

Implementierung: Umgang mit „feindRemoved“.

it('should remove an enemy from the tower when it moves out of range', () => {
    const tower = new Tower(1, { col: 0, row: 1 });
    const enemy = new TinyEnemy();
    enemy.currentPosition = { col: 0, row: 1 };

    // enemy within range
    triggerEnemyMovedEvent(enemy);
    expect(tower.enemies.length()).toBe(1);

    // enemy outside of the range
    enemy.currentPosition = { col: 0, row: 99 };
    triggerEnemyMovedEvent(enemy);

    expect(tower.enemies.length()).toBe(0);
});
Nach dem Login kopieren

Immer wenn ein Ereignis ausgelöst wird und sich der Feind in Reichweite befindet, können wir ihn entfernen.

Abschluss

Durch die Kombination eines ereignisgesteuerten Ansatzes mit einem maximalen Heap haben wir eine effiziente Möglichkeit für Türme erreicht, Feinde dynamisch zu priorisieren. Die Implementierung fügt sich nahtlos in das Event-System des Spiels ein und gewährleistet Echtzeit-Updates und Reaktionsfähigkeit.

Außerdem entfällt beim Testen durch die Verwendung eines ereignisgesteuerten Ansatzes die Notwendigkeit, internen Code mit dem Test zu verknüpfen. Dadurch werden Tests weniger spröde. Wir können den Code hinter dem Verhalten nach Belieben umgestalten, und solange Ereignisse/Listener korrekt eingerichtet sind, sollten die Tests trotzdem bestehen.

Diese Implementierung kann nun den Weg ebnen für:

  • Angriffsfunktionalität hinzufügen (jetzt wissen wir, wen wir angreifen müssen)
  • Austauschen, wie Daten für Feinde gespeichert werden

Sie können diesen Ansatz gerne für Ihre eigenen Tower-Defense-Spiele anpassen.

Das obige ist der detaillierte Inhalt vonAngriff auf den am weitesten entfernten Feind (Tower Defense). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage