第2ターム審査会用①

今回も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}");
    }
}

DoMorningDoWork をテーブル駆動に差し替え:

// 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。

コメント

タイトルとURLをコピーしました