今回もUnityで作成。ジャンルはADV。
とりあえず、授業でやったswitchとifとenumでつくってみる。
1日目で書いたコードは↓
(SceneManager.cs)
using UnityEngine;
public class SceneManager : MonoBehaviour
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
public enum eSceneState
{
SCENE_STATE_MORNING,
SCENE_STATE_WORK,
SCENE_STATE_RESULT,
SCENE_STATE_INTER_MISSION,
}
public eSceneState sceneState;//シーンを格納
public int day;//現在の日付を格納
public int perf;//業務成果
public int stress;//ストレス
public int trust;//信頼
public int dperf;//業務成果(増分)
public int dstress;//ストレス(増分)
public int dtrust;//信頼(増分)
int step = 0;//0=初回表示,1=Enter待ち,2=数字入力待ち
bool HasStressDebuff() => stress >= 80;//ストレスが80を超えるとデバフ
string Signed(int v) => v >= 0 ? $"+{v}" : v.ToString();
void Start()
{
sceneState = eSceneState.SCENE_STATE_MORNING;
day = 1;
stress = trust = perf = 0;
dstress = dtrust = dperf = 0;
}
// Update is called once per frame
void Update()
{
bool inputEnter = Input.GetKeyDown(KeyCode.Return);
switch (sceneState)
{
case eSceneState.SCENE_STATE_MORNING: DoMorning(inputEnter); break;
case eSceneState.SCENE_STATE_WORK: DoWork(inputEnter); break;
case eSceneState.SCENE_STATE_RESULT: DoResult(inputEnter); break;
case eSceneState.SCENE_STATE_INTER_MISSION: DoInterMission(inputEnter); break;
}
//デバッグ用(シーン初期化)
if (Input.GetKeyDown(KeyCode.Escape))
{
sceneState = eSceneState.SCENE_STATE_MORNING; step = 0;
}
}
void DoMorning(bool inputEnter)
{
switch (step)
{
case 0:
Debug.Log($"day:{day}");
Debug.Log("導入テキスト");
step = 1;
break;
case 1:
Debug.Log("選択?1or2");
step = 2;
break;
case 2:
switch (Input.inputString)
{
case "1":
ApplyDelta(5, 0, 0);
step++;
break;
case "2":
ApplyDelta(0, 3, 0);
step++;
break;
default:
break;
}
break;
case 3:
sceneState = eSceneState.SCENE_STATE_WORK; //仕事フェーズへ
step = 0;
break;
}
}
void DoWork(bool inputEnter)
{
switch (step)
{
case 0:
Debug.Log("仕事フェーズ");
step = 1;
break;
case 1:
Debug.Log("どの仕事をする??1or2or3");
step = 2;
break;
case 2:
switch (Input.inputString)
{
case "1":
ApplyDelta(10, 5, 10);
step++;
break;
case "2":
ApplyDelta(50, 20, 2);
step++;
break;
case "3":
ApplyDelta(20, 3, 30);
step++;
break;
default:
break;
}
break;
case 3:
Debug.Log($"[Check] stress={stress}, debuff={(HasStressDebuff() ? "ON" : "off")}");
if (HasStressDebuff())
{
dperf = -3;
perf += dperf;
Debug.Log($"ストレス過多のため成果{Signed(dperf)}");
}
sceneState = eSceneState.SCENE_STATE_RESULT; //結果表示へ
step = 0;
break;
}
}
void DoResult(bool inputEnter)
{
switch (step)
{
case 0:
Debug.Log("結果表示");
step++;
break;
case 1:
Debug.Log($"Day{day}の結果:ストレス{stress},信頼{trust},業務成果{perf}");
Debug.Log("PressEnter");
step++;
break;
case 2:
if (inputEnter)
{
sceneState = eSceneState.SCENE_STATE_INTER_MISSION; //インターミッションへ
step = 0;
}
break;
}
}
void DoInterMission(bool inputEnter)
{
switch (step)
{
case 0:
Debug.Log("インターミッション");
step++;
break;
case 1:
Debug.Log($"{day}日目終了。お疲れ様でした。");
day++;
Debug.Log("PressEnter");
if (day > 4)
{
Debug.Log("ゲーム終了");
enabled = false; //このコンポーネントを止める
return;
}
step++;
break;
case 2:
if (inputEnter)
{
sceneState = eSceneState.SCENE_STATE_MORNING; //翌日の仕事フェーズへ
step = 0;
}
break;
}
}
void ApplyDelta(int ds, int dt, int dp)
{
dstress = ds; dtrust = dt; dperf = dp;
stress += dstress; trust += dtrust; perf += dperf;
stress = Mathf.Clamp(stress, 0, 100);//ストレスの数値範囲
trust = Mathf.Clamp(trust, 0, 100);//信頼の数値範囲
Debug.Log($"[Δ]ストレス{Signed(ds)},信頼{Signed(dt)},業務成果{Signed(dp)}");//ログ表示
Debug.Log($"[Σ]ストレス={stress},信頼={trust},業務成果={perf}");//ログ表示(合計)
}
}
1. Signed
の説明(復習)
string Signed(int v) => v >= 0 ? $"+{v}" : v.ToString();
- これはメソッド(関数)です。引数
v
を受け取り、文字列を返します。(省略形) ?:
は条件演算子。v >= 0
が true なら左、false なら右を返します。$"+{v}"
は 文字列補間。{v}
の中に変数 v の値を埋め込みます。
役割:正の値にプラス記号を付ける。
例:
Signed(5)
→"+5"
Signed(0)
→"+0"
Signed(-3)
→"-3"
これを空のオブジェクトにアタッチ。実行して問題なく動作した。

