ターン制システムは、ゲーム全体の流れを管理する重要な仕組みです。
設計を後回しにして実装を進めると、クラスが肥大化したり、状態遷移が複雑になったりしがちです。
この記事では、「ターン制システムをゼロから設計する考え方」に焦点を当て、全体フロー・クラス分割・役割設計を段階的に解説します。
✨ この記事でわかること
- ターン制システムの全体フローと処理の流れ
- 複雑化しないためのクラス分割の考え方
- 各クラスが担うべき責務と役割分担
- 設計を整理するための設計パターン
- 実際に動くターン制システムの実装例
Unityでの基本的なスクリプト作成には慣れてきたものの、ターン制になると「どこで何を管理すればいいのかわからない」と感じている方に向けた内容です。
コードをただ真似するのではなく、「なぜこのクラスが必要なのか」「なぜこの流れになるのか」を理解できるよう構成しています。

いきなり実装するのではなく、クラス構成と役割を整理することが重要です。
Unity入門の森を見る 初心者歓迎!動画×プロジェクト一式で本格ゲーム制作を学べる
あなたのオリジナルゲーム、今年こそ完成させませんか?
RPG・アクション・ホラー…Unityで本格ゲームを作りたい人のための学習サイトです。
実際に完成するゲームを題材に、
ソースコード・素材・プロジェクト一式をすべて公開。
仕事や学校の合間の1〜2時間でも、
「写経→改造」で自分のゲームまで作りきれる環境です。
ターン制システムの全体フロー

ターン制システムは、以下のフローで動作します。
全体像を理解しましょう。
- STEP1ターン開始(所要0.1秒)
現在のターンのユニットを決定します。行動順キューから、次のユニットを取得します。
- STEP2行動選択(所要1〜10秒)
プレイヤーターンなら、プレイヤーが行動を選択します。敵ターンなら、AIが行動を決定します。
- STEP3行動実行(所要1〜3秒)
選択した行動を実行します。移動・攻撃・スキルなど。アニメーションも再生します。
- STEP4結果処理(所要0.5秒)
ダメージ計算、HP更新、状態変化などを処理します。勝利条件もチェックします。
- STEP5ターン終了(所要0.1秒)
次のターンへ進みます。すべてのユニットが行動済みなら、ターンをリセットします。
このフローを実装すれば、基本的なターン制システムが完成します。
各ステップを、適切なクラスに分担します。
Unity入門の森を見る 初心者歓迎!動画×プロジェクト一式で本格ゲーム制作を学べる
クラス分割の方法

