👻

Unity×C#でわかる!継承とポリモーフィズム : 中級者向けゲーム設計入門

2024/12/30に公開

Unity×C#でわかる!継承とポリモーフィズム : 中級者向けゲーム設計入門

C#プログラミングにおいて、継承とポリモーフィズムは押さえておきたい重要な概念の一つです。特にUnityのようにオブジェクト指向の仕組みを多用するゲームエンジンでは、継承を使った設計と多態性(ポリモーフィズム)を活かしたコードの書き方が、プロジェクトの拡張性や可読性を大きく左右します。本記事では、継承とポリモーフィズムの基礎からUnityでの実装例までを丁寧に解説していきます。

なぜ継承とポリモーフィズムが重要なのか

複数クラスの共通処理をまとめられる

ゲーム開発では、キャラクターや敵、アイテムなど多種多様なクラスが必要になります。もし全てのクラスで共通する処理を「コピペ」で書くと、修正や拡張が発生するたびにコードをあちこち直さなければなりません。継承を使えば共通部分は親クラス(基底クラス)で持ち、個別の動作を子クラスで実装できるため、保守性が高まります。

柔軟な挙動を後から追加できる

ポリモーフィズム(多態性)は「同じ型でも、実際には違う挙動を実装できる」仕組みです。C#ではvirtualabstractoverrideキーワードを使うことで、基底クラスのメソッドを子クラス側で自由に上書きし、新たな動きを与えられます。
たとえば「敵キャラ共通クラスEnemyを継承して、ボスキャラだけ特殊攻撃を付加する」といった具合に、最小限の修正で新たな機能を追加しやすくなります。

UnityではMonoBehaviourを基底クラスとする

Unityのスクリプトは一般的にMonoBehaviourを継承する形で書かれています。つまり、Unity環境自体が継承をベースに設計されており、いわば「継承の恩恵を活用する」構造になっています。自作の基底クラスでさらに拡張し、ポリモーフィズムを組み合わせれば、大規模開発でも管理しやすいアーキテクチャを構築できるでしょう。

C#の継承:基本構文と注意点

クラスの継承構文

// 親クラス(基底クラス)
public class Character
{
    public string characterName;
    public int hp;

    public virtual void Attack()
    {
        Debug.Log(characterName + "の攻撃!");
    }
}

// 子クラス(派生クラス)
public class Warrior : Character
{
    // Warrior独自のプロパティ
    public int stamina;

    // Attackメソッドを上書き
    public override void Attack()
    {
        // base.Attack()で親クラスの処理を呼び出しつつ、追加のロジックを実行
        base.Attack();
        Debug.Log("さらに、剣で追撃!");
    }
}
  • public class 子クラス : 親クラスの形で宣言
  • 基底クラス側をvirtual、派生クラス側をoverrideにすることで、多態的に振る舞えるメソッドを作成
  • base.メソッド名を呼び出すと、親クラスの処理を一部引き継げます

abstractクラス・abstractメソッド

public abstract class Enemy
{
    public string enemyName;

    // 派生クラスで必ず実装させたいメソッド
    public abstract void Attack();

    // 共通処理
    public void PrintName()
    {
        Debug.Log("敵の名前は" + enemyName);
    }
}
  • abstractクラス:インスタンスを直接作れないクラス
  • abstractメソッド:派生クラスで必ず実装を強制するメソッド

抽象クラスを使えば「派生クラスが必ずこのメソッドを持つ」という仕様を明示できるため、プロジェクト規模が大きくなるほどコードの一貫性を保ちやすくなります。

シールクラスとシールメソッド

public sealed class FinalClass
{
    // これ以上継承されないクラス
}

// シールメソッド
public class BaseClass
{
    public virtual void SpecialAttack() { }
}

public class ChildClass : BaseClass
{
    public sealed override void SpecialAttack()
    {
        // このメソッドはこれ以上のoverrideを許可しない
    }
}
  • sealedクラス:継承を禁止してクラス階層の深掘りを防ぎたい場合に使用
  • sealed override:特定のメソッドのみ更なるオーバーライドをブロックできる

通常、ゲームでは柔軟性を重視してsealedを多用するケースは少ないですが、APIレベルで公開したくない機能を制限する際に役立ちます。

