探索パート(その2) 独自構築★【Unity】

絶対調味ロジック

Unityで探索パートの続きを構築していきます。
前回で「移動」「調べる」の行動を制作しました。
今回は「変数」を設置して、「調べる」行動に詳細行動を振り分けていきます。

  • 条件によって、キャラクターのセリフを変えたい
  • 同じ場所の探索結果を、探索回数によって変えていきたい

他ゲームエンジンをかじったことがあるため、「変数設置」と簡単に考えていますが、
Unityでの変数の扱い方は、まったく知りません。

「変数設置」→「変数・条件チェック」→「結果で分岐」

という概要が頭にあるだけなので、スクリプト記述はいつも通りAIに頑張ってもらうことになります。

変数設置のためのスクリプトたち

分岐会話の構築

具体的な挙動として、

  • キャラクターに話しかけると「デフォルトのセリフ」が流れる
  • 黒板の文字を調べると「調べた変数」を取得する
  • 変数取得後に話しかけると「それを踏まえたセリフ」が流れる

といった流れになるシステムを構築していこうと思います。

手探り状態でAIに聞いてみると、Unityでは(他でも?)

  • 変数を預かる(一時保存)スクリプト
  • 変数を付与するスクリプト
  • 変数をチェックするスクリプト

の3つのスクリプトが必要だということが分かりました。

早速AIに3つのスクリプトを書いてもらいます。
いつも通り視認性とアタッチしやすさを優先し、インスペクターで編集できる3つを統合したスクリプトを!
変数は条件的に「bool型」でオンオフすればよいだけなので、それを組み込んだものとしました。

ここで「変数」の「型」や「条件」などを詳しく思い出しておけば、後の苦労も軽減できたと思います…

とりあえず、任意の変数名での設置・チェックして条件が整っていればAセリフ、整っていなければBセリフ・取得変数の確認ができるスクリプトを書いてもらいました。

ここで第一関門。
設置とチェックが完璧なのに、フラグが立たない状態。
何度もアドバイスをもらい、事細かくログにでるようにしてもらい、長時間格闘することになりました。

原因はなんてことない、Unityでの設定の仕方を理解していなかっただけです。
「変数」を設置する際、「Value」などのチェックボックスをチェックしないと「ture」にならない、ということでした。
チェックしていれば取得時に「ture」、していなければ「false」になる、という設定みたいです。

