Menu
CoddyTech

インターフェースとTryGetComponent

CoddyのUnityジャーニー「Unityにおけるゲームアーキテクチャ」セクションの一部。レッスン 7/50。

TryGetComponentは1回の呼び出しでコンポーネントを探し、見つかったかどうかを知らせます。インターフェースにも使えるため、ぶつかった相手がダメージを受けるかどうかを調べる一般的な方法です。この地雷は、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は、呼び出しの中で変数を宣言します。オブジェクトがIDamageableを実装するコンポーネントを持つ場合、TryGetComponentはtrueを返してtargetに値を設定します。そうでなければfalseを返し、targetはnullになります。検索対象はそのオブジェクトだけで、親や子は調べません。

GetComponentは、クラスが見つからない場合とインターフェースが見つからない場合で、異なる動作をします。Editorでは、Rigidbodyを持たないオブジェクトに対してGetComponent<Rigidbody>()を呼び出すと、Unityの偽のnullが返ります。== nullはtrueになりますが、?.では検出されず、呼び出しはMissingComponentExceptionをスローします。インターフェースには偽のnullはありません。GetComponent<IDamageable>()は実際のC#のnullを返すため、== nullと?.のどちらも使えます。TryGetComponentなら、どちらの場合もこの問題を回避でき、Editorではコンポーネントが見つからなくてもメモリを割り当てません。

challenge icon

チャレンジ

簡単

レーザータワーは左右の矢印キーで回転し、Spaceキーを押すとLaser.csのFire()が呼び出されます。Fireを記述してください。タワーの前方に向けて、rangeユニットの長さのレイを飛ばし(Inspectorで10に設定されています)、次の処理を行います。

  • IDamageableを持つものに当たった場合、そのオブジェクトにTakeDamage(damage)を呼び出し、Hitとオブジェクト名をログに出力します。たとえば、Hit Robotのようになります。
  • IDamageableは持たないものの、Rigidbodyを持つ場合は、AddForce(transform.forward * push, ForceMode.Impulse)で押し、Pushedとその名前をログに出力します。
  • それ以外の場合は、Blocked byとその名前をログに出力します。たとえば、Blocked by Pillarのようになります。何にも当たらなかった場合は、Missedをログに出力します。

両方のコンポーネント検索にTryGetComponentを使ってください。IDamageable.cs、Robot.cs、Balloon.csは準備済みです。Playを押して全方向に発射し、その後Checkを押してください。

自分で試してみよう

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()
    {
        // 前方に長さ range 単位のレイを飛ばし、命中した対象を処理する
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

Unityにおけるゲームアーキテクチャのすべてのレッスン