よく使うUnity専用の関数とプロパティ【Unityスタートガイド6-9】

スクリプトでゲームを作っていると、「ほかのコンポーネントを操作したい」「オブジェクトを消したい」「別のオブジェクトを探したい」という場面が何度も出てきます。今回は、Unityのスクリプトでよく使う機能をまとめてご紹介します!

目次

この記事で学べること

  • GetComponentで、同じオブジェクトのほかのコンポーネントを使う方法
  • [SerializeField]で、ほかのオブジェクトやコンポーネントをInspectorから設定する方法
  • AwakeとStartの違い
  • SetActiveとenabledで、オブジェクトやコンポーネントのOn/Offを切り替える方法
  • Destroyでオブジェクトを消す方法
  • ほかのオブジェクトを探す方法(FindWithTagなど)

前提知識

transformとgameObject

スクリプトの中では、アタッチしているオブジェクトの情報に、いつでも次の名前でアクセスできます。

  • transform:そのオブジェクトのTransform(位置・回転・大きさ)
  • gameObject:そのオブジェクト自身
Debug.Log(gameObject.name);          // オブジェクトの名前
Debug.Log(transform.position);       // 位置
transform.localScale = Vector3.one * 2f;   // 2倍の大きさにする

位置の動かし方は6-8の記事で説明しました。

GetComponent:ほかのコンポーネントを使う

同じオブジェクトのコンポーネントを取得する

Transform以外のコンポーネント(Rigidbody、Renderer、自分で作ったスクリプトなど)を使うときは、GetComponent<型>()で取得します。

using UnityEngine;

public class ColorChanger : MonoBehaviour
{
    private Renderer targetRenderer;

    void Awake()
    {
        // 同じオブジェクトに付いているRendererを取得
        targetRenderer = GetComponent<Renderer>();
    }

    void Start()
    {
        // マテリアルの色を赤にする
        targetRenderer.material.color = Color.red;
    }
}

Cubeにアタッチして再生すると、Cubeが赤くなります。

  • < >の中に、取得したいコンポーネントの型を書きます
  • 取得は最初に1回だけ(AwakeかStart)にして、変数に入れておきます。Updateで毎回GetComponentするのは無駄が多いので避けましょう
  • 見つからないときはnullが返ってきます。そのまま使うと、5-3で紹介したNullReferenceExceptionになります

見つからないときに備える

targetRenderer = GetComponent<Renderer>();

if (targetRenderer == null)
{
    Debug.LogWarning("Rendererが付いていません");
}

必ず付いていてほしいコンポーネントなら、6-8で紹介した[RequireComponent(typeof(Renderer))]をクラスの上に書いておくのもオススメです。

親や子のコンポーネントを取得する

書き方探す場所
GetComponent<T>()自分のオブジェクト
GetComponentInChildren<T>()自分と子オブジェクト
GetComponentInParent<T>()自分と親オブジェクト

[SerializeField]で、ほかのオブジェクトを設定する

別のオブジェクトのコンポーネントを使いたいときは、Inspectorからドラッグ&ドロップで設定するのが一番簡単で確実です。

using UnityEngine;

public class TargetLooker : MonoBehaviour
{
    // Inspectorで、見たい相手のTransformを設定する
    [SerializeField] private Transform target;

    void Update()
    {
        if (target != null)
        {
            // 相手の方を向く
            transform.LookAt(target);
        }
    }
}
  • 変数の型をTransformやRigidbodyにしておくと、そのコンポーネントを持ったオブジェクトだけをドロップできます
  • 設定し忘れると「None」のままになり、NullReferenceExceptionの原因になります。エラーが出たら、まずInspectorの「None」を確認しましょう

AwakeとStart

どちらも最初に1回だけ呼ばれるメソッドですが、呼ばれる順番が違います。

メソッド呼ばれるタイミング主な使い道
Awakeオブジェクトが作られたとき(一番最初)自分の準備(GetComponent、new InputSystem_Actions()など)
Start最初のUpdateの直前ほかのオブジェクトを使う準備

シーンの中の全てのオブジェクトのAwakeが終わってから、Startが呼ばれます。なので「自分の準備はAwake、ほかのオブジェクトの情報を使うのはStart」と分けておくと、「相手の準備がまだで値が空だった」という失敗を防げます。

オブジェクトやコンポーネントのOn/Off

SetActive:オブジェクトごと表示・非表示

[SerializeField] private GameObject menuPanel;

void Start()
{
    menuPanel.SetActive(false);   // 非表示にする(子オブジェクトもまとめて)
}

3-1の記事で紹介した、Inspectorの一番上のチェックボックスと同じです。非表示のオブジェクトは、スクリプトのUpdateも止まります。

enabled:コンポーネントだけOn/Off

GetComponent<Renderer>().enabled = false;   // 見えなくする(オブジェクト自体は残る)
enabled = false;                            // このスクリプト自身を止める(Updateが呼ばれなくなる)

Destroy:オブジェクトを消す

Destroy(gameObject);           // 自分のオブジェクトを消す
Destroy(gameObject, 2f);       // 2秒後に消す
Destroy(otherObject);          // 変数に入れた別のオブジェクトを消す
  • Destroyを呼んでも、その瞬間にはまだ消えていません。そのフレームの処理が全部終わったところで消えます
  • Destroy(this)と書くと、オブジェクトではなくこのスクリプト(コンポーネント)だけが消えるので注意しましょう

