Menu
CoddyTech

Eventi C# in Unity

Fa parte della sezione Architettura dei giochi in Unity del percorso Unity di Coddy. Lezione 12 di 64.

Quando il punteggio cambia, sono diverse le cose interessate: il testo del punteggio, un suono, un obiettivo. Se ScoreKeeper chiama ognuna di esse, ha bisogno di un campo per ciascuna e ogni nuova funzionalità significa doverlo modificare. Un evento ribalta la situazione: ScoreKeeper annuncia il cambiamento e chiunque sia interessato si iscrive.

Due parole di C# rendono possibile tutto questo. Action<int> è il tipo di un metodo che accetta un int e non restituisce nulla. Un event di quel tipo è un elenco di tali metodi: altro codice aggiunge il proprio metodo con += e il proprietario li chiama tutti con Invoke. In semplice C#:

using System;

class Alarm
{
    public event Action<int> Rang;

    public void Ring(int hour)
    {
        Rang?.Invoke(hour);
    }
}

class Sleeper
{
    public void WakeUp(int hour)
    {
        Console.WriteLine("Up at " + hour);
    }
}

// altrove
Alarm alarm = new Alarm();
Sleeper sleeper = new Sleeper();
alarm.Rang += sleeper.WakeUp;
alarm.Ring(7);   // In piedi alle 7

In Unity, il mittente dell'evento e i suoi ascoltatori sono componenti, di solito su GameObject diversi:

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, sul testo dell'HUD
public ScoreKeeper keeper;
public TMP_Text label;

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

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

Action<int> significa che ogni ascoltatore è un metodo che accetta un int, in questo caso il nuovo punteggio. Invoke chiama ogni metodo iscritto, nell'ordine in cui si è iscritto. Se non ci sono ascoltatori, l'evento è null, quindi una semplice chiamata a OnScoreChanged(score) genererebbe un'eccezione NullReferenceException, mentre ?. salta la chiamata. La parola chiave event limita gli altri script a += e -=: in ScoreLabel, keeper.OnScoreChanged(5) o keeper.OnScoreChanged = null non viene compilato.

ScoreKeeper non ha un campo per l'etichetta e non sa nemmeno che esiste. Un contatore delle combo o un riproduttore audio si iscrive allo stesso modo e ScoreKeeper rimane invariato; inoltre, una scena di test senza HUD viene eseguita senza errori. Un ascoltatore trova il mittente tramite un riferimento nell'Inspector, come qui, oppure in qualsiasi altro modo tu conosca, ad esempio GetComponent o un singleton. Rimuovere un ascoltatore con -= è importante quando gli oggetti vengono distrutti: ne parleremo nella prossima lezione.

challenge icon

Sfida

Facile

Fai annunciare la combo al combattente.

  1. In Fighter.cs, aggiungi using System; e public event Action<int> OnComboChanged;.
  2. Sostituisci le righe che usano comboText e flame con OnComboChanged?.Invoke(combo); ed elimina entrambi i campi.
  3. Nel metodo Start() di ComboText e ComboFlame, scrivi fighter.OnComboChanged += Show; e += Grow;.

Premi «Gioca» e premi Spazio alcune volte: la combo aumenta, poi si azzera. Poi premi «Verifica».

Provalo tu

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;
            }
        }
    }
}

Tutte le lezioni di Architettura dei giochi in Unity

Esercitati da solo: Playground Unity