Événements C# dans Unity
Fait partie de la section Architecture de jeu dans Unity du Journey Unity de Coddy. Leçon 10 sur 50.
Lorsque le score change, plusieurs éléments sont concernés : le texte du score, un son, un succès. Si le ScoreKeeper appelle chacun d’eux, il lui faut un champ pour chacun, et chaque nouvelle fonctionnalité implique de le modifier. Un event inverse la logique : le ScoreKeeper annonce le changement, et ceux qui sont concernés s’abonnent. Tu connais event et Action en C#. Dans Unity, l’émetteur et ses écouteurs sont des composants, généralement placés sur différents 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, sur le texte du HUD
public ScoreKeeper keeper;
public TMP_Text label;
void Start()
{
keeper.OnScoreChanged += ShowScore;
}
void ShowScore(int score)
{
label.text = "Score: " + score;
}Action<int> signifie que chaque écouteur est une méthode qui prend un int, ici le nouveau score. Invoke appelle toutes les méthodes abonnées, dans l’ordre de leur abonnement. En l’absence d’écouteur, l’événement est null : un simple OnScoreChanged(score) déclencherait donc une NullReferenceException, tandis que ?. ignore l’appel. Le mot-clé event limite les autres scripts à += et -= : dans ScoreLabel, keeper.OnScoreChanged(5) ou keeper.OnScoreChanged = null ne compile pas.
Le ScoreKeeper n’a pas de champ pour le libellé et ne sait pas qu’il existe. Un compteur de combos ou un lecteur de sons s’abonne de la même manière ; le ScoreKeeper reste inchangé, et une scène de test sans HUD s’exécute sans erreur. Un écouteur trouve l’émetteur grâce à une référence de l’Inspector, comme ici, ou par n’importe quel moyen que tu connais, par exemple GetComponent ou un singleton. Supprimer un écouteur avec -= devient important lorsque des objets sont détruits ; c’est le sujet de la prochaine leçon.
Défi
FacileLe combo du combattant augmente à chaque pression sur Espace et retombe à 0 après comboWindow (1) seconde sans coup. Pour l’instant, Fighter.cs définit lui-même le texte du combo et la taille de la flamme ; il lui faut donc un champ pour chacun. Inverse la situation avec un événement :
- Dans
Fighter.cs, déclare un événement public nomméOnComboChangedqui transmet le combo (un int). Déclenche-le avec le nouveau combo à chaque changement, y compris lors de la réinitialisation à 0, et veille à ce qu’un coup ne provoque pas d’erreur si personne n’écoute. - Supprime les champs
comboTextetflamede Fighter ainsi que les lignes qui les utilisent : Fighter ne sait rien du HUD. - Dans
ComboText.csetComboFlame.cs, abonne leurs méthodesShowetGrowà l’événement du combattant dansStart(). Les deux ont un champfighter, relié dans la scène.
Appuie sur Play, frappe le sac avec Espace quelques fois, attends une seconde, puis clique sur Check.
Essayez vous-même
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;
}
}
}
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Architecture de jeu dans Unity
1Des composants, pas des hiérarchies
Des composants simplesUn script de base pour les ennemisDes composants abstraitsDes composants qui fonctionnent ensembleRécapitulatif : tourelle modulaire4Données sérialisées
Classes sérialisablesListes dans l’inspecteurÉnumérations dans l’inspecteurRécapitulatif : table de butin7Machines à états
Les états sous forme de classesUne machine à étatsTransitionsLes cerveaux des ennemisRécapitulatif : états d’une porte10Projet : Survivant de l’arène
Le hérosTypes d’ennemis2Interfaces dans Unity
IDamageableInterfaces et TryGetComponentGetComponentsRécapitulatif : touche d’interaction5ScriptableObjects
Assets de donnéesStatistiques des armesParamètres partagésLes vagues sous forme de donnéesRécapitulatif : base de données d’objets