オブジェクトを新しく作るInstantiateは、プレハブと一緒に第7章で説明します。

ほかのオブジェクトを探す

Inspectorで設定できない場合(途中で作られたオブジェクトなど)は、スクリプトで探します。

タグで探す:FindWithTag

GameObject player = GameObject.FindWithTag("Player");

if (player != null)
{
    Debug.Log("プレイヤーを見つけた:" + player.name);
}
  • オブジェクトのInspector上部にあるTagが「Player」のものを探します(「Player」タグは最初から用意されています)
  • 自分でタグを作る方法は、6-10の記事で説明します

型で探す:FindFirstObjectByType

PlayerMover mover = FindFirstObjectByType<PlayerMover>();

シーンの中から、そのスクリプトが付いたオブジェクトを探します。古い記事のFindObjectOfTypeは、Unity6ではFindFirstObjectByType(またはFindAnyObjectByType)に置き換わっています。

探すのは最初の1回だけ

Find系の関数は、シーンの中を全部探すので時間がかかります。Updateの中で毎フレーム探すのはやめて、AwakeかStartで1回探して変数に入れておきましょう。また、名前で探すGameObject.Find("名前")は、名前を変えたら見つからなくなるので、タグやInspectorでの設定を優先します。

実践サンプル:時間がたつと色が変わって消える

これまでの機能を組み合わせてみましょう。Cubeにアタッチして再生すると、指定した秒数で色が変わり、少しして消えます。

using UnityEngine;

[RequireComponent(typeof(Renderer))]
public class TimedBlock : MonoBehaviour
{
    [SerializeField] private float warningTime = 2f;   // 色が変わるまでの秒数
    [SerializeField] private float destroyDelay = 1f;  // 色が変わってから消えるまでの秒数
    [SerializeField] private Color warningColor = Color.red;

    private Renderer blockRenderer;
    private float timer = 0f;
    private bool isWarning = false;

    void Awake()
    {
        blockRenderer = GetComponent<Renderer>();
    }

    void Update()
    {
        if (isWarning)
        {
            return;
        }

        timer += Time.deltaTime;

        if (timer >= warningTime)
        {
            isWarning = true;
            blockRenderer.material.color = warningColor;
            Destroy(gameObject, destroyDelay);
            Debug.Log(gameObject.name + "がもうすぐ消えます");
        }
    }
}
  • Awake:自分のRendererを取得
  • Update:経過時間を数えて、時間がきたら色を変える
  • Destroy(gameObject, 秒数):少し待ってから自分を消す
  • isWarning:一度だけ処理するためのbool。これがないと、毎フレームDestroyを呼んでしまいます
  • Inspectorで時間や色を変えて、いろいろ試してみてください
スライム

GetComponentで取ったはずなのに、nullって言われる・・・

フェアリー

まずは本当にそのコンポーネントが付いているか、Inspectorを見てみよう!付いているのに取れないときは、子オブジェクトに付いていないかも確認してね

よくあるエラーと対処法

エラー:NullReferenceException(GetComponentの結果を使ったとき)

  • 原因:取得したいコンポーネントが、そのオブジェクトに付いていない
  • 対処法:Inspectorで付いているか確認する。子オブジェクトに付いている場合はGetComponentInChildrenを使う

エラー:UnassignedReferenceException: The variable ○○ has not been assigned

  • 原因:[SerializeField]の変数を、Inspectorで設定し忘れている
  • 対処法:Inspectorで「None」になっている欄に、オブジェクトをドラッグ&ドロップする

エラー:FindWithTagで見つからない(nullになる)

  • 原因:探したいオブジェクトのTagが設定されていない、タグ名のつづりが違う、またはオブジェクトが非表示(SetActive(false))になっている
  • 対処法:InspectorのTagを確認する。非表示のオブジェクトはFindで見つけられないので、Inspectorでの設定を使う

エラー:’Object.FindObjectOfType’ is obsolete

  • 原因:古い書き方を使っている
  • 対処法:FindFirstObjectByTypeに書き換える

エラー:Destroyしたのに、すぐ後の処理でまだオブジェクトが残っている

  • 原因:Destroyは、そのフレームの最後に消える
  • 対処法:消えたかどうかに頼らず、boolで「消える予定」を管理する(上のサンプルのisWarningのように)

まとめ

  • GetComponent:同じオブジェクトのほかのコンポーネントを取得(AwakeかStartで1回だけ)
  • [SerializeField]:ほかのオブジェクトはInspectorで設定するのが一番確実
  • Awake → Start:自分の準備はAwake、ほかのオブジェクトを使う準備はStart
  • SetActive / enabled:オブジェクト全体、またはコンポーネントだけのOn/Off
  • Destroy:オブジェクトを消す(そのフレームの最後に消える)
  • FindWithTag / FindFirstObjectByType:スクリプトで探す(最初に1回だけ)

次のステップ

第6章の最後は、オブジェクト同士がぶつかったことをスクリプトで受け取る方法です:

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメント一覧 (1件)

コメントする

目次