対応バージョン:Unity 6.3 LTS(6000.3系)/WebGL出力 この記事はシリーズ全11回の第4回です。第3回では会話システムと話題カードシステムを実装しました。今回はゲームの進行を管理する核心部分を作ります。 【PR】本記事にはアフィリエイトリンクを含みます。
前回までで「セリフを表示する」「話題カードを選ぶ」という基本動作が動く状態になりました。しかしこのままでは、すべての話題カードが最初から表示されてしまいます。
アドベンチャーゲームらしい「ある情報を聞いたら次の話題が解放される」「証拠を入手したら追及コマンドが使えるようになる」という進行管理の仕組みを今回実装します。
目次
- STEP3:FlagManager(フラグ管理・話題解放)
- STEP4:EvidenceSystem(証拠入手・通知UI)
- 完成して振り返って
- 次回予告
- あわせて読みたいおすすめ書籍【PR】
- この記事を作成するにあたって参考にしたサイト
STEP3:FlagManager(フラグ管理・話題解放)
フラグとは何か
「フラグ」はゲームの進行状態を管理するための仕組みです。「この会話を聞いた」「この証拠を入手した」という事実を、文字列のIDとして記録しておきます。
たとえば沙耶との「あの夜のこと」という話題を最後まで聞いたとき、talked_saya_nightというフラグを立てます。FlagManagerはこのフラグが立ったことを検知し、「月凪の過去について」という新しい話題カードのIsUnlockedをtrueに変更します。これで次に話題カードパネルを開いたとき、新しい話題が増えているという状態になります。
FlagManagerを作る
Scripts/System/フォルダに「FlagManager」という名前でMonoBehaviour Scriptを作成します。
using UnityEngine;
using System.Collections.Generic;
public class FlagManager : MonoBehaviour
{
public static FlagManager Instance;
private HashSet<string> activeFlags = new HashSet<string>();
void Awake()
{
Instance = this;
}
public void SetFlag(string flagID)
{
if (!activeFlags.Contains(flagID))
{
activeFlags.Add(flagID);
Debug.Log("Flag set: " + flagID);
OnFlagChanged(flagID);
}
}
public bool HasFlag(string flagID)
{
return activeFlags.Contains(flagID);
}
void OnFlagChanged(string flagID)
{
UnlockTopicsByFlag(flagID);
}
void UnlockTopicsByFlag(string flagID)
{
TopicData[] allTopics = Resources.LoadAll<TopicData>("Topics");
foreach (TopicData topic in allTopics)
{
if (topic.unlockFlagID == flagID)
{
topic.isUnlocked = true;
Debug.Log("Topic unlocked: " + topic.topicTitle);
}
}
}
}
設計のポイント
フラグの保存にHashSet<string>を使っています。List<string>でも動きますが、HashSetは「すでに含まれているか」の確認が高速で、重複して同じフラグが登録されることもありません。フラグの数が増えても動作が遅くなりにくい設計です。
Resources.LoadAll<TopicData>("Topics")はAssets/Resources/Topicsフォルダ内にある全TopicDataを動的に読み込みます。これにより、新しい話題カードを追加するときにスクリプトを書き換える必要がなく、Topicsフォルダにファイルを置くだけで自動的に管理対象になります。
Resourcesフォルダの準備
Resources.LoadAll<T>()を使うには、読み込みたいアセットがAssets/Resourcesフォルダの中になければなりません。
🔧 詳しい手順
- ProjectウィンドウのAssetsフォルダで右クリック→「Create」→「Folder」で「Resources」フォルダを作成する
- Resourcesフォルダ内に「Topics」フォルダを作成する
- 第3回で作成したTopicDataのファイル(Topic_Saya_Nightなど)を、Data/Dialogues/TopicsフォルダからResources/Topicsフォルダに移動する(ProjectウィンドウでドラッグすればOK)
⚠️ 実際にハマったミス:Resourcesフォルダのタイポ 開発中に「Resources」を「Resoueces」(rを1つ抜かし)とタイポしたまま進めてしまいました。フラグを立てても
Resources.LoadAll<TopicData>("Topics")が何も見つけられず、話題カードが解放されないという不具合が出ました。エラーも警告も出ないので気づくのが遅れました。Resourcesは「Re-sour-ces」と読むと覚えやすいです。フォルダを作ったら必ず綴りを確認してください。
TopicDataにフラグ解放条件を設定する
第3回で作ったTopicData.csに、フラグ解放のための項目をすでに追加してあります。
unlockFlagID // このIDのフラグが立つと解放される
たとえば「月凪の過去について」という話題カードの場合、Inspectorで以下のように設定します。
Topic ID:saya_past
Topic Title:月凪の過去について
Is Unlocked:チェックを外す(最初は非表示)
Unlock Flag ID:talked_saya_night
これで「あの夜のこと」を最後まで聞いてtalked_saya_nightフラグが立ったとき、FlagManagerが自動的に「月凪の過去について」のIsUnlockedをtrueに変えてくれます。
DialogueDataにフラグ設定を追加する
会話が終わったときにフラグを立てる設定は、DialogueDataのInspectorで行います。
Set Flag On Complete:talked_saya_night
この設定をした会話を最後まで読むと、DialogueManagerのEndDialogue()からFlagManager.Instance.SetFlag("talked_saya_night")が呼ばれ、フラグが立ちます。
🔧 詳しい手順(テストする)
- GameManagerにAdd ComponentでFlagManagerを追加する
- Char_SayaのTopicsに新しい話題カード(Topic_Saya_Past)を追加し、Is Unlockedのチェックを外す
- Topic_Saya_PastのUnlock Flag IDに「talked_saya_night」と入力する
- Ch2_Saya_Night(あの夜のことの会話データ)のSet Flag On Completeに「talked_saya_night」と入力する
- 再生して「あの夜のこと」を最後まで読む
- ConsoleにFlag set: talked_saya_night・Topic unlocked: 月凪の過去についてと表示されて、話題カードパネルに新しいカードが増えれば成功
⚠️ 「Flag set」は出るが「Topic unlocked」が出ない場合
Resources.LoadAll<TopicData>("Topics")がTopicDataを見つけられていません。以下を確認してください。
- Resourcesフォルダの綴りが正確か(大文字小文字・スペルミス)
- Topic_Saya_PastがResources/Topicsフォルダの中にあるか
- Topic_Saya_PastのUnlock Flag IDに正確に「talked_saya_night」と入力されているか

