Menu
CoddyTech

Schnittstellen und TryGetComponent

Teil des Abschnitts Spielarchitektur in Unity der Unity-Journey von Coddy. Lektion 8 von 64.

TryGetComponent fragt in einem Aufruf nach einer Komponente und teilt dir mit, ob eine gefunden wurde. Es funktioniert auch mit Schnittstellen und ist daher die übliche Methode, um bei einem getroffenen Objekt abzufragen, ob es verwundet werden kann. Diese Mine fügt allem in ihrer Umgebung Schaden zu, das IDamageable ist:

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 deklariert die Variable innerhalb des Aufrufs. TryGetComponent gibt true zurück und füllt target, wenn das Objekt eine Komponente hat, die IDamageable implementiert; andernfalls gibt es false zurück und target ist null. Es prüft nur dieses eine Objekt, niemals dessen übergeordnetes Objekt oder dessen Kinder.

GetComponent meldet eine fehlende Klasse und eine fehlende Schnittstelle unterschiedlich. Im Editor gibt GetComponent<Rigidbody>() bei einem Objekt ohne Rigidbody Unitys falsches null zurück: == null ist true, aber ?. erkennt es nicht und der Aufruf löst MissingComponentException aus. Eine Schnittstelle hat kein falsches null: GetComponent<IDamageable>() gibt ein echtes C#-null zurück, sodass == null und ?. beide darauf funktionieren. TryGetComponent vermeidet diese Frage bei beiden, und es allokiert im Editor nichts, wenn die Komponente fehlt.

challenge icon

Aufgabe

Einfach

Schreibe Fire() in Laser: ein Strahl, vier mögliche Ergebnisse.

  1. Führe von der Turmspitze aus entlang transform.forward einen Physics.Raycast mit der Länge range aus. Bei einem Fehlschuss protokolliere Missed.
  2. Wenn hit.collider.TryGetComponent(out IDamageable target) zutrifft, rufe TakeDamage(damage) auf und protokolliere "Hit " + hit.collider.name.
  3. Andernfalls: Wenn das Objekt ein Rigidbody hat, wende AddForce(transform.forward * push, ForceMode.Impulse) an und protokolliere "Pushed " sowie den Namen; andernfalls "Blocked by " sowie den Namen.

Drücke „Spielen“, drehe dich und feuere in jede Richtung. Drücke dann „Prüfen“.

Probier es selbst

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()
    {
        // Schicke einen Strahl nach vorn, der range Einheiten lang ist, und verarbeite, was er trifft
    }
}

Alle Lektionen in Spielarchitektur in Unity

Übe selbstständig: Unity-Playground