1. はじめに
Unityでゲームを作っていると、「コードがどんどん増えて、どこで何をしているのかわからなくなった……」という経験はありませんか?
特にゲーム開発では、キャラクターの動き、敵のAI、スコアの管理、UIの制御など、さまざまな要素をスクリプトで制御するため、気づけば長大なコードが一つのスクリプトに詰め込まれてしまうこともよくあります。
例えば、プレイヤーの移動を処理するスクリプトに、攻撃やアイテムの取得、ダメージ処理まで全部詰め込んでしまうと、後から修正や機能追加をするたびに影響範囲が広がり、バグを生みやすくなります。
こうした問題を避けるには、**「スクリプトの整理」**がとても重要です。
SOLID原則を適用するとコードがどう整理されるのか
そこで役立つのが 「SOLID原則」 というオブジェクト指向プログラミングの考え方です。
SOLID原則とは、スクリプトを整理し、管理しやすくするための5つのルール であり、これを意識することで以下のようなメリットがあります。
- スクリプトがシンプルになる → 一つのスクリプトが一つの役割を持つため、どこで何をしているのかが明確になる
- 変更がしやすくなる → 影響範囲が小さくなるため、修正や機能追加が簡単になる
- バグが減る → 一つのスクリプトに多くの処理を書かないので、意図しないバグを防ぎやすくなる
つまり、SOLID原則を意識することで、「わかりやすく、管理しやすいスクリプト」 を書くことができるのです。
記事の概要(初心者向けにわかりやすく解説)
この記事では、Unityのスクリプトを整理するために役立つ SOLID原則の基本と、実際のUnityスクリプトでの適用方法 をわかりやすく解説していきます。
- SOLID原則とは何か?
- Unityのスクリプトにどう適用すればいいのか?
- 具体的なコード例を使った解説
これらを順番に説明しながら、今すぐ使える実践的なスクリプト整理術 を紹介していきます!
Unityのコードをスッキリ整理して、スムーズなゲーム開発を目指しましょう!
2. SOLID原則とは?
オブジェクト指向設計の基本
ゲーム開発では、多くのオブジェクト(キャラクター、敵、アイテム、UI など)が登場し、それぞれがさまざまな処理を行います。そのため、オブジェクトごとの役割を明確にし、拡張しやすく、バグを少なくするための**「設計のルール」**が重要になります。
そこで登場するのが**「オブジェクト指向設計」**です。オブジェクト指向では、スクリプトを「役割ごとの部品」として作り、それらを組み合わせてゲームを構築します。適切に設計することで、コードの管理がしやすくなり、変更や追加が簡単になります。
しかし、ただ「オブジェクトを分ける」だけでは、適切な設計にならないこともあります。
そこで役立つのが、SOLID原則 という5つのルールです。
SOLIDの5つの原則の概要
SOLID原則とは、「オブジェクト指向設計を正しく行うためのルール」 であり、以下の5つの原則から成り立っています。
- S(単一責任の原則 – Single Responsibility Principle)
- O(オープン・クローズドの原則 – Open/Closed Principle)
- L(リスコフの置換原則 – Liskov Substitution Principle)
- I(インターフェース分離の原則 – Interface Segregation Principle)
- D(依存関係逆転の原則 – Dependency Inversion Principle)
それぞれの原則について、Unityでの具体的な適用例を交えて説明していきます。
S:単一責任の原則(Single Responsibility Principle)
「1つのクラス(スクリプト)は、1つの責務(役割)のみを持つべき」
❌ 悪い例(NGな書き方)
public class Player : MonoBehaviour
{
public void Move() { /* 移動処理 */ }
public void Attack() { /* 攻撃処理 */ }
public void TakeDamage() { /* ダメージ処理 */ }
public void DisplayHealthUI() { /* HP表示 */ }
}
このように、「移動」「攻撃」「ダメージ処理」「UI表示」など、さまざまな責任を1つのクラスが持っていると、修正が大変になります。
✅ 良い例(単一責任に分割)
public class PlayerMovement : MonoBehaviour
{
public void Move() { /* 移動処理 */ }
}
public class PlayerCombat : MonoBehaviour
{
public void Attack() { /* 攻撃処理 */ }
}
public class PlayerHealth : MonoBehaviour
{
public void TakeDamage() { /* ダメージ処理 */ }
}
public class PlayerUI : MonoBehaviour
{
public void DisplayHealthUI() { /* HP表示 */ }
}
こうすることで、それぞれの役割が明確になり、修正や拡張がしやすくなります。
O:オープン・クローズドの原則(Open/Closed Principle)
「クラス(スクリプト)は拡張に対して開いていて、修正に対して閉じているべき」
これは、既存のコードを修正せずに、新しい機能を追加できるように設計するべき、という考え方です。
❌ 悪い例(直接クラスを修正する)
public class Enemy
{
public void Attack() { /* 通常攻撃 */ }
}
もし新しい「魔法攻撃」タイプの敵を作りたくなった場合、Enemy
クラスを直接修正しなければなりません。
✅ 良い例(拡張可能な設計)
public abstract class Enemy : MonoBehaviour
{
public abstract void Attack();
}
public class MeleeEnemy : Enemy
{
public override void Attack() { /* 近接攻撃 */ }
}
public class MagicEnemy : Enemy
{
public override void Attack() { /* 魔法攻撃 */ }
}
このように、基盤となるクラス(Enemy)を変更せずに、新しいタイプの敵を追加 できます。
L:リスコフの置換原則(Liskov Substitution Principle)
「子クラス(サブクラス)は、親クラス(スーパークラス)として代用できるべき」
サブクラスが、親クラスの代わりとして問題なく動作するべき、という原則です。
❌ 悪い例(サブクラスが親クラスのルールを破る)
public class Bird
{
public virtual void Fly() { Debug.Log("鳥が飛ぶ"); }
}
public class Penguin : Bird
{
public override void Fly() { throw new System.Exception("ペンギンは飛べません!"); }
}
この場合、ペンギンは Bird
を継承していますが、「飛べない」という例外を出してしまっています。これは良くない設計です。
✅ 良い例(適切な継承)
public abstract class Bird { }
public class FlyingBird : Bird
{
public void Fly() { Debug.Log("鳥が飛ぶ"); }
}
public class Penguin : Bird
{
public void Swim() { Debug.Log("ペンギンが泳ぐ"); }
}
このように、「飛べる鳥」と「泳ぐ鳥」を別々に定義 することで、問題を解決できます。
I:インターフェース分離の原則(Interface Segregation Principle)
「大きなインターフェースを、小さなインターフェースに分割するべき」
❌ 悪い例(1つのインターフェースに多すぎる機能)
public interface ICharacter
{
void Attack();
void CastMagic();
void Heal();
}
すべてのキャラクターが魔法を使うわけではないので、これは適切ではありません。
✅ 良い例(インターフェースを分割)
public interface IAttacker { void Attack(); }
public interface IMagicUser { void CastMagic(); }
public interface IHealer { void Heal(); }
これにより、必要な機能だけを実装できます。
D:依存関係逆転の原則(Dependency Inversion Principle)
「高レベルモジュールは、低レベルモジュールに直接依存せず、抽象に依存するべき」
❌ 悪い例(具体的なクラスに依存している)
public class Game
{
private Player player = new Player();
}
✅ 良い例(抽象化を利用)
public class Game
{
private ICharacter character;
public Game(ICharacter character)
{
this.character = character;
}
}
これにより、ICharacter
を実装した異なるキャラクター(Player
や Enemy
など)を簡単に変更できます。
「SOLID原則を適用すると、コードの可読性が上がり、管理しやすくなります。ただし、MonoBehaviourを継承したスクリプトのプロパティが増えてくると、インスペクターが見づらくなることも…。
そんなときに役立つのが Odin Inspector and Serializer です。
このアセットを使うと、スクリプトを整理しながら、見やすいカスタムインスペクターを簡単に作成できます!」