チェックボックスはどうすれば?という質問もすでにしていたのですが、チェックしなくていいよーと言われていたので、
原因究明に時間がかかりました(#^ω^)

そしてトラブル中に、変数についての知識も増えていき、

  • 「変数を一時的に保存するスクリプト」と「変数付与と変数チェックスクリプト」は分けた方が良いということ
  • 「変数を一時的に保存するスクリプト」の設置は1つのSceneだけで良くて、使いまわせるということ
  • 「bool型」を保存することと、その他の変数を保存することは共通ではなく、それ用に記述する必要があること
  • 「int」「float」「string」も使用できるようにすると、各条件なんかも拡張しておいたほうが良いこと

などなどが襲いかかってきました。

3つ統合でうまくいっていたものを分解しようとすると、まぁうまくはいかず、
スキルがないので該当記述だけを抜き出して、手動で改修するなんてこともできないわけで、
さらに機能追加となると、指示も良く分からなくなってくる始末です…

なんとか2つに分け、扱える変数も増やし、挙動も問題ないところまで持っていくことができました。
その作業中も、変数に対して次々にやらなくてはならないことが増えていき、「変数システム」の大変さを思い知りました。

(あれ?こういう構築をすっ飛ばして、楽に開発するためにゲームエンジン使ってるんじゃなかったっけ??)
という疑問もわいてきましたが、スクリプトは書いてもらっているので、それだけでもAIゲームエンジンしてますね…

テストプレイ時の「一時保存スクリプト」の自動生成

変数一時保存スクリプトは、開始時のSceneに一回設置すれば良いとのことでした。
しかし設置していないSceneのテストプレイ時には、設置を経由していないので、エラーになります。
そこで、テストプレイ時に存在しない場合は「自動生成」してくれるように機能を追加してくれました。

Sceneでの使いまわし方法は「DontDestryOnLoad」という仕組みを使うようです。

どちらの機能も(へぇ~そんなことできるんだぁ)と思いながらAI任せで学んでいくという…

変数の「型」ではなく「種類」を3つ作る。

  • 一時的に使用したいだけの変数
  • セーブデータなどに保存しておきたい変数
  • クリア済み条件として永久的に残っていて欲しい変数

これらの使い分けも必要だったので、「接頭辞」の有無と種類によって、自動で振り分けてもらえるようにしました。
具体的には、セーブデータ用の変数名には「SAV_」、永久保存用の変数名には「SYS_」と頭につければ、それでふりわけてもらえる、というものです。

セーブロードシステムにはまだ手を出していないので、そこは手入れする余地を残し、
永久保存用は、PC内にJSONファイルを自動生成して、そこに保存するという仕組みです。

変数設置といっても、考えなくてはいけなかったことが多すぎて、手軽に実装しようとしたことを後悔しました。
おかげで、基本的考え方は学べたのでそれは良かったですが…

今回の変数システムについては 変数(フラグ)システム【Unity】 で詳しく説明しています。

システム構築に紆余曲折ありましたが、当初のやりたいことはできました。
「bool型」オン(true)オフ(false)のシンプルな条件での挙動です。

セーブ・ロード問題の解決メモ★0806

探索パート(Search_Rack1)の会話・演出再生中にセーブ・ロードを行った際、意図しない挙動が発生。

問題A:
Msg_Search_Rack1_A のセリフ途中でセーブ&ロードを行うと、
会話が終了した扱いとなり、ロード直後に次の Msg_Search_Rack1_B が再生されてしまう。

問題B:
会話 B の終了後、画像表示用オブジェクト(Msg_Search_Rack1_B2)が表示されている状態でセーブ&ロードを行うと、
直前の会話 B が最初から再再生されてしまう。

■ 根本原因の分析

原因1:フラグ加算(更新)タイミングの誤り
Rack1_Flag(フラグ評価・切り替えを行うコントローラー)を
通った(アクティブ化された)「瞬間(会話の開始前・途中)」 に SAV_ フラグの加算(+1)を行っていたため。
・会話を最後まで読み進めていない(途中でセーブした)場合でも、データ上は「フラグ更新済み」として保存され、ロード時に次の分岐が評価されてしまっていた。

原因2:演出状態(B2)のフラグ未割り当て
Msg_Search_Rack1_B2(画像表示)を独立した状態として管理しておらず、
データ上は「Msg_Search_Rack1_B を再生する条件(フラグ値)」のまま維持されていたため。
・ロード時にシステムが参照するフラグ値が B のままであるため、仕様通り B のセリフが再読み込みされていた。

■ 採用した解決策(スクリプト改修なし・設定のみ)

Hierarchy構造の大幅変更やスクリプト修正は行わず、
「フラグの加算位置の移動」 および 「フラグ値による状態の細分化」 のみで解決。

・分岐の数と同数の変数チェックを設置すること。
・Messenger(会話システム)がないオブジェクト表示の際に、フラグ加算を忘れず行うこと。

① フラグ加算処理の移動(会話読了時へ)

  • Rack1_Flag は 「現在のフラグ値を見て、どのオブジェクトを起動するか判定(チェック)するだけ」 の役割に限定(加算処理を削除)。
  • 会話が完全に終了したタイミングで通過する Msg_Search_Rack1_End に「フラグ加算(+1)」の役割を移動。

結果:会話途中でセーブしても「まだ未読(フラグ未加算)」として保存され、ロード後も正しく現在の会話の最初から復元されるようになった。

② フラグ値の細分化(B2 の独立状態化)

  • Msg_Search_Rack1_B(セリフ)の終了時ではなく、Msg_Search_Rack1_B2(画像表示)の終了・通過タイミングでフラグをさらに +1 加算するよう調整。
  • Rack1_Flag に B2 用の条件判定(例: Count == 2)を追加し、C の起動条件をさらにその上の数値(例: Count == 3)に繰り下げた。

結果:B2 表示中にセーブ&ロードを行っても、B2(画像表示)のみが正確に再構築・表示されるようになった。

■ 今後の構築ルール・標準テンプレート

今後の探索オブジェクト(Search_Rack2 以降など)を作成する際は、本設計原則を共通ルールとして適用する。

【フラグ制御の原則】

  1. 判定(Check)と 付与(Set/Add)を明確に分離する
    ・評価コントローラー(Rack_Flag): 「チェック」のみ行う(加算は絶対に行わない)
    ・会話・演出の末尾(End / 各状態の最後): 「フラグ加算(付与)」を行う
  2. セーブロードで状態を保持したい画面・演出はすべて「独立したフラグ値(State)」として刻む
    ・フラグ値 = 0 : 会話 A 再生
    ・フラグ値 = 1 : 会話 B 再生
    ・フラグ値 = 2 : 演出 B2(画像表示)再生
    ・フラグ値 = 3 : 会話 C 再生(または調査完了状態)
  3. 最終状態(調査完了後)のフォールバック設定
    ・想定外の数値や、調査完了後のクリックに対しては「何も起きない」または「汎用テキスト」が判定されるように条件上限(例: Count >= 3)を意識して設定する。

調べる回数が条件のギミック

探索パートの根幹を作っていきます。

  • 1回目:探索ボタンをクリックでデフォルトセリフ
  • 2回目:さらにクリックで、情報を取得
  • 3回目:調べつくしたあとのセリフ

といったところでしょうか。
変数は「int型」を設置し、クリックするたびに「+1」していく仕組みになります。
「0」の場合「1」の場合「2」の場合、と条件で分岐させます。

変数付与スクリプトを記述してもらっていた時、
「条件として、Min数値とMax数値の範囲指定もできるようにしといたほうが良いですよ」というアドバイスとともに、そのように書いてもらっていたので、さっそくMax設定を使用させてもらいました。

セリフ変化は3回で終わりなので、「2」になった時点で「+1」しなくてよくなりますので、Max数値に「2」を設定しておきます。

システムさえできあがっていれば、あとはそれぞれ指定していけばよいので、とても楽です。

一方、オブジェクト指向で自分構築だと、オブジェクトでの分岐や締めのオブジェクトではなにを非アクティブにしておくか、というような作業がパズルみたいにのしかかってきました。

変数もインスペクターで視認しやすく編集可能にしていますが、
15前後を設置しただけで、ちょっと見にくくなってきていたのでそれも再考の余地はありそうです。

「int型」分岐も想定通りの挙動にできました。
取得した変数を持ち越して、「論争パート」で使用できることを願い、探索パートひな形の完成です。

Scene遷移ギミック

今回のゲームは(将来のゲームでもですが)複数のSceneで構成されています。
UnityではSceneの扱いも独特?っぽいので注意が必要です。
複雑な訳ではなく「登録し忘れ」というミスが発生する可能性があるということです。

「調査を終わります」ボタンをクリックしたら、別Sceneに遷移するギミックを作ります。

「ビルド設定」を開き、制作していてゲーム内で使用するSceneの登録をします。

現在開いているSceneを「Add Open Scenes」ボタンで登録するか、「Asset」フォルダからSceneをドラッグします。
「Scenes In Build」に使用Sceneが順番に登録されていることが確認できたら完了です。
右側の「0」「1」「2」という数字がScene番号になるので、Sceneの指標にもなります。

「調査を終わります」ボタンに「SceneManager.LoadScene(“読み込みたいシーン名”);」などのスクリプトを読み込ませれば、Scene遷移も完了です。

次回は、若干のゲーム性を加える「論争パート」の制作開始です。
「ゲーム性」については、すでにAIとケンカしながら作り上げいます…
結論がそれでいいのかはおいておいて、ですが…

コメント