Übersicht

Zustandsmaschine

Pushdown-Automat-Muster zur Verwaltung komplexer Entity-Verhaltensweisen.

MavonEngine verwendet ein Pushdown-Automat-Muster für die Entity-Zustandsverwaltung. Zustände werden gestapelt: Ein neuer Zustand kann oben hinzugefügt werden (der vorherige wird ausgesetzt) und später wieder entfernt, um ihn fortzusetzen. Dies ermöglicht komplexe Verhaltensweisen wie Unterbrechungen und fortsetzbare Aktionen.

Referenz: Das Muster ist direkt aus Game Programming Patterns — State-Kapitel entnommen.

EntityState

Alle Zustände erweitern die abstrakte EntityState-Klasse.

import { EntityState, Actor } from '@mavonengine/core'

class IdleState extends EntityState {
  enter(): void {
    // Wird aufgerufen, wenn dieser Zustand zum aktiven Zustand wird
  }

  suspend(): void {
    // Wird aufgerufen, wenn ein neuer Zustand darüber gestapelt wird
  }

  leave(): void {
    // Wird aufgerufen, wenn dieser Zustand dauerhaft vom Stack entfernt wird
  }

  update(delta: number): EntityState | void {
    // Neuen Zustand zurückgeben zum Wechseln, oder void um in diesem Zustand zu bleiben
    if (this.entity./* eine Bedingung */) {
      return new WalkState(this.entity)
    }
  }
}

Lebenszyklus-Methoden

MethodeWann aufgerufen
enter()Zustand wird der Stack-Spitze
suspend()Ein anderer Zustand wird darüber gestapelt
leave()Zustand wird dauerhaft vom Stack entfernt
update(delta)Jeden Tick, nur am obersten Zustand aufgerufen

Wechseln

Gib einen neuen EntityState von update() zurück, um zu wechseln. Das leave() des aktuellen Zustands wird aufgerufen und das enter() des neuen Zustands.

update(delta: number): EntityState | void {
  if (this.shouldAttack()) {
    return new AttackState(this.entity)
  }
}

Zugriff auf die Entity

Jeder Zustand hat eine Referenz auf den besitzenden Actor über this.entity.

class WalkState extends EntityState {
  update(delta: number): EntityState | void {
    // Entity bewegen
    this.entity.position.x += delta * speed
  }
}

Verwendung mit Actor

Zustände werden automatisch von Actor.update() verwaltet. Initialisiere den ersten Zustand im Konstruktor deines Actors:

import { Actor, EntityState } from '@mavonengine/core'

class MyActor extends Actor {
  constructor() {
    super()
    this.state = [new IdleState(this)]
  }
}

Der Stack ist bei actor.state verfügbar (ein Array, wobei das letzte Element der aktive Zustand ist).

Beispiel: Idle → Walk → Attack

class IdleState extends EntityState {
  update(delta: number) {
    if (input.keysPressed.has('KeyW')) return new WalkState(this.entity)
  }
}

class WalkState extends EntityState {
  update(delta: number) {
    this.entity.position.z -= delta * 5
    if (input.keysPressed.has('Space')) return new AttackState(this.entity)
    if (!input.keysPressed.has('KeyW')) return new IdleState(this.entity)
  }
}

class AttackState extends EntityState {
  private timer = 0

  update(delta: number) {
    this.timer += delta
    if (this.timer > 0.5) return new IdleState(this.entity)
  }
}