SOLID原則を意識することで、Unityのスクリプトを整理し、メンテナンスしやすいコードを作ることができます。次のセクションでは、具体的なUnityスクリプトにSOLID原則を適用する方法を詳しく解説していきます!
3. UnityスクリプトにSOLID原則を適用する方法
ここでは、UnityのスクリプトにSOLID原則をどのように適用できるのか、具体例を交えながら解説していきます。
単一責任の原則(SRP)
「1つのスクリプトは、1つの役割のみを持つようにする」
❌ 悪い例(1つのスクリプトに複数の役割を持たせる)
public class Player : MonoBehaviour
{
public void Move() { /* プレイヤーの移動処理 */ }
public void Attack() { /* 攻撃処理 */ }
public void TakeDamage() { /* ダメージ処理 */ }
}
このコードでは、「移動」「攻撃」「ダメージ処理」がすべて Player
クラスに詰め込まれており、スクリプトが複雑になっています。
✅ 良い例(役割ごとにスクリプトを分割)
public class PlayerMovement : MonoBehaviour
{
public void Move() { /* プレイヤーの移動処理 */ }
}
public class PlayerCombat : MonoBehaviour
{
public void Attack() { /* 攻撃処理 */ }
}
public class PlayerHealth : MonoBehaviour
{
public void TakeDamage() { /* ダメージ処理 */ }
}
こうすることで、各スクリプトが1つの責任に集中し、コードの管理がしやすくなります。例えば、移動のロジックを変更する場合、PlayerMovement
だけを編集すればよくなります。
オープン・クローズドの原則(OCP)
「既存のコードを変更せずに拡張できる設計にする」
例えば、敵の攻撃パターンを増やしたいとき、直接 Enemy
クラスを変更すると、バグが発生しやすくなります。
❌ 悪い例(敵の攻撃タイプを直接 Enemy
クラスに追加)
public class Enemy : MonoBehaviour
{
public void Attack(string type)
{
if (type == "Melee") { /* 近接攻撃 */ }
else if (type == "Ranged") { /* 遠距離攻撃 */ }
}
}
攻撃タイプが増えるたびに Enemy
クラスを修正する必要があり、拡張しづらくなります。
✅ 良い例(拡張可能な設計 – 継承を活用)
public abstract class Enemy : MonoBehaviour
{
public abstract void Attack();
}
public class MeleeEnemy : Enemy
{
public override void Attack() { /* 近接攻撃処理 */ }
}
public class RangedEnemy : Enemy
{
public override void Attack() { /* 遠距離攻撃処理 */ }
}
こうすることで、新しい攻撃パターンを追加する場合、新しいクラスを作るだけで済みます。Enemy
クラスを直接変更する必要がないため、安全に拡張できます。
リスコフの置換原則(LSP)
「サブクラスはスーパークラスと完全に互換性を持つべき」
これは、親クラスの代わりとしてサブクラスが正常に動作するようにする というルールです。
❌ 悪い例(サブクラスが親クラスの想定を崩してしまう)
public class Bird
{
public virtual void Fly() { Debug.Log("鳥が飛ぶ"); }
}
public class Penguin : Bird
{
public override void Fly() { throw new System.Exception("ペンギンは飛べません!"); }
}
このコードでは、Bird
を継承している Penguin
ですが、「飛べない」ため、親クラスの振る舞いを壊してしまっています。
✅ 良い例(適切な継承関係)
public abstract class Bird { }
public class FlyingBird : Bird
{
public void Fly() { Debug.Log("鳥が飛ぶ"); }
}
public class Penguin : Bird
{
public void Swim() { Debug.Log("ペンギンが泳ぐ"); }
}
「飛ぶ鳥」と「泳ぐ鳥」を別々のクラスに分けることで、リスコフの置換原則を守ることができます」。
インターフェース分離の原則(ISP)
「大きなインターフェースを、小さなインターフェースに分割する」
❌ 悪い例(1つのインターフェースに多すぎる機能)
public interface ICharacter
{
void Attack();
void CastMagic();
void Heal();
}
すべてのキャラクターが魔法を使うわけではないため、不適切な設計です。
✅ 良い例(インターフェースを分割)
public interface IAttacker { void Attack(); }
public interface IMagicUser { void CastMagic(); }
public interface IHealer { void Heal(); }
こうすることで、必要な機能だけを実装できるため、不要なメソッドを無理に実装する必要がなくなります。
依存関係逆転の原則(DIP)
「依存関係を抽象化することで、柔軟な設計にする」
この原則では、高レベルモジュール(ゲーム全体の流れを制御する部分)が、低レベルモジュール(個々のクラス)に直接依存しないようにします。
❌ 悪い例(特定のクラスに直接依存している)
public class Game
{
private Player player = new Player();
}
この場合、Game
クラスは Player
クラスに強く依存しており、別のキャラクターに変更するのが難しくなります。
✅ 良い例(依存関係を抽象化する)
public class Game
{
private ICharacter character;
public Game(ICharacter character)
{
this.character = character;
}
}
こうすることで、ICharacter
を実装した Player
や Enemy
など、異なるキャラクターを簡単に変更できます。
まとめ
SOLID原則をUnityのスクリプトに適用することで、整理しやすく、拡張しやすいコード を作ることができます。
✅ 単一責任の原則(SRP) → スクリプトを役割ごとに分割
✅ オープン・クローズドの原則(OCP) → 既存のコードを変更せずに新機能を追加
✅ リスコフの置換原則(LSP) → サブクラスが親クラスとして問題なく動作するようにする
✅ インターフェース分離の原則(ISP) → インターフェースを小さく分割し、不要な実装を防ぐ
✅ 依存関係逆転の原則(DIP) → 抽象クラスやインターフェースを使って依存関係を柔軟にする

