Interfaces y TryGetComponent
Parte de la sección Arquitectura de juegos en Unity del Journey de Unity de Coddy. Lección 8 de 64.
TryGetComponent solicita un componente e indica si lo encontró, todo en una sola llamada. También funciona con interfaces, por lo que es la forma habitual de preguntar a lo que sea que golpees si puede recibir daño. Esta mina daña todo lo que hay a su alrededor que sea IDamageable:
public class Mine : MonoBehaviour
{
public float radius = 3f;
public int damage = 5;
void OnTriggerEnter(Collider other)
{
foreach (Collider c in Physics.OverlapSphere(transform.position, radius))
{
if (c.TryGetComponent(out IDamageable target))
{
target.TakeDamage(damage);
}
}
Destroy(gameObject);
}
}out IDamageable target declara la variable dentro de la llamada. TryGetComponent devuelve true y asigna un valor a target cuando el objeto tiene un componente que implementa IDamageable; de lo contrario, devuelve false y target es null. Solo busca en ese objeto, nunca en su objeto padre ni en sus objetos secundarios.
GetComponent informa de manera diferente si falta una clase o una interfaz. En el Editor, GetComponent<Rigidbody>() en un objeto sin Rigidbody devuelve el null falso de Unity: == null es true, pero ?. no lo detecta y la llamada lanza MissingComponentException. Una interfaz no tiene un null falso: GetComponent<IDamageable>() devuelve un null real de C#, por lo que == null y ?. funcionan con él. TryGetComponent evita esta cuestión en ambos casos y no asigna memoria en el Editor cuando falta el componente.
Desafío
FácilEscribe Fire() en Laser: un rayo, cuatro resultados.
- Lanza
Physics.Raycastdesde la torre siguiendotransform.forward, con una longitud derange. Si no acierta, registraMissed. - Si
hit.collider.TryGetComponent(out IDamageable target), llama aTakeDamage(damage)y registra"Hit " + hit.collider.name. - Si no, si tiene un
Rigidbody, aplicaAddForce(transform.forward * push, ForceMode.Impulse)y registra"Pushed "seguido del nombre; si no,"Blocked by "seguido del nombre.
Pulsa «Jugar», gira y dispara en todas direcciones. Después, pulsa «Comprobar».
Pruébalo tú mismo
using UnityEngine;
using UnityEngine.InputSystem;
public class Laser : MonoBehaviour
{
public float range = 10f;
public int damage = 1;
public float push = 5f;
public float turnSpeed = 90f;
private InputAction moveAction;
void Start()
{
moveAction = InputSystem.actions.FindAction("Move");
}
void Update()
{
float turn = moveAction.ReadValue<Vector2>().x;
transform.Rotate(0f, turn * turnSpeed * Time.deltaTime, 0f);
if (Keyboard.current.spaceKey.wasPressedThisFrame)
{
Fire();
}
}
void Fire()
{
// Lanza un rayo hacia adelante de range unidades de longitud y gestiona lo que alcance
}
}
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