ポリモーフィズム(多態性):同じ呼び出しでも結果が異なる仕組み

overrideとオーバーロードの違い

  • override:親クラスと同じシグネチャのメソッドを上書きし、実行結果を変更
  • オーバーロード:同じメソッド名でも、引数の数や型が違うバリエーションを増やすだけで、ポリモーフィズムとは別概念
public class Mage : Character
{
    // overrideによる上書き
    public override void Attack()
    {
        Debug.Log("魔法で遠距離攻撃!");
    }

    // オーバーロードによる引数違い
    public void Attack(int spellPower)
    {
        Debug.Log("魔力" + spellPower + "の魔法攻撃!");
    }
}

インターフェースとの違い

インターフェース(interface)はクラスではなく、実装を含まない「仕様の塊」です。

  • 継承:親クラスのメソッドやプロパティを引き継いで利用・上書きできる
  • インターフェース:メソッドのシグネチャのみ定義し、それを複数クラスで同じように実装

ゲーム開発では「特定の能力を持つ」共通インターフェースを用意して、複数クラスに実装させるケースもありますが、継承や抽象クラスとは別の使い方をすることが多いです。

Unityで多態性を活かす実装例

ここからは実際にUnity上で継承とポリモーフィズムを組み合わせた例を見ていきましょう。典型的なのは「敵クラスの基底Enemy」と「ボスや小型敵など、具体的な子クラス」による実装です。

1. 基底Enemyクラス

using UnityEngine;

public abstract class Enemy : MonoBehaviour
{
    public string enemyName;
    public int hp;

    // abstractメソッド
    public abstract void Attack();

    // 共通メソッド
    public void TakeDamage(int damage)
    {
        hp -= damage;
        Debug.Log(enemyName + "は" + damage + "のダメージを受けた!HP: " + hp);
        if(hp <= 0)
        {
            Death();
        }
    }

    void Death()
    {
        Debug.Log(enemyName + "は倒れた…");
        // 何らかの消滅処理
        Destroy(gameObject);
    }
}
  • MonoBehaviourを継承する抽象クラス
  • Attack()を必ず派生クラスで実装させる
  • TakeDamage()は全敵共通の処理を提供

2. 小型敵(Slime)クラス

public class Slime : Enemy
{
    void Start()
    {
        enemyName = "スライム";
        hp = 30;
    }

    public override void Attack()
    {
        Debug.Log(enemyName + "の体当たり攻撃!");
        // 体当たりロジック
    }
}
  • Enemyを継承
  • Attack()overrideで具体的に実装(スライム固有の攻撃)

3. ボス敵(Dragon)クラス

public class Dragon : Enemy
{
    void Start()
    {
        enemyName = "ドラゴン";
        hp = 200;
    }

    public override void Attack()
    {
        Debug.Log(enemyName + "は炎を吐いた!");
        // 炎ブレスロジック
    }
}
  • 同じAttack()メソッドを、ドラゴン用に全く別の処理で実装
  • 「Enemy型」に統一的にアクセスできても、実際には多態的に処理が変わる

4. ゲーム内での呼び出し

public class EnemyManager : MonoBehaviour
{
    // シーンに配置された敵オブジェクトをまとめて管理
    private Enemy[] enemies;

    void Start()
    {
        enemies = FindObjectsOfType<Enemy>();
        // Enemyを継承した全クラス(SlimeやDragon)が格納される
    }

    void Update()
    {
        // テスト:スペースキーで全敵が攻撃
        if(Input.GetKeyDown(KeyCode.Space))
        {
            foreach(var e in enemies)
            {
                e.Attack(); 
                // ここではEnemy型だが、実際にはSlimeやDragonのAttack()が呼ばれる
            }
        }
    }
}
  • FindObjectsOfType<Enemy>()で、シーン上のEnemyを継承したオブジェクト全てを取得
  • 1行のe.Attack()呼び出しで、各クラス独自の攻撃を多態的に実行できる

このようにポリモーフィズムを活かすと、敵の種類が増えてもAttack()を追加実装するだけで拡張でき、EnemyManager側のコード変更を最小限に抑えられます。