次のセクションでは、具体的なUnityプロジェクトでのコード適用例をさらに詳しく解説 していきます!
4. SOLID原則を使ったUnityスクリプトの具体的な実装
ここでは、SOLID原則をUnityスクリプトに適用する具体的な実装方法を紹介します。特に MonoBehaviour を継承する場合の注意点 や、既存のコードをSOLID設計にリファクタリングする手順 についても詳しく解説していきます。
サンプルコードを用いた具体的な適用方法
単一責任の原則(SRP)を適用したスクリプトの整理
❌ 改善前(1つのスクリプトに複数の責務がある)
public class Player : MonoBehaviour
{
public void Move() { /* 移動処理 */ }
public void Attack() { /* 攻撃処理 */ }
public void TakeDamage() { /* ダメージ処理 */ }
public void DisplayHealthUI() { /* HPをUIに表示 */ }
}
このように、移動、攻撃、ダメージ処理、UIの更新が1つのスクリプトにまとまってしまうと、修正や拡張が難しくなります。
✅ 改善後(責務ごとにスクリプトを分割)
public class PlayerMovement : MonoBehaviour
{
public void Move() { /* 移動処理 */ }
}
public class PlayerCombat : MonoBehaviour
{
public void Attack() { /* 攻撃処理 */ }
}
public class PlayerHealth : MonoBehaviour
{
public void TakeDamage() { /* ダメージ処理 */ }
}
public class PlayerUI : MonoBehaviour
{
public void DisplayHealthUI() { /* HP表示処理 */ }
}
こうすることで、各スクリプトが1つの役割に集中し、コードの管理がしやすくなります。
オープン・クローズドの原則(OCP)を適用した拡張性のあるスクリプト
❌ 改善前(既存のクラスを直接変更しなければならない設計)
public class Enemy : MonoBehaviour
{
public void Attack(string type)
{
if (type == "Melee") { /* 近接攻撃処理 */ }
else if (type == "Ranged") { /* 遠距離攻撃処理 */ }
}
}
この場合、新しい攻撃タイプを追加するたびにEnemy
クラスを編集しなければならず、コードが膨れ上がります。
✅ 改善後(拡張可能な設計 – 継承を活用)
public abstract class Enemy : MonoBehaviour
{
public abstract void Attack();
}
public class MeleeEnemy : Enemy
{
public override void Attack() { /* 近接攻撃処理 */ }
}
public class RangedEnemy : Enemy
{
public override void Attack() { /* 遠距離攻撃処理 */ }
}
こうすることで、新しい攻撃パターンを追加する場合、新しいクラスを作るだけで済み、既存のEnemy
クラスを変更する必要がなくなります。
MonoBehaviourを継承する場合の注意点
Unityでは、多くのスクリプトが MonoBehaviour
を継承しているため、継承の使いすぎに注意 する必要があります。
MonoBehaviourを継承するクラスを減らす工夫
MonoBehaviour
を継承すると、GameObject にアタッチする必要がある ため、以下のように適切に分離するのが理想です。
❌ 悪い例(不要にMonoBehaviourを継承)
public class PlayerCombat : MonoBehaviour
{
public void Attack() { /* 攻撃処理 */ }
}
この場合、PlayerCombat
は MonoBehaviour
を継承していますが、攻撃の処理自体には MonoBehaviour
の機能は不要 です。
✅ 良い例(MonoBehaviourを継承せずに、他のクラスで利用する)
public class PlayerCombat
{
public void Attack() { /* 攻撃処理 */ }
}
public class Player : MonoBehaviour
{
private PlayerCombat combat = new PlayerCombat();
public void PerformAttack()
{
combat.Attack();
}
}
こうすることで、PlayerCombat
を通常のC#クラスとして扱い、MonoBehaviourを継承するクラスを減らすことでスクリプトを整理できます。
SOLID設計を意識したコードリファクタリングの手順
- 単一責任の原則(SRP)を意識して、1つのスクリプトが1つの役割を持つようにする
- 移動、攻撃、UI管理などを分割する
- 必要に応じて
MonoBehaviour
の継承を外す
- オープン・クローズドの原則(OCP)を適用し、新機能を追加しやすい設計にする
abstract
クラスを利用し、既存のコードを変更せずに拡張できるようにする- 例:
Enemy
クラスをMeleeEnemy
とRangedEnemy
に分ける
- リスコフの置換原則(LSP)を考慮し、サブクラスが親クラスとして違和感なく動作するか確認する
- 例:
FlyingBird
とPenguin
をBird
クラスから適切に分離する
- 例:
- インターフェース分離の原則(ISP)を適用し、必要な機能だけを実装できるようにする
- 例:
ICharacter
インターフェースを分割し、IAttacker
、IMagicUser
、IHealer
などの細かいインターフェースにする
- 例:
- 依存関係逆転の原則(DIP)を利用し、柔軟にコンポーネントを管理できるようにする
- 依存関係を
ICharacter
のようなインターフェースにし、具体的なクラスに依存しないようにする - 例:
Game
クラスがPlayer
ではなく、ICharacter
を使うようにする
- 依存関係を
まとめ
✅ SOLID原則を適用すると、スクリプトが整理され、修正・拡張がしやすくなる
✅ MonoBehaviourを継承する場合は、本当に必要かどうか考える
✅ 既存のスクリプトをリファクタリングすることで、より良い設計にできる
「SOLID原則を意識すると、スクリプトの役割を分け、整理されたプロジェクト構造を作ることが重要です。
しかし、スクリプトが増えてくると、インスペクターの表示が乱雑になったり、オブジェクト管理が煩雑になることも…。
そこで便利なのが Odin Inspector and Serializer です。
カスタムインスペクターを活用することで、プロジェクトの管理が劇的に楽になります!」

