Kursinhalt
Kampfspiel in Unity
Kampfspiel in Unity
Laufzustand
public abstract class State
{
public bool isStateFinished;
public abstract void StartState();
public virtual void UpdateState()
{
}
public abstract void EndState();
public virtual void FinishState()
{
isStateFinished = true;
}
}
Änderungen und Ergänzungen
isStateFinished-Variable:
Dies ist eine boolesche Variable, die angibt, ob der Zustand seine Ausführung abgeschlossen hat.
FinishState-Methode:
Dies ist eine neue virtuelle Methode, die isStateFinished
auf true
setzt.
Da sie als virtuell deklariert ist, können abgeleitete Klassen diese Methode überschreiben, falls zusätzliche Aktionen beim Beenden eines Zustands erforderlich sind.
Warum diese Änderungen vorgenommen wurden
Die Änderungen führen die Variable isStateFinished
ein, um den Abschluss eines Zustands zu verfolgen, sowie die Methode FinishState
, um die Signalisierung des Zustandsabschlusses zu standardisieren. Dadurch können abgeleitete Klassen eigene Logik beim Abschluss eines Zustands hinzufügen.
Run State
public class RunState : State
{
Rigidbody2D rb;
Animator animator;
Transform player;
float speed;
Vector2 scale;
Vector2 velocity;
public RunState(Rigidbody2D rb, Animator animator, Transform p, float speed)
{
this.animator = animator;
player = p;
this.speed = speed;
this.rb = rb;
scale = rb.transform.localScale;
velocity = new Vector2();
}
public override void StartState()
{
isStateFinished = false;
animator.SetBool("run", true);
}
public override void UpdateState(float DeltaTime)
{
scale.x = rb.position.x > player.position.x ? -1 : 1;
rb.transform.localScale = scale;
velocity.x = scale.x * speed;
rb.velocity = velocity;
}
public override void EndState()
{
animator.SetBool("run", false);
}
}
Betrachten wir die Klasse RunState
, die von der Klasse State
erbt. Diese Klasse ist für das Laufverhalten unseres Gegners verantwortlich. Im Folgenden werden die Ergänzungen und Änderungen an dieser Klasse erläutert.
Konstruktor:
public RunState(Rigidbody2D rb, Animator animator, Transform p, float speed)
;
Dieser Konstruktor initialisiert den RunState
mit den erforderlichen Komponenten: einem Rigidbody2D
für die Bewegung, einem Animator
für Animationen, einem Transform
zur Verfolgung des Spielers und einer speed
-Variable für die Laufgeschwindigkeit des Gegners;
StartState-Methode:
public override void StartState()
;
Diese Methode setzt isStateFinished
auf false
und startet die Laufanimation, indem der boolesche Parameter "run" im Animator auf true
gesetzt wird.
UpdateState-Methode:
public override void UpdateState(float DeltaTime)
;
Diese Methode aktualisiert die Position und Ausrichtung des Gegners basierend auf der Position des Spielers;
Sie passt die Skalierung des Gegners an, damit dieser dem Spieler zugewandt ist, berechnet die Geschwindigkeit basierend auf dem Wert von speed und wendet diese Geschwindigkeit auf das Rigidbody2D
an.
EndState-Methode:
public override void EndState()
Diese Methode stoppt die Laufanimation, indem der boolesche Parameter "run" im Animator auf false
gesetzt wird.
Funktionsweise für unseren Gegner
-
Bewegung und Animation: Durch die Verwendung von
Rigidbody2D
undAnimator
sorgt derRunState
dafür, dass sich der Gegner flüssig bewegt und passende Animationen ablaufen. Dies macht das Verhalten sowohl visuell als auch physikalisch realistisch; -
Verfolgung der Spielerposition: Das
player
-Transform ermöglicht es dem Gegner, sich stets auf den Spieler zuzubewegen, was für Verfolgungs- oder Laufverhalten essenziell ist; -
Richtungssteuerung: Die Anpassung von
scale.x
basierend auf der Position des Spielers stellt sicher, dass der Gegner beim Laufen korrekt zum Spieler ausgerichtet ist, was zur Realitätsnähe beiträgt; -
Dynamische Zustandsaktualisierung: Die Methode
UpdateState
wird in jedem Frame aufgerufen, um die Bewegung und Ausrichtung des Gegners kontinuierlich an die Position des Spielers anzupassen. Dadurch reagiert der Gegner dynamisch und flexibel.
Gegner-Initialisierung
private void Start()
{
idle = new IdleState(animator);
runState = new RunState(GetComponent<Rigidbody2D>(), animator, player, speed);
stateManager = new StateManager(idle);
FarAwayTransition = new Transition(() =>
{
return (ThresholdDistance < Vector2.Distance(transform.position, player.position));
}, new StatePourcentage(runState, 50f), new StatePourcentage(dashState, 50f));
toIdleTransition = new Transition(() =>
{
return stateManager.GetCurrentState().isStateFinished;
}, new StatePourcentage(idle, 100));
finishRunning = new Transition(() =>
{
return (ThresholdDistance >= Vector2.Distance(transform.position, player.position));
}, new StatePourcentage(idle, 100));
stateManager.AddStateTransition(idle, FarAwayTransition);
stateManager.AddStateTransition(dashState, toIdleTransition);
stateManager.AddStateTransition(runState, finishRunning);
}
Erklärung
Initialisierung des Zustands:
Die Variablen idle
und runState
werden mit ihren jeweiligen Zuständen initialisiert. Die Variable idle
ist eine Instanz von IdleState
, der der Animator übergeben wird, während runState
eine Instanz von RunState
ist, die ein Rigidbody2D
, einen Animator
, ein Transform
für den Spieler und einen Geschwindigkeitswert enthält.
Initialisierung des StateManagers:
stateManager = new StateManager(idle);
Der StateManager
wird mit dem idle
-Zustand als Startzustand initialisiert.
Übergangsdefinitionen:
-
FarAwayTransition:
FarAwayTransition = new Transition(() => { return (ThresholdDistance < Vector2.Distance(transform.position, player.position)); }, new StatePourcentage(runState, 50f), new StatePourcentage(dashState, 50f));
; Dieser Übergang prüft, ob der Spieler weiter alsThresholdDistance
entfernt ist; -
toIdleTransition:
toIdleTransition = new Transition(() => { return stateManager.GetCurrentState().isStateFinished; }, new StatePourcentage(idle, 100));
Dieser Übergang prüft, ob der aktuelle Zustand abgeschlossen ist. Falls ja, erfolgt der Übergang mit 100% Wahrscheinlichkeit in denidle
-Zustand. -
finishRunning:
finishRunning = new Transition(() => { return (ThresholdDistance >= Vector2.Distance(transform.position, player.position)); }, new StatePourcentage(idle, 100));
Dieser Übergang prüft, ob der Spieler näher alsThresholdDistance
ist. Falls ja, erfolgt der Übergang mit 100% Wahrscheinlichkeit in denidle
-Zustand.
Hinzufügen von Übergängen zum StateManager:
stateManager.AddStateTransition(idle, FarAwayTransition);
stateManager.AddStateTransition(dashState, toIdleTransition);
stateManager.AddStateTransition(runState, finishRunning);
Diese Zeilen fügen die definierten Übergänge dem stateManager
hinzu.
Warum wir es so gemacht haben
Dynamische Zustandsänderungen:
Die Übergänge ermöglichen es dem Gegner, sein Verhalten dynamisch basierend auf der Position des Spielers und dem Abschlussstatus des aktuellen Zustands zu ändern. Dadurch wird der Gegner reaktiver und interaktiver innerhalb der Spielumgebung.
Bedingte Übergänge:
Der Einsatz von Bedingungen (wie das Überprüfen der Distanz oder des Abschlusses eines Zustands) stellt sicher, dass Zustandswechsel logisch und angemessen erfolgen, was die Realitätsnähe des Gameplays erhöht.
Wahrscheinlichkeitsbasierte Übergänge:
Die Verwendung von StatePourcentage
ermöglicht wahrscheinlichkeitsbasierte Übergänge und fügt dem Verhalten des Gegners ein Element von Unvorhersehbarkeit und Vielfalt hinzu.
Danke für Ihr Feedback!