【Unity】インスペクターで変数の登録(アウトレット接続)について

2024年3月28日

Unityではインスペクターウィンドウで初期値の登録ができたり、GameObjectをドラッグ&ドロップしたりを含む初期化が可能です
ここでは、そのような使い方を基本をすでに理解されている方を対象にC#の学習を含めた機能について解説していきます

Component(ゲームオブジェクトにアタッチされている機能クラス:ゲームオブジェクトを選択した時のインスペクターに表示されているもの)をドラッグ&ドロップ

C#の継承についての学習を含めた機能紹介

スクリプトを含むコンポーネントは、すべてComponentクラスを継承しています
その様子を見てみましょう

3つのメンバーをクラス(スクリプト)で宣言しています
型はComponent型(クラス)です
なので、Componentを継承している派生クラスは代入することができます

using UnityEngine;

public class ComponentSample : MonoBehaviour
{
    public Component component1;

    [field:SerializeField]
    public Component component2 { get; set; }

    [SerializeField]
    Component component3;
}

解説

  1. public Component component1;
    • これは一番簡単な方法です。Unityで直接見えるようにして、誰でも編集できるようにします。プログラミングの中からも使えます。
  2. [field: SerializeField] public Component component2 { get; set; }
    • ここでは少し特別なやり方で、「属性」を使っています。これにより、普段は見えない設定もUnityで編集できるようになります。このやり方のいいところは、設定を変えた時に特別な動作をさせることができる点です。
  3. [SerializeField] Component component3;
    • この方法は、中の設定を外からはいじれないようにしつつ、Unityの画面からは編集できるようにする方法です。これで、大切なデータを守りつつ、必要な設定は自由に変えられます。

簡単に言うと、これらはUnityのゲーム作りで、部品をどう設定するかを選ぶための3つの方法です。ゲームを作る時の計画や、どれだけ他の人に見せたいかによって、使い分けます。

代入結果

Rigidbodyクラス、Colliderクラス、スクリプトそれぞれはComponentを継承している派生クラスなので、ドラッグ&ドロップすることができます

GameObject(ゲームオブジェクト:ヒエラルキーに存在しているもの)をドラッグ&ドロップ

GameObject型で宣言した場合、ヒエラルキーからゲームオブジェクトをドラッグ&ドロップすると、GameObject型のインスタンスが代入されます

また、Component型(またはComponentを継承している型)を指定している場合、ゲームオブジェクト自体をドラッグ&ドロップすると、そのゲームオブジェクトにアタッチされているコンポーネントリストから型に合ったインスタンスが自動的に代入されます

今回は、さっそく動画で実行状況を確認していきましょう

using UnityEngine;

public class ComponentSample : MonoBehaviour
{
    public GameObject obj;

    public BoxCollider boxCollider;

    private void Start()
    {
        Debug.Log(obj.name);
        boxCollider.isTrigger = true;
    }
}

実行時にインスタンスを取得する方法(GameObject.FindやGetComponentメソッド)との違い

今回のサンプルのような、GameObject.FindやGetComponentのようなメソッドを使用しないアプローチには、メリットとデメリットがあります

メリット

  1. パフォーマンスの向上: GameObject.FindやGetComponentは実行時にオブジェクトを検索するため、特に大きなシーンや多くのオブジェクトが存在する場合にパフォーマンスに影響を与えることがあります。エディタで直接参照を設定すると、これらの検索コストを削減できます。
  2. 型安全性の向上: エディタで直接参照を設定することで、間違った型のコンポーネントが割り当てられるリスクを減らすことができます。コード上での検索と比較して、エディタは間違った型のオブジェクトを割り当てられないため、エラーの可能性を減少させます。
  3. 開発の迅速化: エディタを使用してコンポーネントの関係を設定することで、コードを書く必要が減り、開発プロセスをスピードアップすることができます。

デメリット

  1. 柔軟性の低下: 実行時にオブジェクトの構成が変更される場合、GameObject.FindやGetComponentを使った動的な検索が必要になることがあります。エディタでの静的な設定では、このような動的な変更に対応することが難しくなります。
  2. 再利用性の問題: エディタで直接関係を設定したプレハブやコンポーネントは、他のシーンやプロジェクトで再利用する際に、再度同じ設定を行う必要があります。これは、プロジェクト間でのコンポーネントの再利用性を低下させる可能性があります。
  3. エディタ依存: エディタでの設定は、プロジェクトが複雑になるにつれて管理が難しくなる可能性があります。特に、大規模なチームで作業する場合、誰がどのオブジェクトをどのように設定したかを追跡することが困難になることがあります。

