Unityにおける継承関係でのStartライフサイクルイベント

virtual / override の利用方法と実装例


1. 概要

Unityのスクリプトでは、Start メソッドはコンポーネントが有効になったときに自動的に呼び出される初期化イベントです。
MonoBehaviourのStart自体はvirtualに定義されていませんが、複数のクラス間で共通の初期化処理を実装する場合、独自の基底クラスを作成してvirtual/overrideを利用する方法があります。


2. virtual と override の基本

  • virtual
    • 基底クラスでメソッドをvirtualとして宣言すると、派生クラスでそのメソッドを上書き(オーバーライド)できるようになります。
    • 基底クラスの共通処理を記述し、必要に応じて派生クラスで変更や追加が可能です。
  • override
    • 派生クラスで、基底クラスのvirtualメソッドの動作を上書きするために使用します。
    • 基底クラスの共通処理を引き継ぎつつ、派生クラス独自の処理を追加する場合は、base.Start() を呼び出して基底クラスの処理を実行できます。

3. 継承関係での実装例

以下は、基底クラスと派生クラスでStartメソッドをvirtual/overrideを使って実装する例です。

using UnityEngine;

// 基底クラスで共通の初期化処理を定義する
public class BaseScript : MonoBehaviour
{
    // virtualとして宣言することで、派生クラスでの上書きを許可
    protected virtual void Start()
    {
        Debug.Log("BaseScriptのStart処理");
        // 共通の初期化処理をここに記述
    }
}
using UnityEngine;

// 派生クラスで、基底クラスのStart処理を上書きして独自処理を追加
public class DerivedScript : BaseScript
{
    // overrideキーワードを使って基底クラスのStartを上書き
    protected override void Start()
    {
        Debug.Log("DerivedScriptのStart処理");

        // 必要に応じて、基底クラスのStart処理も実行する
        base.Start();

        // 追加の初期化処理があればここに記述
    }
}

4. 注意点

  • MonoBehaviourのStartメソッド
    Unity内部では、スクリプトにStartメソッドが存在するかどうかをリフレクションで検出し自動で呼び出します。そのため、通常のスクリプトではvirtual/overrideを利用する必要はありません。
    しかし、複数のクラスで共通の初期化処理を実装したい場合、独自にvirtual化したメソッドを定義するのが有効です。
  • 共通処理と個別処理の分離
    基底クラスで共通処理を定義し、派生クラスでoverrideすることで、コードの再利用性と保守性が向上します。
    派生クラス内で必要に応じて base.Start() を呼び出すことで、基底クラスの初期化処理を取り込むことができます。

5. まとめ

  • Unityでは、MonoBehaviourのStartは自動実行されるため通常の利用ではvirtual/overrideは不要ですが、
    複数クラス間での共通初期化処理を実装する際には独自の基底クラスを作成し、virtual/overrideを利用すると便利です。
  • virtual を基底クラスで定義し、override を派生クラスで実装することで、
    共通処理と個別処理を柔軟に管理でき、コードの再利用性が向上します。

このように、Unityにおける継承関係での初期化処理は、C#のvirtual/overrideの仕組みを活用することで、明確かつ効率的に実装できます。


6. テスト用チュートリアル

ここでは、上記のコード例を実際にUnity上でテストする手順を説明します。

ステップ 1: 新規プロジェクトの作成

  1. Unity Hub を起動し、新しいプロジェクト(2Dまたは3Dどちらでも可)を作成します。

ステップ 2: スクリプトの作成

  1. Assets フォルダー内で右クリック → Create > MonoBehaviour Script を選択し、BaseScript.cs と名前を付けます。
  2. 以下のコードを BaseScript.cs に貼り付けます。
using UnityEngine;

public class BaseScript : MonoBehaviour
{
    protected virtual void Start()
    {
        Debug.Log("BaseScriptのStart処理");
        // 共通の初期化処理をここに記述
    }
}
  1. 同様に、DerivedScript.cs を作成し、以下のコードを貼り付けます。
using UnityEngine;

public class DerivedScript : BaseScript
{
    protected override void Start()
    {
        Debug.Log("DerivedScriptのStart処理");
        base.Start();
        // 追加の初期化処理があればここに記述
    }
}

ステップ 3: シーンにスクリプトを配置

  1. Hierarchy ウィンドウで、Create Empty をクリックして空のGameObjectを作成します。
  2. 作成したGameObjectを選択し、Inspector ウィンドウで Add Component をクリック。
  3. DerivedScript を検索して追加します。
    ※ 基底クラスのスクリプトは自動的に継承されるため、DerivedScript をアタッチすればOKです。

ステップ 4: テストの実行

  1. シーンを保存し、Play ボタンを押して実行します。
  2. Console ウィンドウを確認すると、以下のようなログが出力されるはずです:
    • 「DerivedScriptのStart処理」
    • 「BaseScriptのStart処理」
  3. これにより、派生クラスのStartメソッドが実行され、その中で基底クラスのStartが呼ばれていることが確認できます。

ステップ 5: 実験と拡張

  • ログの順番: ログの順番を変えてみることで、base.Start() の呼び出しタイミングがどのように影響するかを学ぶことができます。
  • 追加処理: 各クラス内でさらに初期化処理を追加し、どのように継承関係が動作するか確認してみてください。
  • エラーの確認: スクリプトの内容を変更した場合、Unityエディタのコンソールにエラーが出ないか確認し、正しく動作しているかテストします。

このチュートリアルに沿って進めることで、Unityにおけるvirtual/overrideの基本的な使い方と、そのテスト方法を実践的に学ぶことができます。

DerivedScriptスクリプトを次のようにすると?

using UnityEngine;

public class DerivedScript : BaseScript
{
    void Start()
    {

    }
}

この場合、DerivedScript の Start メソッドは BaseScript の Start メソッドをオーバーライドしていないため、隠蔽(hiding)になっています。

詳細な動作

  • 隠蔽の結果
    DerivedScript で定義された Start メソッドは、BaseScript の protected virtual Start を隠してしまいます。そのため、Unity は DerivedScript の Start メソッドだけを呼び出し、BaseScript の Start 内の処理(例:Debug.Log(“BaseScriptのStart処理"))は実行されません。
  • コンパイラ警告
    同じシグネチャのメソッドを override キーワードなしで定義すると、C# コンパイラから「隠蔽している」という警告が出ることがあります。これは意図的に BaseScript の Start をオーバーライドしたい場合、override キーワードを使うべきという注意です。

まとめ

  • DerivedScript で単に void Start() { } とすると、BaseScript の Start メソッドは呼ばれず、DerivedScript の空の Start メソッドのみが実行されます。
  • BaseScript の共通初期化処理を実行したい場合は、DerivedScript で override キーワードを使い、内部で base.Start() を呼び出す必要があります。

この動作により、継承階層内で意図しない初期化処理が抜け落ちる可能性があるので注意してください。

Unity,継承

Posted by hidepon