Menu
CoddyTech

C#-Events in Unity

Teil des Abschnitts Spielarchitektur in Unity der Unity-Journey von Coddy. Lektion 10 von 50.

Wenn sich der Punktestand ändert, betrifft das mehrere Dinge: den Punktestandstext, einen Sound, einen Erfolg. Wenn der ScoreKeeper jedes davon aufruft, braucht er für jedes ein Feld, und jede neue Funktion bedeutet, dass er bearbeitet werden muss. Ein Ereignis kehrt das um: Der ScoreKeeper kündigt die Änderung an, und alle, die daran interessiert sind, abonnieren es. Du kennst event und Action aus C#. In Unity sind der Herausgeber und seine Listener Komponenten, normalerweise auf verschiedenen GameObjects:

using System;
using UnityEngine;

public class ScoreKeeper : MonoBehaviour
{
    public event Action<int> OnScoreChanged;
    private int score;

    public void AddPoints(int points)
    {
        score += points;
        OnScoreChanged?.Invoke(score);
    }
}
// ScoreLabel.cs, am Text des HUDs
public ScoreKeeper keeper;
public TMP_Text label;

void Start()
{
    keeper.OnScoreChanged += ShowScore;
}

void ShowScore(int score)
{
    label.text = "Score: " + score;
}

Action<int> bedeutet, dass jeder Listener eine Methode ist, die einen int entgegennimmt, hier den neuen Punktestand. Invoke ruft jede abonnierte Methode auf, und zwar in der Reihenfolge, in der sie abonniert haben. Gibt es keinen Listener, ist das Ereignis null, sodass ein einfaches OnScoreChanged(score) eine NullReferenceException auslösen würde; ?. überspringt den Aufruf stattdessen. Das Schlüsselwort event beschränkt andere Skripte auf += und -=: In ScoreLabel lässt sich keeper.OnScoreChanged(5) oder keeper.OnScoreChanged = null nicht kompilieren.

Der ScoreKeeper hat kein Feld für das Label und weiß nicht, dass es existiert. Ein Combo-Zähler oder ein Sound-Player abonniert es auf dieselbe Weise, und der ScoreKeeper bleibt unverändert; eine Testszene ohne HUD läuft ohne Fehler. Ein Listener findet den Herausgeber über eine Inspector-Referenz wie hier oder auf eine andere bekannte Weise, etwa mit GetComponent oder einem Singleton. Einen Listener mit -= zu entfernen, ist wichtig, sobald Objekte zerstört werden; darum geht es in der nächsten Lektion.

challenge icon

Aufgabe

Einfach

Die Combo des Kämpfers wächst mit jedem Treffer mit der Leertaste und fällt nach comboWindow (1) Sekunde ohne Treffer wieder auf 0 zurück. Momentan setzt Fighter.cs selbst den Combo-Text und die Größe der Flamme, daher braucht es für beides ein Feld. Ändere das mit einem Ereignis:

  • Deklariere in Fighter.cs ein öffentliches Ereignis namens OnComboChanged, das die Combo (eine int) übergibt. Löse es jedes Mal mit der neuen Combo aus, wenn sich die Combo ändert, auch beim Zurücksetzen auf 0, und stelle sicher, dass ein Treffer keinen Fehler verursacht, wenn niemand darauf hört.
  • Lösche die Felder comboText und flame des Fighters sowie die Zeilen, die sie verwenden: Der Fighter weiß nichts über das HUD.
  • Abonniere in ComboText.cs und ComboFlame.cs die Methoden Show und Grow in Start() für das Ereignis des Fighters. Beide haben ein fighter-Feld, das in der Szene verknüpft ist.

Drücke Play, triff den Sandsack ein paar Mal mit der Leertaste, warte eine Sekunde und klicke dann auf Prüfen.

Probier es selbst

using UnityEngine;
using UnityEngine.InputSystem;
using TMPro;

public class Fighter : MonoBehaviour
{
    public float comboWindow = 1f;
    public TMP_Text comboText;
    public Transform flame;
    private int combo;
    private float sinceHit;

    void Update()
    {
        if (Keyboard.current.spaceKey.wasPressedThisFrame)
        {
            combo++;
            sinceHit = 0f;
            comboText.text = "Combo x" + combo;
            flame.localScale = Vector3.one * (0.5f + 0.25f * combo);
        }
        else if (combo > 0)
        {
            sinceHit += Time.deltaTime;
            if (sinceHit > comboWindow)
            {
                combo = 0;
                comboText.text = "";
                flame.localScale = Vector3.one * 0.5f;
            }
        }
    }
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Spielarchitektur in Unity