GameObject.FindやGetComponentを使わないアプローチは、適切に使用すれば多くのメリットを提供しますが、プロジェクトのニーズや動的な構成の要求に応じて慎重に検討する必要があります。

使い分け

GameObject.FindやGetComponentとエディタでの直接参照設定を使い分ける際のポイントは、主にプロジェクトの要件、パフォーマンスの最適化、開発プロセスの効率化に関連しています。ここでは、いくつかの使い分けの指針を示します。

GameObject.FindやGetComponentを使用する場面

  1. 動的なコンテンツ:
    • ゲーム中に生成されるオブジェクトや、シーンに最初から存在しないオブジェクトにアクセスする必要がある場合。例えば、ランタイムで生成される敵キャラクターに対してコンポーネントを取得したいときなどです。
  2. 柔軟性が必要な場面:
    • オブジェクトの参照が頻繁に変わる、またはプレイヤーの行動によって変わる可能性がある場合。動的なシステムや、ユーザーの入力に基づいて変化するゲームメカニクスに有効です。
  3. シーン横断的な参照が必要な場合:
    • 複数のシーンにまたがるオブジェクトや、シーンを跨いでデータを共有する必要がある場合。シーンのロード時に特定のオブジェクトを探し出すために役立ちます。

エディタでの直接参照設定を使用する場面

  1. 固定的なシーン構造:
    • ゲームの開始時から終了まで、オブジェクトの構造や関係が変わらない場合。特に、UI要素や環境オブジェクトなど、予め設定された構造を持つシーンに適しています。
  2. パフォーマンスの最適化:
    • ゲームのロード時や実行時のパフォーマンスに敏感な場合。エディタでの事前設定は、ランタイムでの検索コストを削減し、パフォーマンスを向上させます。
  3. 開発の迅速化とシンプルさ:
    • 小規模なプロジェクトやプロトタイピングの段階で、迅速に開発を進める必要がある場合。エディタを利用することで、コード量を減らし、開発プロセスをシンプルに保つことができます。

使い分けの鍵は、プロジェクトのニーズと具体的な状況を理解し、各方法のメリットとデメリットをバランスよく考慮することにあります。効率的な開発フローとパフォーマンスの最適化を目指すことが重要です。

自作クラスでは

継承状態


このコードはオブジェクト指向プログラミングの継承機能を示しています。BaseClassという基底クラスがあり、MonoBehaviourを継承しています。このクラスにはidという公開整数フィールドがあります。DerivedClassBaseClassを継承し、特に新しい機能を追加していませんが、BaseClassの機能を全て引き継いでいます。ComponentSampleクラスでは、Startメソッド内でbaseClassidフィールドに10という値を設定しています。これはUnityのゲーム開始時に一度だけ呼び出されるメソッドです。このコードは、Unity内のオブジェクト間でデータを共有し、基底クラスを通じて振る舞いを継承する方法を示しています。

今回もさっそく動画で確認していきましょう

using UnityEngine;

public class ComponentSample : MonoBehaviour
{
    public BaseClass baseClass;

    private void Start()
    {
        baseClass.id = 10;
    }
}
using UnityEngine;

public class BaseClass : MonoBehaviour
{
    public int id;
}
public class DerivedClass : BaseClass
{
}

スクリプトにインナークラスを含める

このコードは内部に[Serializable]属性を持つMyClassというクラスが定義されており、nameという公開文字列フィールドがあります。ComponentSampleクラスのStartメソッド内で、myClassnameフィールドに"太郎"という文字列を設定しています。[Serializable]属性によりMyClassはUnityエディタ上で視覚的に編集可能となり、ゲーム開始時に自動的に"太郎"という名前が設定されます。

動画で確認していきましょう

using System;
using UnityEngine;

public class ComponentSample : MonoBehaviour
{
    public MyClass myClass;

    private void Start()
    {
        myClass.name = "太郎";
    }

    [Serializable]
    public class MyClass
    {
       public string name;
    }
}

実は、インナークラスでなくても同様な結果を得られます

using System;
using UnityEngine;

public class ComponentSample : MonoBehaviour
{
    public MyClass myClass;

    private void Start()
    {
        myClass.name = "太郎";
    }
}

[Serializable]
public class MyClass
{
    public string name;
}

Unity

Posted by hidepon