探索パートの再開発★【Unity6】

絶対調味ロジック

ノベルパートと同様に、
Unity6 + URP 形式で探索パートを作り直しています。

システム適応

兎に角、まずは設定バックログセーブなどのシステムを探索用に対応させることから始めます。
一番の問題はセーブロード
何を保存させるのか、保存できない場合はロード時に個別でアクティブにするなど、
Cutノベル形式でのセーブロードと異なるLocation探索形式に対応させるだけで手いっぱいです((;゚Д゚)

システム適応・探索パート★【Unity6】にて現在も改善中。

セーブロード

Cut進行用Location探索用に対応させるのが思ったほど大変でした。

Cutの場合は、
Cut_001 → Cut_002 → … とMessengerとの連携で、Cut内の状態を保存して、そのまま復元する方式です。

Locationは、
Cutの代わりに「Front」「Left」「Right」「Back」の移動先内に状態を詰め込んでいます。
復元条件も分かれていきます。

・Messengerが存在する場合と存在しない場合
・デフォルトカメラ位置とロケーション内でのカメラ移動後
・セーブ時に表示されているUIがある場合、表示されていない場合、違うUIが表示されている場合
・それらの複合的な状態の復元

機能追加や修正をするたびに、復元条件が膨れていき、それらに対しての解を作る、
という作業を繰り返していました。

セーブロード画面のテキスト表示の仕方も、ノベルとは微妙に変える必要がありました。
そういう細かい改善も多々でてきます。

現状は、どのLocation内の状態でも、復元に成功している状態までもっていけています。
ノベルパート」だけで完結させることが、とても楽だったのだということが身に沁みました…

バックログ

バックログもまた探索用表示に対応させる必要がありました。

  • 探索専用の表示:
    探索場所をクリックし、メッセージが流れるため、話者名ではなくクリック場所の表示に
  • 連続同一探索:
    連続で同じ場所を探索した場合の場所(名前)処理を再表示するように
  • 初回表示時のスクロールバー表示の不具合修正

バックログの改善★0522にて詳しく記載。

カメラシステム Cinemachine

有名どころのカメラシステムである「Cinemachine」を搭載させました。
ノベルパート含めて「DOTween」でカメラを移動させていたのですが、
想定挙動をさせるための改善がちょっと複雑になりそうだったため、自動カメラシステムを搭載しておこうとなりました。

ノベルでもそうでしたが、
DOTween」の場合、メインカメラを複製して位置を決め、スクリプトで位置を取得するため、
編集中にカメラアングルを確かめるために複製メインカメラのOn/Offをしていました。
これが地味に面倒だったわけですが、
Cinemachine」の場合、その場のシネカメラを表示するだけで実際の画面表示をしてくれるので、とても便利です。
スクリプトいらずでのカメラ移動も楽チンです。
さっさと導入しておくべきでした。

カメラ挙動はDOTweenを使用したときと同じにできます。

カメラシステム Cinemachine導入【URP】にて導入方法を詳しく説明しています。

オブジェクト遮蔽 Occlusion

以前にノベルパートで試してみた「オクルージョン」を探索パートに採用してみました。

ノベルパートとは違い、同じ場所をくるくると廻る探索パートでは、
Location毎にアクティブ非アクティブを設定するよりも自動で遮断できた方が適していると判断しました。

この規模だと逆に全部表示のままのほうが良さそうな気もしますが、もうよく分かりません(´・ω・`)

その他、全体的な修正

Sys_SceneLoader 修正★

■ 修正の目的

  • 番号指定(int)→ シーン名指定(string) への変更
  • 拡張性・安全性・保守性の大幅向上
  • Unityの標準的な作法に合わせた実装

■ 主な修正点

項目変更内容
シーン指定方法int sceneIndex → string sceneName(推奨)
ロードモードLoadSceneMode を明示的に指定可能(Single / Additive)
非同期ロードuseAsync オプション追加(デフォルト:true)
安全性シーン名未設定時のエラー処理追加
可読性Header + Tooltip でInspectorを整理
保守性コメント充実 + 拡張しやすい構造

■ 推奨設定(Unityスタンダード)

  • sceneName:シーン名を直接入力(Build Settingsに登録されている名前)
  • loadModeSingle(通常のシーン遷移の場合)
  • useAsynctrue(チェックを入れる)

■ 注意点

  • シーン名はBuild Settingsに追加されている必要があります
  • シーン名は大文字小文字を区別します(正確に一致)
  • 将来的にシーンを増やす場合は、ScriptableObject版やenum版への移行も検討可能
  • isLoading は現在シンプルに実装しています(必要に応じてコルーチンでリセット処理を追加可能)

自動スイッチ追加★0607

■ 修正の目的

既存の「ボタンクリックによる手動遷移(デモ機能)」を維持したまま、
オブジェクトがアクティブ(有効化)になった瞬間に「自動でシーン遷移する機能」を共存させる。

■ 主な変更点(実装内容)

  • 切り替えスイッチ(チェック)の追加
    インスペクターからON/OFF可能な loadOnEnable(bool型)を新設。
  • ライフサイクルイベントの組み込み
    Unityの OnEnable() 内で上記スイッチを判定し、ONの場合のみ LoadScene() を自動実行するロジックを追加。
  • 多重ロード防止の維持
    既存の isLoading フラグによるガード(2重ロード防止)が、自動ロード時にもそのまま機能するように設計。

■ コンポーネントの設定とヒエラルキーの運用方法

用途Load On Enable(スイッチ)ヒエラルキーの配置・運用方法
ボタンクリック(手動)OFF(チェックなし)UIのButtonオブジェクト、または管理用オブジェクトにアタッチ。
Buttonの OnClick() から LoadScene() を呼び出す。
即時遷移(自動)ON(チェックあり)空のGameObject(Trigger_SceneLoad 等)にアタッチ。
初期状態からアクティブにしておく。
任意のタイミング(自動)ON(チェックあり)空のGameObjectにアタッチ。
初期状態は非アクティブにしておき、遷移させたいタイミングで他スクリプトから .SetActive(true) する。

■ ⚠️ 運用の注意点

  • 設定ミス(ヒューマンエラー)のリスク
    1つのスクリプトで「手動」と「自動」の両方に対応したため、
    インスペクターのチェックボックス(スイッチ)1つで挙動が激変します。
    設定ミスによる「意図しない自動遷移(暴発)」に注意してください。
  • 非同期ロード時のオブジェクト破棄
    LoadSceneMode.Single で遷移する場合、ロードが始まった瞬間にこのオブジェクト自体が破棄されます。
    ロード進捗の監視などを追加する場合は、途中でオブジェクトが消えてエラーにならないよう注意が必要です。

UI_ButtonVisual 改善

■ コア設計:単一状態管理への集約

課題:
元のコードは Mode(Normal/Selected等)と isPointerOver などのフラグがバラバラに管理されており、
状態変化の正確なタイミング(コルーチンのリセット時機)が掴みにくい状態でした。

解決:
フラグの組み合わせを 11 通りの DetailedState(詳細状態) という1つの列挙型へ完全に集約しました。
これにより、「状態が切り替わった瞬間」を確実に検知し、
アニメーションを 0 フレーム目から綺麗にリセット・再生する構造にしています。

■ 全状態へのマルチアニメーション対応

拡張:
通常のボタン(Normal/Hover/Press)、Selected、Disabled、
トグル(ON/OFF各自のNormal/Hover/Press)の
全状態に対して個別の List<Sprite>(アニメーション配列)を持てるように拡張しました。

ターゲット個別のコマ数同期:
同一ボタン内の複数ターゲット(背景、アイコン、装飾など)がそれぞれ「異なるコマ数のアニメーション」を持っていても、内部の最小公倍数(全体の最大フレーム数)を動的に計算して破綻なくループ再生します。

■ 非アクティブ(SetActive)時のバグ・エラー対策

エラーの解消 (OnDisable):
GameObjectが非アクティブ化される瞬間に StartCoroutine が走るUnityのライフサイクル違反を解決。
非アクティブ化の際はコルーチンを安全に停止(StopAnime)し、
状態をクリアするだけの軽量なシャットダウン処理に変更しました。

復帰バグの解消 (OnEnable):
オブジェクトが再度アクティブ(表示)になった瞬間に最新のコンテキストで ApplyCurrentState() を再実行し、
画面から消えたりグラフィックが停止したりする現象を徹底防止しています。

■ 賢いフォールバック(None対策)

仕様:
単体の Sprite(例: hover や press)がインスペクター上で未設定(None)であっても、
対応するアニメーション配列に要素があれば、
自動的にその「0番目のフレーム(最初のコマ)」を静止画の身代わりとして描画します(配列も空なら normal を参照)。
これにより、インスペクターの設定が最小限でも表示が壊れません。

■ パフォーマンス最適化

ループ内で毎回 new WaitForSeconds を生成していた元のサンプルの記述を改め、
メンバ変数(またはコルーチン開始時)にキャッシュすることで、
UIの切り替えやアニメーション高頻度再生による GC (ガベージコレクション) スパイクの発生を徹底的に排除 しています。

Sys_Random_3Anime 改善

オブジェクトがアクティブになった瞬間に自動的に1枚目の画像(animeOpen)に戻してタイマーをリセットするように。

解決:OnEnable(オブジェクトが有効になったときに走る関数)を追加

void OnEnable()
    {
        ResetAnimation();
    }
// ★外部からも、内部(OnEnable)からも安全に呼べるリセット処理
    public void ResetAnimation()
    {
        // 動作中のコルーチンがあれば確実に止める
        if (currentCoroutine != null)
        {
            StopCoroutine(currentCoroutine);
            currentCoroutine = null;
        }

        // Startより先に呼ばれた場合の対策
        if (spriteRenderer == null) spriteRenderer = GetComponent<SpriteRenderer>();

        // 1枚目の画像(開いた目)に強制的に戻す
        if (spriteRenderer != null && animeOpen != null)
        {
            spriteRenderer.sprite = animeOpen;
        }

        // タイマーの初期化
        SetNextAnimeTime();
    }

この修正により、カメラ移動や画面切り替えに伴ってキャラクター(または目のオブジェクト)が
SetActive(true) になった瞬間に、自動的に OnEnable が走り、確実にパッチリ目(1枚目)から再スタート
するようになります。
コルーチンが途中で残って半目になる不具合も綺麗に消えるはずです。

追加★0603 探索パート用Chapterシステム

ノベル・探索ともに「Chapter演出」を入れました。
当然のように探索パートへの対応が必要になったので、機能を追加しました。

Sys_ExpChapter システム概要

目的:
探索パートに入るたび(ノベルや他シーンから探索へ移行したタイミング)にChapterを表示する。
探索パート内でのロードでは表示しない。

設計方針:
・保存変数(SAV_)は一切使用しない
・セッション内フラグ(hasPlayedInThisSession)で制御
・DontDestroyOnLoad は使用せず、プロジェクトの設計ルールに準拠

最終スクリプト(Sys_ExpChapter.cs)要点

  • Awake() は完全に削除(DontDestroyOnLoad不要のため)
  • OnEnable / OnDisable でシーンロードイベントを監視
  • Sys_LocationController の存在で探索モードを判定
  • Unity 6対応済み

実装手順

  1. スクリプト作成
    • ファイル名: Sys_ExpChapter.cs
    • 推奨場所: Assets/Script/System/ または Assets/Script/System_set/
  2. Hierarchy設置
    • System_set 配下(または探索シーン内で有効な位置)に空のGameObjectを作成
    • 名前を Sys_ExpChapter に変更
    • Sys_ExpChapter スクリプトをアタッチ
  3. インスペクター設定
    • Chapter表示オブジェクト:表示したいChapterオブジェクトを割り当て
    • Chapter Duration:演出時間(秒)を調整(デフォルト5秒)
  4. 探索パートへの遷移処理(重要)
    • ノベルなどから探索パートへ移行する箇所で、必ず以下の処理を追加:
      var chapterSys = FindFirstObjectByType<Sys_ExpChapter>(); if (chapterSys != null) chapterSys.ResetForNextEntry();

動作確認ポイント

  • ノベル → 探索へ移行 → Chapterが流れる
  • 探索内でセーブ/ロード → Chapterは流れない
  • 探索 → ノベル → 探索 と再移行 → またChapterが流れる
  • ResetForNextEntry() を呼ぶことで、次の探索入場時に再度再生可能

デバッグ用機能

  • インスペクター上で Sys_ExpChapter を右クリック → Force Play Chapter Now で強制再生可能

コメント