Eventos de C# en Unity
Parte de la sección Arquitectura de juegos en Unity del Journey de Unity de Coddy. Lección 10 de 50.
Cuando cambia la puntuación, hay varias cosas que dependen de 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. Ya conoces event y Action de C#. En Unity, el publicador y sus oyentes son componentes, normalmente en diferentes 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 simple 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 compilan.
ScoreKeeper no tiene ningún campo para la etiqueta y ni siquiera sabe que existe. Un contador de combos o un reproductor de sonido se suscribe de la misma manera; ScoreKeeper no cambia, y una escena de prueba sin HUD se ejecuta sin errores. Un oyente encuentra el publicador mediante una referencia del Inspector, como aquí, o de cualquier forma que conozcas, por ejemplo, con GetComponent o un singleton. Eliminar un oyente con -= es importante cuando se destruyen objetos; eso se verá en la siguiente lección.
Desafío
FácilEl combo del luchador aumenta con cada pulsación de Space y vuelve a 0 después de comboWindow (1) segundo sin recibir un golpe. Ahora mismo, Fighter.cs establece el texto del combo y el tamaño de la llama por sí mismo, así que necesita un campo para cada uno. Cámbialo para usar un evento:
- En
Fighter.cs, declara un evento público llamadoOnComboChangedque pase el combo (un int). Invócalo con el nuevo combo cada vez que cambie, incluido cuando se reinicie a 0, y asegúrate de que un golpe no cause ningún error cuando nadie esté suscrito. - Elimina los campos
comboTextyflamede Fighter, y las líneas que los usan: Fighter no sabe nada del HUD. - En
ComboText.csyComboFlame.cs, suscribe sus métodosShowyGrowal evento del luchador enStart(). Ambos tienen un campofighter, vinculado en la escena.
Pulsa Play, golpea el saco con Space unas cuantas veces, espera un segundo y luego pulsa Check.
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;
}
}
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
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 modular4Datos serializados
Clases serializablesListas en el InspectorEnumeraciones en el InspectorRepaso: tabla de botín7Máquinas de estados
Estados como clasesUna máquina de estadosTransicionesCerebros de enemigosRepaso: estados de puertas10Proyecto: Superviviente de la arena
El héroeTipos de enemigos2Interfaces en Unity
IDamageableInterfaces y TryGetComponentGetComponentsRepaso: tecla de interacción5ScriptableObjects
Recursos de datosEstadísticas de armasConfiguración compartidaOleadas como datosRepaso: base de datos de objetos