Kursinhalt
Kampfspiel in Unity
Kampfspiel in Unity
Angriffsstatus
public class AttackState : State
{
string attackStateName;
bool isAttacking;
Animator animator;
Transform transform;
float range;
int damage;
LayerMask playerLayer;
public AttackState(Transform t, Animator animator, LayerMask playerLayer, string attackStateName, int damage, float range = 2.1f)
{
this.animator = animator;
this.attackStateName = attackStateName;
this.range = range;
transform = t;
this.damage = damage;
this.playerLayer = playerLayer;
}
public override void StartState()
{
isStateFinished = false;
animator.SetBool(attackStateName, true);
isAttacking = false;
}
public override void EndState()
{
animator.SetBool(attackStateName, false);
}
public override void UpdateState(float deltaTime)
{
Attack();
}
public override void StartAction()
{
isAttacking = true;
}
public override void FinishMovement()
{
isAttacking = false;
}
void Attack()
{
if (!isAttacking) return;
RaycastHit2D rayCastHit = Physics2D.Raycast(transform.position, Vector2.right * transform.localScale.x, range, playerLayer);
if (rayCastHit)
{
if (rayCastHit.transform.TryGetComponent(out IGetAttacked getAttacked))
{
getAttacked.GetAttacked(damage);
isAttacking = false;
}
}
}
}
Erklärung der AttackState-Klasse
Die AttackState
-Klasse ist ein spezifischer Zustand, der das Angriffsverhalten des Gegners steuert. Diese Klasse erbt von der State
-Klasse und beinhaltet Methoden zum Starten, Aktualisieren und Beenden des Angriffs-Zustands sowie zur Ausführung der Angriffsaktion.
Klassendefinition und Member-Variablen
Klassendefinition:
public class AttackState : State
;
Diese Klasse erbt von der State
-Klasse, was bedeutet, dass sie die abstrakten Methoden aus State
implementieren muss.
Member-Variablen:
string attackStateName;
Der Name des Angriffs-Zustands, der im Animator verwendet wird.
bool isAttacking;
Ein Flag, das angibt, ob der Gegner aktuell angreift.
Animator animator;
Steuert die Animationen.
Transform transform;
Das Transform des Gegners, verwendet für Positionierung und Raycasting.
float range;
Die Angriffsreichweite.
int damage;
Der durch den Angriff verursachte Schaden.
LayerMask playerLayer;
Der Layer-Mask, der zur Identifizierung des Spielers verwendet wird.
Konstruktor
Der Konstruktor initialisiert den AttackState
mit den erforderlichen Komponenten: einem Transform
für die Positionierung, einem Animator
für Animationen, einer Layer-Maske zur Identifizierung des Spielers, dem Namen des Angriffsstatus, dem Schadenswert und der Angriffsreichweite. Diese Werte werden den entsprechenden Member-Variablen zugewiesen.
StartState-Methode
Diese Methode setzt isStateFinished
auf false
, löst die Angriffsanimation aus, indem der entsprechende boolesche Parameter im Animator auf true
gesetzt wird, und setzt das Flag isAttacking
auf false
zurück.
EndState-Methode
Diese Methode stoppt die Angriffsanimation, indem der entsprechende boolesche Parameter im Animator auf false
gesetzt wird.
UpdateState-Methode
Diese Methode wird in jedem Frame aufgerufen und löst die Attack
-Methode aus, um die Angriffsaktion auszuführen.
StartAction-Methode
Diese Methode setzt isAttacking
auf true
und zeigt damit an, dass die Angriffsaktion begonnen hat.
FinishMovement-Methode
Diese Methode setzt isAttacking
auf false
und zeigt damit an, dass die Angriffsaktion beendet ist.
Angriffsmethode
Diese Methode führt die Angriffsaktion aus. Wenn isAttacking
auf true
gesetzt ist, wird ein Strahl in die Richtung geworfen, in die der Gegner blickt. Trifft der Strahl ein Objekt auf dem playerLayer
, wird die Methode GetAttacked
auf dem getroffenen Objekt aufgerufen, wodurch Schaden verursacht und die Angriffsaktion beendet wird.
Warum wir es so umgesetzt haben
-
Kontrolle über das Angriffsverhalten: Das Flag
isAttacking
ermöglicht eine präzise Steuerung darüber, wann der Angriff stattfinden soll, wodurch das Verhalten besser auf Spielereignisse reagieren kann; -
Dynamische Angriffsausführung: Durch die kontinuierliche Aktualisierung des Angriffsstatus des Gegners stellt der
AttackState
sicher, dass der Gegner den Spieler genau und dynamisch angreifen kann; -
Integration von Animationen: Die Verwendung von Animator-Parametern stellt sicher, dass die Animationen des Gegners korrekt mit seinen Angriffen synchronisiert werden, was ein flüssiges und realistisches Erlebnis bietet.
Funktionsweise im Kontext
Angriffsstatus betreten: Wenn der Gegner in den AttackState
wechselt, wird die Methode StartState
aufgerufen, die die Angriffsanimation auslöst und das Flag isAttacking
zurücksetzt.
Während des Angriffs: Die Methode UpdateState
wird in jedem Frame aufgerufen. Sie löst die Methode Attack
aus, um zu prüfen, ob ein Angriff stattfinden soll.
Angriff starten: Die Methode StartAction
setzt isAttacking
auf true
, sodass die Methode Attack
die Angriffsaktion ausführen kann.
Angriff ausführen: Die Methode Attack
wirft einen Strahl, um den Spieler zu erkennen, und verursacht Schaden, wenn der Spieler getroffen wird.
Angriff beenden: Die Methode FinishMovement
setzt isAttacking
auf false
und beendet damit die Angriffsaktion.
Angriffsstatus verlassen: Wenn der Gegner den AttackState
verlässt, wird die Methode EndState
aufgerufen, wodurch die Angriffsanimation gestoppt wird.
Durch diese Struktur des AttackState
wird sichergestellt, dass der Gegner reaktionsschnelle und dynamische Angriffe auf den Spieler ausführen kann, mit fließenden Übergängen zwischen Animationen und Zuständen.
Nahübergang:
closeTransition = new Transition(() =>
{
return (ThresholdDistance >= Mathf.Abs(transform.position.x - player.position.x));
}, new StatePourcentage(attack2, 50f), new StatePourcentage(attack1, 50f));
stateManager.AddStateTransition(idle, closeTransition);
stateManager.AddStateTransition(idle, FarAwayTransition);
stateManager.AddStateTransition(dashState, toIdleTransition);
stateManager.AddStateTransition(dashState, finishRunning);
stateManager.AddStateTransition(runState, finishRunning);
stateManager.AddStateTransition(attack2, toIdleTransition);
stateManager.AddStateTransition(attack1, toIdleTransition);
closeTransition:
Diese Transition prüft, ob sich der Spieler innerhalb einer bestimmten horizontalen Distanz (ThresholdDistance
) zum Gegner befindet.
Wenn die Bedingung erfüllt ist, erfolgt ein zufälliger Übergang zu entweder attack1
oder attack2
mit jeweils gleicher Wahrscheinlichkeit (je 50%).
Codebeispiel:
```csharp
closeTransition = new Transition(() =>
{
return (ThresholdDistance >= Mathf.Abs(transform.position.x - player.position.x));
}, new StatePourcentage(attack2, 50f), new StatePourcentage(attack1, 50f));
```
Hinzufügen von closeTransition zum Idle-Zustand:
stateManager.AddStateTransition(idle, closeTransition);
Diese Zeile fügt die closeTransition
dem idle
-Zustand hinzu, sodass die Zustandsmaschine diese Bedingung prüft, wenn sich der Gegner im Idle-Zustand befindet.
Warum wir es so gemacht haben
Das Übergangssystem ermöglicht es dem Gegner, basierend auf der Nähe des Spielers in einen Angriffsmodus zu wechseln, was die Interaktion verbessert. Der probabilistische Ansatz zur Auswahl zwischen verschiedenen Angriffen sorgt für Unvorhersehbarkeit und erhöht die Herausforderung und das Interesse am Spiel.
Funktionsweise im Kontext
Idle-Zustand:
Während sich der Gegner im idle
-Zustand befindet, prüft er ständig mit dem ThresholdDistance
, ob sich der Spieler innerhalb der closeTransition
befindet.
Ist der Spieler nah genug, wird der closeTransition
ausgelöst und der Gegner wechselt entweder in attack1
oder attack2
.
Angriffszustände:
Sobald sich der Gegner in attack1
oder attack2
befindet, führt er den Angriff aus.
Nach Abschluss des Angriffs sorgt der bestehende toIdleTransition
dafür, dass der Gegner wieder in den idle
-Zustand zurückkehrt und erneut die Bedingung für den closeTransition
prüft.
Durch das Hinzufügen dieses closeTransition
stellen wir sicher, dass der Gegner den Spieler dynamischer und unvorhersehbarer angreifen kann, wenn sich dieser in unmittelbarer Nähe befindet. Dies verbessert das Gameplay, indem das Verhalten des Gegners reaktiver und ansprechender gestaltet wird.
Danke für Ihr Feedback!