継承とポリモーフィズムがもたらすメリット・デメリット

メリット

  1. 共通処理の一元化
    バグ修正やロジック変更があっても、基底クラスを直すだけで全子クラスに反映されます。
  2. 柔軟な拡張性
    新しい種類の敵やキャラクターを追加しても、最小限の変更で済むため開発が楽になります。
  3. 可読性の向上
    コードを「抽象度の高い基底部分」と「具体的な派生部分」に分けて整理できるため、大規模プロジェクトでも見通しを保ちやすいです。

デメリット

  1. 複雑化のリスク
    クラス階層を深くしすぎると、継承関係の把握が難しくなります。
  2. 単一継承の制約
    C#では複数のクラスから同時に継承できないため、設計によってはインターフェースとの組み合わせが必要になる場合もあります。
  3. 使い分けの学習コスト
    抽象クラスやインターフェースなど複数の仕組みがあるので、チームで統一的なコーディングルールを決めないと混乱が生じやすくなります。

応用:コンポーネント指向設計との融合

Unityは、継承と同じくらい「コンポーネント指向」が重要な世界です。GameObjectに複数のコンポーネント(スクリプトやColliderなど)を付け足して機能を拡張していきます。

  • 「動き自体は親クラスで共通化し、各種ステータスはScriptableObjectなど別コンポーネントに分離」
  • 「パーティクル演出やサウンド制御は、独立したコンポーネントに任せる」

このように継承とコンポーネント指向をバランスよく使い分けることで、重複コードを減らしながら高い拡張性を実現できます。

実装イメージ
  • SlimeDragonはEnemyを継承しつつ、HP表示やパーティクルなど各種コンポーネントを必要に応じて追加

まとめ:継承とポリモーフィズムを駆使して拡張性の高いUnity開発を

C#の継承とポリモーフィズムは、ゲーム開発において大きな威力を発揮する仕組みです。

  • 基底クラスで共通機能を提供し、子クラスで具体的挙動を実装
  • 多態性(ポリモーフィズム)により、一括管理しつつ多様な動きを実現
  • 抽象クラスやインターフェース、コンポーネント指向などの合わせ技で高い柔軟性を確保

Unity特有のMonoBehaviour継承も、C#のオブジェクト指向を理解しておけばより活かしやすくなります。設計段階で「どの部分を共通化し、どこを派生クラスに任せるか」を明確にすることで、後々の拡張も楽になり、メンテナンスコストを大幅に抑えられるでしょう。

この記事を読んでもっと実践したいと感じたあなたへ

Unity開発を効率よく進めるためには、実践的なスキルと仲間との交流が欠かせません。
そんな方におすすめのステップが、下記の3つです。

1. 有料教材「どこでもUnity教室」でゲーム制作を短期マスター

  • 5日でシンプルなFPS完成:初心者向けに要点を押さえたカリキュラム
  • C#や最新のInputSystem、FPS実装まで網羅:つまずきやすいポイントを先回りで解説
  • 購入特典:Discord招待+サンプルプロジェクトDLで、疑問や実装例を即確認

たった5日でFPSゲームが作れる自分に変わる教材はこちら
https://zenn.dev/ryuryu_game/books/fd28de9d8e963a

2. 無料コミュニティで、疑問をすぐに解消&モチベーションUP

  • 初心者~中級者までOK:学習進度に合わせて質問や情報共有
  • 質問サポートが充実:わからないことを仲間や講師に即相談
  • 学習仲間と切磋琢磨:一緒に学ぶから続けやすい

Discordサーバー参加はこちら
https://discord.gg/5FwuKCacNy

3. 実績豊富な“ゲーム開発所RYURYU”があなたをトータルサポート

  • コナラ総販売200件超:さまざまなUnity開発の依頼を対応
  • VR/AR/AIなど最新技術にも精通:幅広いノウハウを活かして開発支援
  • ゲームクリエイター甲子園や東京ゲームショウなど出展実績多数

ご相談・お問い合わせはこちら
https://coconala.com/users/1772507

継承やポリモーフィズムの理解が深まれば、Unityでの開発の幅はぐんと広がります。ぜひこれらのリソースを活用して、さらに実践的なスキルアップを目指してみてください。

Discussion