第二ステップ:1イベント作っただけなのに、ifとswitchだと複雑になり、早々に限界を感じたので、構造をアップデートしていく。
1) “コード内テーブル”化(最短でswitch卒業)
まずは**配列(テーブル)**にイベントと選択肢をまとめ、汎用処理で回します。テキストは当面コード内に置く→あとでSO/CSVに差し替える前提。
// 1) データ構造(ファイル先頭のクラス直下に追加)
[System.Serializable]
public class StatDelta { public int stress, trust, perf; }
[System.Serializable]
public class Option {
public char key; // '1','2','3'
public string label; // 表示文
public StatDelta delta; // 効果
}
[System.Serializable]
public class GameEvent {
public string title; // イベントタイトル
public string prompt; // 説明
public Option[] options; // 選択肢
}
// 2) イベント定義(当面はコードに直書き)
GameEvent morningEvent = new GameEvent {
title = "導入",
prompt = "選択? 1=火消し / 2=通常対応",
options = new []{
new Option{ key='1', label="火消し", delta=new StatDelta{ stress=+5, trust=0, perf=0 }},
new Option{ key='2', label="通常対応", delta=new StatDelta{ stress=0, trust=+3, perf=0 }},
}
};
GameEvent workEvent = new GameEvent {
title="仕事フェーズ",
prompt="どの仕事をする? 1=軽 / 2=中 / 3=重",
options=new[]{
new Option{ key='1', label="軽案件", delta=new StatDelta{ stress=+5, trust=0, perf=+2 }},
new Option{ key='2', label="中案件", delta=new StatDelta{ stress=+10, trust=+5, perf=+10 }},
new Option{ key='3', label="重案件", delta=new StatDelta{ stress=+20, trust=+3, perf=+30 }},
}
};
汎用の適用ロジック:
// 一致する選択肢を探して適用
bool TryApplyChoice(GameEvent ev)
{
var s = Input.inputString; // ゆきさん流を尊重
if (string.IsNullOrEmpty(s)) return false;
char c = s[0];
foreach (var op in ev.options){
if (op.key == c){
ApplyDelta(op.delta.stress, op.delta.trust, op.delta.perf);
return true;
}
}
return false;
}
// 表示ヘルパ
void ShowEvent(GameEvent ev){
Debug.Log(ev.title);
Debug.Log(ev.prompt);
foreach (var op in ev.options){
Debug.Log($"{op.key}: {op.label}");
}
}
DoMorning
と DoWork
をテーブル駆動に差し替え:
// 0=表示,1=数字待ち
int morningStep = 0, workStep = 0;
void DoMorning(bool inputEnter)
{
if (morningStep == 0){ Debug.Log($"Day:{day}"); ShowEvent(morningEvent); morningStep=1; return; }
if (morningStep == 1){
if (TryApplyChoice(morningEvent)){ morningStep=0; sceneState=eSceneState.SCENE_STATE_WORK; }
}
}
void DoWork(bool inputEnter)
{
if (workStep == 0){ ShowEvent(workEvent); workStep=1; return; }
if (workStep == 1){
if (TryApplyChoice(workEvent)){
if (HasStressDebuff()){
int penalty = -3; perf += penalty;
Debug.Log($"※疲労で成果{Signed(penalty)}");
}
workStep=0; sceneState=eSceneState.SCENE_STATE_RESULT;
}
}
}
👉 これで switch文が“ゼロ” でもイベントを増やせます。
選択肢・効果は配列に追加するだけ。混乱ポイントが激減します。
2) 次:ScriptableObject化(差し替えだけ)
上の GameEvent / Option / StatDelta
をそのまま SO にします。
// GameEventSO.cs
[CreateAssetMenu(menuName="Gomikuzu/GameEvent")]
public class GameEventSO : ScriptableObject {
public string title;
[TextArea] public string prompt;
public Option[] options;
}
GameEventSO
をプロジェクトで作り、Inspectorで文言と数値を編集。- コード側は
public GameEventSO morningEventSO;
として参照し、ShowEvent(morningEventSO)
/TryApplyChoice(morningEventSO)
に置換。 - 将来 CSV を読み込むなら、SO から「初期値を読み込み→CSVで上書き」の二段構えにすればOK。
コメント