次のセクションでは、SOLID原則を適用したプロジェクトの管理方法について 解説していきます!
5. SOLID原則を適用したプロジェクト管理のコツ
SOLID原則を理解し、スクリプトを適切に設計したとしても、プロジェクト全体の管理が不十分だと、スクリプトが増えるにつれて混乱しやすくなります。そこで、SOLID原則を適用したプロジェクト管理のコツを紹介します。
1. スクリプトのフォルダ分け(役割ごとに整理)
❌ 悪い例(スクリプトがバラバラ)
/Assets
├── Scripts
├── PlayerMovement.cs
├── Enemy.cs
├── Attack.cs
├── GameManager.cs
├── UIManager.cs
├── Health.cs
このように すべてのスクリプトが 1 つのフォルダにあると、どこに何があるのか分かりづらくなります。
✅ 良い例(役割ごとに整理)
/Assets
├── Scripts
├── Player
│ ├── PlayerMovement.cs
│ ├── PlayerCombat.cs
│ ├── PlayerHealth.cs
│
├── Enemy
│ ├── BaseEnemy.cs
│ ├── MeleeEnemy.cs
│ ├── RangedEnemy.cs
│
├── Managers
│ ├── GameManager.cs
│ ├── UIManager.cs
│
├── UI
│ ├── HealthBar.cs
│ ├── ScoreDisplay.cs
このように フォルダを「役割ごと」に分けることで、スクリプトを探しやすくなります。
2. 名前付けルールの統一
スクリプトの名前付けが統一されていないと、どんな役割のスクリプトなのか分かりにくくなります。
❌ 悪い例(統一されていない命名)
public class MovePlayer { } // 動詞が先で統一感がない
public class PlayerAttackScript { } // "Script" という余計な単語
public class Health { } // プレイヤー用か敵用か不明
✅ 良い例(統一された命名)
public class PlayerMovement { } // "Player" という接頭辞で明確
public class PlayerCombat { } // 役割が明確
public class PlayerHealth { } // 何の "Health" か分かる
💡 ポイント
- クラス名は 「役割 + 対象」 の形式で付ける
Manager
やController
のような 管理クラスは明確な名前にするI
を付けてインターフェースを区別する(例:IAttackable
)
3. メンテナンスしやすいコード構造の作り方
✅ コーディングスタイルの統一
コードの書き方が統一されていないと、可読性が下がります。
チーム開発でも個人開発でも、書き方を統一することでメンテナンスしやすくなります。
❌ 悪い例(統一されていないコードスタイル)
public class Player {public void Move(){ Debug.Log("移動");}}
インデントがバラバラで、見づらい。
✅ 良い例(統一されたコードスタイル)
public class Player
{
public void Move()
{
Debug.Log("移動");
}
}
ポイント
- インデントを統一する(タブ or スペース)
- メソッドの開始
{
は次の行に書く - 変数名はキャメルケース(
playerHealth
)にする - クラス名はパスカルケース(
PlayerHealth
)にする
4. コメントとドキュメントの活用
SOLID原則を適用すると、スクリプトが整理されますが、コードを読んだだけで全員が理解できるとは限りません。
適切に コメントやドキュメントを活用 しましょう。
✅ 良いコメントの例
/// <summary>
/// プレイヤーの移動を制御するクラス
/// </summary>
public class PlayerMovement : MonoBehaviour
{
/// <summary> プレイヤーの移動速度 </summary>
public float speed = 5f;
/// <summary> 移動処理 </summary>
public void Move()
{
// 入力を取得
float move = Input.GetAxis("Horizontal");
transform.Translate(Vector3.right * move * speed * Time.deltaTime);
}
}
💡 ポイント
/// <summary>
を使ってクラスとメソッドの説明を記述- 処理が複雑な部分はコメントを残す
- 不必要なコメントは書かない(コードを見れば分かるものは不要)
5. 依存関係を最小限にする設計
SOLID原則の 「依存関係逆転の原則(DIP)」 を意識すると、スクリプト間の結びつきを減らし、変更に強いコードになります。
❌ 悪い例(強く結びついた依存関係)
public class GameManager : MonoBehaviour
{
private Player player = new Player();
}
このように GameManager
が Player
に直接依存していると、変更しづらくなります。
✅ 良い例(依存関係を減らす設計)
public class GameManager : MonoBehaviour
{
private ICharacter character;
public GameManager(ICharacter character)
{
this.character = character;
}
}
💡 ポイント
- 具体的なクラス (
Player
やEnemy
) ではなく、抽象クラス (ICharacter
) を利用 GameManager
を直接Player
に依存させず、柔軟に変更できるようにする
まとめ
SOLID原則を適用するだけでなく、プロジェクト全体の管理を徹底することで、さらに開発がスムーズになります。
✅ スクリプトを役割ごとにフォルダ分けする → 探しやすく整理する
✅ 名前付けルールを統一する → 役割が分かりやすいクラス名にする
✅ メンテナンスしやすいコードスタイルを採用する → インデントや変数命名を統一する
✅ コメントとドキュメントを活用する → コードの意図を伝えやすくする
✅ 依存関係を最小限にする設計を心がける → 変更に強いコードにする

次のセクションでは、よくある質問(Q&A)形式で、SOLID原則の実践方法や疑問点を解説していきます!
6. まとめ
この記事では、SOLID原則をUnityのスクリプトに適用する方法について解説しました。SOLID原則を意識して設計することで、コードの整理ができ、メンテナンスや拡張がしやすくなります。
SOLID原則をUnityスクリプトに適用するメリット
✅ スクリプトの役割が明確になり、管理しやすくなる
Player.cs
に移動や攻撃、UI更新などをすべて詰め込むのではなく、「移動」「攻撃」「UI」などの役割ごとにスクリプトを分ける ことで、コードがスッキリ整理される。
✅ バグが減り、修正がしやすくなる
Enemy.cs
を直接修正するのではなく、BaseEnemy.cs
を作成し、それを継承したMeleeEnemy.cs
やRangedEnemy.cs
を用意することで、新しい機能を追加しても既存のコードに影響を与えずに済む。
✅ 開発スピードが向上する
- しっかり設計されたコードは、機能追加がしやすく、修正やデバッグの時間を削減できる ため、開発のスピードが向上する。
まずは単一責任の原則から意識するのがオススメ
SOLID原則の中でも、特に**「単一責任の原則(SRP)」** を意識するだけで、コードがぐっと整理されます。
例えば、次のようなケースで「単一責任の原則」を適用できます。
❌ 悪い例(すべてを1つのスクリプトにまとめる)
public class Player : MonoBehaviour
{
public void Move() { /* 移動処理 */ }
public void Attack() { /* 攻撃処理 */ }
public void TakeDamage() { /* ダメージ処理 */ }
public void UpdateUI() { /* UI更新処理 */ }
}
このように 複数の責務を1つのスクリプトにまとめると、修正や管理が大変になります。
✅ 良い例(単一責任の原則を適用)
public class PlayerMovement : MonoBehaviour
{
public void Move() { /* 移動処理 */ }
}
public class PlayerCombat : MonoBehaviour
{
public void Attack() { /* 攻撃処理 */ }
}
public class PlayerHealth : MonoBehaviour
{
public void TakeDamage() { /* ダメージ処理 */ }
}
public class PlayerUI : MonoBehaviour
{
public void UpdateUI() { /* UI更新処理 */ }
}
こうすることで、スクリプトの役割が明確になり、バグを減らしながら開発を進めやすくなります。
実践的なコード整理でゲーム開発をスムーズに
SOLID原則を適用すると、スクリプトが整理され、プロジェクト全体の見通しが良くなります。
💡 今すぐできる実践的なコード整理術
- スクリプトを役割ごとにフォルダ分けする
Scripts/Player/
やScripts/Enemy/
のように、カテゴリごとにフォルダを作る
- クラス名を分かりやすく統一する
PlayerMovement
/EnemyAI
/HealthManager
のように、明確な名前を付ける
- コメントやドキュメントを適切に記述する
/// <summary>
を活用し、何をするクラスなのかを明確にする
- 不要な
MonoBehaviour
の継承を減らすMonoBehaviour
を継承するのは必要最小限にし、できるだけ通常の C# クラスを使う

SOLID原則を活用すれば、スクリプトの整理がしやすくなり、開発の効率が大幅に向上します!
最初からすべての原則を完璧に適用する必要はありませんが、まずは「単一責任の原則」から意識し、徐々に他の原則も取り入れてみるのがオススメです。
整理されたコードで、スムーズなゲーム開発を楽しみましょう! 🎮✨
よくある質問(FAQ)
- QUnityのスクリプトはどの原則を一番意識すべき?
- A
「単一責任の原則(SRP)」を最優先で意識するのがおすすめです。
SOLID原則の中でも、特に 「単一責任の原則(SRP)」 を意識することで、コードの整理がしやすくなります。
例えば、1つのスクリプトに「移動」「攻撃」「HP管理」「UI更新」などの処理がすべて詰め込まれていると、修正や拡張が非常に大変になります。
✅ 単一責任の原則を意識すると…
- スクリプトごとに役割が明確になり、コードを探しやすくなる
- 不要な修正を減らし、バグを防ぎやすくなる
- 新機能の追加が簡単になる
💡 まずは「1つのスクリプト = 1つの責務」から意識してみましょう!
- QSOLID原則を意識するとコードが増えてしまうが、どうすればいい?
- A
コードの量が増えるのは自然なことですが、それは「管理しやすいコード」になっている証拠です!
たしかに、SOLID原則を意識するとクラスの数は増えます。しかし、その分 「どこに何の処理があるのか」が明確になるため、長期的に見るとメリットが大きい です。
例えば、1つの巨大なスクリプトにすべての処理を書いてしまうと、
- 修正のたびに影響範囲が広がる
- バグが増えやすい
- コードが読みにくくなる
といった問題が発生します。
💡 コードが増えても、管理しやすいなら問題なし!
- フォルダ分けをして、スクリプトを整理する
- 共通処理は
Utility
クラスやManager
クラスにまとめる - MonoBehaviourを継承するクラスを減らし、通常のC#クラスを活用する
これらを意識すれば、コードが増えても開発しやすい環境を作ることができます!
- QMonoBehaviourを継承してもSOLID原則を適用できる?
- A
もちろん適用できます! ただし、MonoBehaviourの継承は最小限にするのがポイントです。
Unityでは、
MonoBehaviour
を継承することで、スクリプトをGameObject
にアタッチできます。ただし、何でもMonoBehaviour
を継承すると、次のような問題が発生することがあります。❌ 悪い例(不要にMonoBehaviourを継承)
public class PlayerCombat : MonoBehaviour
{
public void Attack() { /* 攻撃処理 */ }
}この場合、
Attack
メソッドは特にMonoBehaviour
の機能(Update()
やStart()
など)を必要としていません。そのため、MonoBehaviourを継承する意味がありません。✅ 良い例(MonoBehaviourを継承せず、依存関係を減らす)
public class PlayerCombat
{
public void Attack() { /* 攻撃処理 */ }
}
public class Player : MonoBehaviour
{
private PlayerCombat combat = new PlayerCombat();
public void PerformAttack()
{
combat.Attack();
}
}こうすることで、
MonoBehaviour
を必要なクラスだけに限定し、スクリプトの結びつきを減らせます。💡 MonoBehaviourを継承するかどうかの判断基準
- スクリプトが
Update()
やStart()
を使うか? - GameObject にアタッチする必要があるか?
- 他のスクリプトから独立して動作できるか?
これらを考慮しながら、MonoBehaviourの継承を最小限にし、通常のC#クラスを活用することで、SOLID原則を適用しやすくなります!
- スクリプトが