STEP4:EvidenceSystem(証拠入手・通知UI)
EvidenceDataを作る
Scripts/System/フォルダに「EvidenceData」という名前でMonoBehaviour Scriptを作成し、クラスをScriptableObjectに書き換えます。
using UnityEngine;
[CreateAssetMenu(fileName = "EvidenceData", menuName = "MysteryADV/EvidenceData")]
public class EvidenceData : ScriptableObject
{
public string evidenceID;
public string evidenceName;
[TextArea(2, 4)]
public string description;
}
EvidenceManagerを作る
Scripts/System/フォルダに「EvidenceManager」という名前でMonoBehaviour Scriptを作成します。
using UnityEngine;
using System.Collections.Generic;
public class EvidenceManager : MonoBehaviour
{
public static EvidenceManager Instance;
private List<EvidenceData> collectedEvidence = new List<EvidenceData>();
void Awake()
{
Instance = this;
}
public void CollectEvidence(EvidenceData evidence)
{
if (!collectedEvidence.Contains(evidence))
{
collectedEvidence.Add(evidence);
Debug.Log("Evidence collected: " + evidence.evidenceName);
FlagManager.Instance.SetFlag("evidence_" + evidence.evidenceID);
EvidenceNotifier.Instance.ShowNotification(evidence.evidenceName);
}
}
public bool HasEvidence(string evidenceID)
{
return collectedEvidence.Exists(e => e.evidenceID == evidenceID);
}
public List<EvidenceData> GetAllEvidence()
{
return collectedEvidence;
}
}
証拠を入手したとき、FlagManager.Instance.SetFlag("evidence_" + evidence.evidenceID)で自動的にフラグも立てています。たとえば動画(evidenceID: “video”)を入手するとevidence_videoというフラグが立ちます。このフラグを使って、追及コマンドの解放などの条件判定ができます。
入手通知UIを作る
Scripts/UI/フォルダに「EvidenceNotifier」という名前でMonoBehaviour Scriptを作成します。
using UnityEngine;
using TMPro;
using System.Collections;
public class EvidenceNotifier : MonoBehaviour
{
public static EvidenceNotifier Instance;
public GameObject notificationPanel;
public TMP_Text notificationText;
void Awake()
{
Instance = this;
notificationPanel.SetActive(false);
}
public void ShowNotification(string evidenceName)
{
notificationText.text = "証拠を入手:" + evidenceName;
notificationPanel.SetActive(true);
StartCoroutine(HideAfterDelay(3f));
}
IEnumerator HideAfterDelay(float delay)
{
yield return new WaitForSeconds(delay);
notificationPanel.SetActive(false);
}
}
StartCoroutineとIEnumeratorを使うことで、「3秒後に非表示にする」という時間のかかる処理を、他の処理を止めずに非同期で実行できます。
🔧 詳しい手順(通知UIを作る)
- Hierarchyで右クリック→「UI (Canvas)」→「Panel」を選択し、名前を「NotificationPanel」にする
- Rect TransformをShift+Altを押しながら右上に設定し、Width:400・Height:80・Pos X:-20・Pos Y:-20に設定する
- NotificationPanel内に「Text – TextMeshPro」を追加し、名前を「NotificationText」にする。アンカーをStretch(四方)に設定し、Font Size:20・Color:Whiteにする
- NotificationPanelのImageのColorを濃い紺色(Hex: 323250FF)に変更する
- NotificationPanelのチェックを外して最初は非表示にする
- GameManagerにAdd ComponentでEvidenceManagerとEvidenceNotifierを追加する
- EvidenceNotifierのInspectorのNotification Panel欄にNotificationPanel、Notification Text欄にNotificationTextをドラッグ&ドロップして接続する
証拠データを作る
🔧 詳しい手順
- Resourcesフォルダ内に「Evidences」フォルダを作成する
- Evidencesフォルダ内で右クリック→「MysteryADV」→「EvidenceData」を選択し、名前を「Evidence_Video」にする
- Inspectorに以下を入力する
- Evidence ID:video
- Evidence Name:請求書の動画
- Description:木下健太が月凪で撮影した動画。請求書の内訳と、田中浩二が宗一郎と話している場面が映っている。
- 証拠を入手させたい会話データ(DialogueData)のGrant Evidence On Complete欄にEvidence_Videoをドラッグ&ドロップする
完成して振り返って
⚠️ ハマったポイント
- Resourcesフォルダの名前は特に注意が必要。タイポしてもエラーが出ないので気づきにくい。フォルダを作ったら即確認する
HashSet<string>はフラグ管理に適している。List<string>でもよいが、重複チェックが簡潔に書ける- 証拠入手時にフラグも自動で立てる設計にすると、後から「この証拠を持っているか確認する」という条件が書きやすくなる
Coroutine(IEnumerator)は「n秒後に何かする」という時間のかかる処理に使える。今回の通知UIの自動消去に使ったが、ウェイト演出・フェードアウトなど応用範囲が広いDebug.Logでフラグや証拠の入手をログに出しておくと、「フラグが立っているのか立っていないのか」の確認が格段にしやすくなる。実装が完了したら削除してよい
次回予告
第5回では、シーン遷移とエンディング分岐を実装し、WebGL出力でブラウザで動かすところまで進めます。「証拠を揃えて容疑者を追及したら、ゲームが終わる」という大詰めの部分です。
あわせて読みたいおすすめ書籍【PR】
今回実装したフラグ管理・ScriptableObject・Coroutineについてさらに深く学びたい方には、以下の書籍もおすすめです。本セクションにはアフィリエイトリンクを含みます。
- 『Unityの教科書 Unity 6完全対応版』(北村愛実 著/SBクリエイティブ) ── ScriptableObjectやCoroutineの基礎を体系的に学べるUnity 6対応の定番入門書
- 『楽しく学ぶ Unity「2Dゲーム」作りのきほん』(森巧尚 著/マイナビ出版) ── ゲームの進行管理・フラグ設計の考え方を実例と合わせて解説
- 『作って学ぶゲームプログラミング Unity まるっと入門 Unity6完全対応』(トライタム 著/吉谷幹人 監修) ── Resources.LoadAllを使った動的アセット読み込みの実践例を含む
- 『ゲームシナリオの書き方 第2版』(佐々木智広 著/SBクリエイティブ) ── フラグ設計をシナリオ側の視点から学べる。「どのタイミングで何を解放するか」の設計思想が参考になる
- 『作って学べる Unity本格入門 Unity6対応版』(賀好昭仁 著/技術評論社) ── 今回のシリーズを読み終えてさらにステップアップしたい人向けの中級者向け書籍
※このセクションのリンクはアフィリエイトリンクであり、商品が購入された場合、サイト運営者に紹介料が支払われることがあります【PR】。


コメント