クラスを適切に分割することで、複雑化を防げます。
分割方法を紹介します。
推奨クラス構成
✅ 推奨クラス構成
- TurnManager:ターン管理、状態遷移
- TurnOrderManager:行動順管理、キュー管理
- ActionSelector:行動選択(プレイヤー・AI)
- ActionExecutor:行動実行、アニメーション
- BattleSystem:戦闘処理、ダメージ計算
各クラスが、明確な役割を持ちます。
メンテナンスしやすくなります。
クラス間の連携
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
public class TurnManager : MonoBehaviour { public TurnOrderManager turnOrderManager; public ActionSelector actionSelector; public ActionExecutor actionExecutor; public BattleSystem battleSystem; private Unit currentUnit; private ActionCandidate selectedAction; public void ProcessTurn() { // 1. 次のユニットを取得 currentUnit = turnOrderManager.GetNextUnit(); if (currentUnit == null) { // 全ユニットが行動済み turnOrderManager.ResetTurnOrder(); return; } // 2. 行動を選択 selectedAction = actionSelector.SelectAction(currentUnit); // 3. 行動を実行 actionExecutor.ExecuteAction(currentUnit, selectedAction); // 4. 結果を処理 battleSystem.ProcessBattleResult(); } } |
各クラスが、明確な役割を持ちます。
連携することで、ターン制システムが動作します。
Unity入門の森を見る 初心者歓迎!動画×プロジェクト一式で本格ゲーム制作を学べる
各クラスの役割分担

各クラスの役割を明確にします。
実装方法を紹介します。
TurnManager(ターン管理)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
public class TurnManager : MonoBehaviour { public TurnState currentState = TurnState.Waiting; public TurnOrderManager turnOrderManager; public ActionSelector actionSelector; public ActionExecutor actionExecutor; private Unit currentUnit; void Update() { switch (currentState) { case TurnState.Waiting: if (turnOrderManager.HasNextUnit()) { StartTurn(); } break; case TurnState.ActionSelect: // 行動選択を待つ break; case TurnState.ActionExecute: ExecuteAction(); break; case TurnState.TurnEnd: EndTurn(); break; } } void StartTurn() { currentUnit = turnOrderManager.GetNextUnit(); currentState = TurnState.ActionSelect; } void ExecuteAction() { ActionCandidate action = actionSelector.GetSelectedAction(); actionExecutor.ExecuteAction(currentUnit, action); currentState = TurnState.TurnEnd; } void EndTurn() { currentUnit = null; currentState = TurnState.Waiting; } } |
TurnManagerは、ターン全体の流れを管理します。
状態遷移を制御します。
TurnOrderManager(行動順管理)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
public class TurnOrderManager : MonoBehaviour { public List<Unit> allUnits = new List<Unit>(); private Queue<Unit> turnQueue = new Queue<Unit>(); public void InitializeTurnOrder() { turnQueue.Clear(); // 速度でソート List<Unit> sortedUnits = allUnits .Where(u => u.stats.currentHP > 0) .OrderByDescending(u => u.stats.speed) .ToList(); foreach (var unit in sortedUnits) { turnQueue.Enqueue(unit); } } public Unit GetNextUnit() { if (turnQueue.Count == 0) { InitializeTurnOrder(); } return turnQueue.Count > 0 ? turnQueue.Dequeue() : null; } public bool HasNextUnit() { return turnQueue.Count > 0; } public void ResetTurnOrder() { InitializeTurnOrder(); } } |
TurnOrderManagerは、行動順を管理します。
速度でソートし、キューで管理します。
ActionSelector(行動選択)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
public class ActionSelector : MonoBehaviour { public ActionMenuUI actionMenu; public EnemyAI enemyAI; private ActionCandidate selectedAction; private bool isSelecting = false; public ActionCandidate SelectAction(Unit unit) { if (IsPlayerUnit(unit)) { return SelectPlayerAction(unit); } else { return SelectEnemyAction(unit); } } ActionCandidate SelectPlayerAction(Unit unit) { isSelecting = true; actionMenu.ShowMenu(unit); // プレイヤーの選択を待つ while (isSelecting) { // 選択が完了するまで待つ } return selectedAction; } ActionCandidate SelectEnemyAction(Unit unit) { return enemyAI.SelectBestAction(unit); } public void OnActionSelected(ActionCandidate action) { selectedAction = action; isSelecting = false; } bool IsPlayerUnit(Unit unit) { // 実装は省略 return true; } } |
ActionSelectorは、行動選択を管理します。
プレイヤーとAIの両方に対応します。
Unity入門の森を見る 初心者歓迎!動画×プロジェクト一式で本格ゲーム制作を学べる
複雑化を防ぐ設計パターン

設計パターンを使えば、複雑化を防げます。
実装方法を紹介します。
コマンドパターン
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
public abstract class Command { protected Unit unit; public Command(Unit unit) { this.unit = unit; } public abstract void Execute(); public abstract void Undo(); } public class MoveCommand : Command { private Vector2Int fromPosition; private Vector2Int toPosition; public MoveCommand(Unit unit, Vector2Int toPosition) : base(unit) { this.toPosition = toPosition; this.fromPosition = new Vector2Int(unit.gridX, unit.gridY); } public override void Execute() { unit.SetPosition(toPosition.x, toPosition.y, gridMap); } public override void Undo() { unit.SetPosition(fromPosition.x, fromPosition.y, gridMap); } } public class AttackCommand : Command { private Unit target; public AttackCommand(Unit unit, Unit target) : base(unit) { this.target = target; } public override void Execute() { battleSystem.ExecuteAttack(unit, target); } public override void Undo() { // 攻撃の取り消し(実装は省略) } } |
コマンドパターンを使えば、行動をオブジェクト化できます。
取り消し機能も実装しやすくなります。
オブザーバーパターン
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
using System; public class TurnEventManager : MonoBehaviour { public static event Action<Unit> OnUnitTurnStart; public static event Action<Unit> OnUnitTurnEnd; public static event Action OnTurnReset; public static void NotifyUnitTurnStart(Unit unit) { OnUnitTurnStart?.Invoke(unit); } public static void NotifyUnitTurnEnd(Unit unit) { OnUnitTurnEnd?.Invoke(unit); } public static void NotifyTurnReset() { OnTurnReset?.Invoke(); } } public class TurnOrderUI : MonoBehaviour { void OnEnable() { TurnEventManager.OnUnitTurnStart += UpdateDisplay; TurnEventManager.OnTurnReset += RefreshDisplay; } void OnDisable() { TurnEventManager.OnUnitTurnStart -= UpdateDisplay; TurnEventManager.OnTurnReset -= RefreshDisplay; } void UpdateDisplay(Unit unit) { // UIを更新 } void RefreshDisplay() { // UIをリフレッシュ } } |
オブザーバーパターンを使えば、クラス間の結合を緩和できます。
イベントで通知することで、拡張しやすくなります。

設計パターンは、複雑化を防ぐために有効です。ただし、最初はシンプルに実装して、必要に応じてパターンを適用しましょう。
Unity入門の森を見る 初心者歓迎!動画×プロジェクト一式で本格ゲーム制作を学べる
実装例:完全なターン制システム

実際に使える、完全なターン制システムの実装例を紹介します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
using UnityEngine; using System.Collections.Generic; public class CompleteTurnBasedSystem : MonoBehaviour { [Header("管理クラス")] public TurnOrderManager turnOrderManager; public ActionSelector actionSelector; public ActionExecutor actionExecutor; public BattleSystem battleSystem; public InputManager inputManager; [Header("状態")] public TurnState currentState = TurnState.Waiting; private Unit currentUnit; void Start() { turnOrderManager.InitializeTurnOrder(); } void Update() { switch (currentState) { case TurnState.Waiting: if (turnOrderManager.HasNextUnit()) { StartNextTurn(); } break; case TurnState.ActionSelect: // 行動選択を待つ inputManager.EnableInput(); break; case TurnState.ActionExecute: inputManager.DisableInput(); ExecuteSelectedAction(); break; case TurnState.TurnEnd: EndCurrentTurn(); break; } } void StartNextTurn() { currentUnit = turnOrderManager.GetNextUnit(); if (currentUnit == null) { // 全ユニットが行動済み turnOrderManager.ResetTurnOrder(); currentState = TurnState.Waiting; return; } if (IsPlayerUnit(currentUnit)) { currentState = TurnState.ActionSelect; actionSelector.StartPlayerActionSelection(currentUnit); } else { currentState = TurnState.ActionExecute; ActionCandidate action = actionSelector.SelectEnemyAction(currentUnit); actionExecutor.ExecuteAction(currentUnit, action); } } void ExecuteSelectedAction() { ActionCandidate action = actionSelector.GetSelectedAction(); actionExecutor.ExecuteAction(currentUnit, action); currentState = TurnState.TurnEnd; } void EndCurrentTurn() { // 勝利条件をチェック if (battleSystem.CheckWinCondition()) { // 勝利処理 return; } if (battleSystem.CheckLoseCondition()) { // 敗北処理 return; } currentUnit = null; currentState = TurnState.Waiting; } bool IsPlayerUnit(Unit unit) { // 実装は省略 return true; } } |
このコードで、完全なターン制システムが実装できます。
各クラスが明確な役割を持ち、連携して動作します。
Unity入門の森を見る 初心者歓迎!動画×プロジェクト一式で本格ゲーム制作を学べる
よくある質問(FAQ)

Unity入門の森を見る 初心者歓迎!動画×プロジェクト一式で本格ゲーム制作を学べる
あなたのオリジナルゲーム、今年こそ完成させませんか?
RPG・アクション・ホラー…Unityで本格ゲームを作りたい人のための学習サイトです。
実際に完成するゲームを題材に、
ソースコード・素材・プロジェクト一式をすべて公開。
仕事や学校の合間の1〜2時間でも、
「写経→改造」で自分のゲームまで作りきれる環境です。
まとめ

ターン制システムは、クラスを適切に分割することで、複雑化を防げます。
最初に設計を決めて、段階的に実装しましょう。
✅ 今日から始める3ステップ
- ステップ1:クラス構成を設計する(所要1時間)
- ステップ2:各クラスの役割を実装する(所要3時間)
- ステップ3:クラス間の連携を実装する(所要2時間)
本格的にUnityを学びたい方は、Unity入門の森で実践的なスキルを身につけましょう。
あなたのペースで、少しずつ進めていけば大丈夫です。
Unity入門の森を見る 初心者歓迎!動画×プロジェクト一式で本格ゲーム制作を学べる



コメント