Les événements C# dans Unity
Fait partie de la section Architecture de jeu dans Unity du Journey Unity de Coddy. Leçon 12 sur 64.
Lorsque le score change, plusieurs éléments sont concernés : le texte du score, un son, un succès. Si ScoreKeeper appelle chacun d’eux, il lui faut un champ pour chacun, et chaque nouvelle fonctionnalité implique de le modifier. Un événement inverse la situation : ScoreKeeper annonce le changement, et ceux qui sont concernés s’abonnent.
Deux mots de C# permettent cela. Action<int> est le type d’une méthode qui prend un int et ne renvoie rien. Un event de ce type est une liste de telles méthodes : un autre code ajoute sa méthode avec +=, et le propriétaire les appelle toutes avec Invoke. En C# classique :
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);
}
}
// ailleurs
Alarm alarm = new Alarm();
Sleeper sleeper = new Sleeper();
alarm.Rang += sleeper.WakeUp;
alarm.Ring(7); // Debout à 7Dans Unity, l’émetteur et ses abonnés sont des composants, généralement 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 abonné est une méthode qui prend un int, ici le nouveau score. Invoke appelle toutes les méthodes abonnées, dans l’ordre où elles se sont abonnées. Sans abonné, l’événement vaut null, donc un simple OnScoreChanged(score) déclencherait 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.
ScoreKeeper n’a pas de champ pour l’étiquette et ne sait pas qu’elle existe. Un compteur de combo ou un lecteur audio s’abonne de la même manière, et ScoreKeeper reste inchangé ; une scène de test sans HUD s’exécute sans erreur. Un abonné trouve l’émetteur grâce à une référence dans l’Inspector, comme ici, ou par n’importe quel moyen que tu connais, par exemple GetComponent ou un singleton. Retirer un abonné avec -= devient important une fois que les objets sont détruits, ce qui sera le sujet de la prochaine leçon.
Défi
FacileFais annoncer son combo au combattant.
- Dans
Fighter.cs, ajouteusing System;etpublic event Action<int> OnComboChanged;. - Remplace les lignes qui utilisent
comboTextetflameparOnComboChanged?.Invoke(combo);, et supprime les deux champs. - Dans le
Start()deComboTextet deComboFlame, écrisfighter.OnComboChanged += Show;et+= Grow;.
Appuie sur « Jouer » et appuie plusieurs fois sur Espace : le combo augmente, puis s’efface. Ensuite, appuie sur « Vérifier ».
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;
}
}
}
}
Toutes les leçons de Architecture de jeu dans Unity
1Des composants, pas des hiérarchies
De petits composantsUn script de base pour les ennemisComposants abstraitsDes composants qui fonctionnent ensembleRécapitulatif : tourelle modulaireRécapitulatif : canon double4Données sérialisées
Classes sérialisablesListes dans l’InspecteurÉnumérations dans l’InspecteurRécapitulatif : table de butinRécapitulatif : tirer le butin2Les interfaces dans Unity
IDamageableInterfaces et TryGetComponentGetComponentsRécapitulatif : touche d’interactionLe plus proche à portée5ScriptableObjects
Ressources de donnéesStatistiques des armesParamètres partagésSauver le ventLes vagues comme donnéesRécapitulatif : base de données des objetsRécapitulatif : acheter dans la boutique3Événements
Les événements C# dans UnityS’abonner dans OnEnableChamps UnityEventLes événements pilotent l’interfaceRécapitulatif : fenêtre de succèsRécapitulatif : minuteur de la fenêtreEntraînez-vous par vous-même : Playground Unity