Eventos de C# en Unity
Parte de la sección Arquitectura de juegos en Unity del Journey de Unity de Coddy. Lección 12 de 64.
Cuando cambia la puntuación, hay varias cosas que se interesan por ello: el texto de la puntuación, un sonido, un logro. Si ScoreKeeper llama a cada una, necesita un campo para cada una, y cada nueva característica implica editarlo. Un evento le da la vuelta a eso: ScoreKeeper anuncia el cambio y quien esté interesado se suscribe.
Dos palabras de C# hacen que esto funcione. Action<int> es el tipo de un método que recibe un int y no devuelve nada. Un event de ese tipo es una lista de esos métodos: otro código añade su método con +=, y el propietario los llama a todos con Invoke. En C# sencillo:
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);
}
}
// en otra parte
Alarm alarm = new Alarm();
Sleeper sleeper = new Sleeper();
alarm.Rang += sleeper.WakeUp;
alarm.Ring(7); // Levantado a las 7En Unity, el publicador y sus oyentes son componentes, normalmente en distintos 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, en el texto del HUD
public ScoreKeeper keeper;
public TMP_Text label;
void Start()
{
keeper.OnScoreChanged += ShowScore;
}
void ShowScore(int score)
{
label.text = "Score: " + score;
}Action<int> significa que cada oyente es un método que recibe un int, aquí la nueva puntuación. Invoke llama a todos los métodos suscritos, en el orden en que se suscribieron. Si no hay ningún oyente, el evento es null, así que una llamada directa a OnScoreChanged(score) provocaría una NullReferenceException, mientras que ?. omite la llamada. La palabra clave event limita los demás scripts a += y -=: en ScoreLabel, keeper.OnScoreChanged(5) o keeper.OnScoreChanged = null no compila.
ScoreKeeper no tiene ningún campo para la etiqueta y no sabe que existe. Un contador de combos o un reproductor de sonido se suscribe de la misma manera, y ScoreKeeper se queda tal cual; además, una escena de prueba sin HUD se ejecuta sin errores. Un oyente encuentra al publicador mediante una referencia del Inspector, como aquí, o de cualquier otra forma que conozcas, como GetComponent o un singleton. Quitar un oyente con -= es importante cuando se destruyen objetos, y ese es el tema de la próxima lección.
Desafío
FácilHaz que el luchador anuncie su combo.
- En
Fighter.cs, añadeusing System;ypublic event Action<int> OnComboChanged;. - Reemplaza las líneas que usan
comboTextyflameporOnComboChanged?.Invoke(combo);y elimina ambos campos. - En el
Start()deComboTextyComboFlame, escribefighter.OnComboChanged += Show;y+= Grow;.
Pulsa «Jugar» y presiona Espacio unas cuantas veces: el combo aumenta y después se borra. Luego, pulsa «Comprobar».
Pruébalo tú mismo
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;
}
}
}
}
Todas las lecciones de Arquitectura de juegos en Unity
1Componentes, no jerarquías
Componentes pequeñosUn script base para enemigosComponentes abstractosComponentes que trabajan juntosRepaso: torreta modularRepaso: cañón doble4Datos serializados
Clases serializablesListas en el InspectorEnumeraciones en el InspectorRepaso: tabla de botínRepaso: sortear el botín2Interfaces en Unity
IDamageableInterfaces y TryGetComponentGetComponentsRepaso: Tecla de interacciónRepaso: El más cercano al alcance5ScriptableObjects
Activos de datosEstadísticas de armasConfiguración compartidaGuardar el vientoOleadas como datosRepaso: base de datos de objetosRepaso: comprar en la tienda3Eventos
Eventos de C# en UnitySuscribirse en OnEnableCampos UnityEventLos eventos controlan la interfazRepaso: ventana emergente de logrosRepaso: temporizador de la ventana emergentePractica por tu cuenta: Playground de Unity