Unityっぽい動作とかスクリプトのカスタマイズとか色々必要になってくる
実現したい動作
- Ariadne のダンジョン内から、ORKの戦闘シーンを呼び出す/戻ってくる方法
- 簡単な歩数エンカウントの実装
- 現在位置の保存
- (未)ダンジョン情報の保存
Ariadne のダンジョン内から、ORKの戦闘シーンを呼び出す
ORKの戦闘シーンを呼び出す
Ariadneは仕組み上、Playerの位置が座標固定のため、ORKの持つ衝突判定機能などでのエンカウントが出来ない。
なので、Battleコンポーネントの持つ機能を他の方法で動的に呼び出すしかない。
ORK3のBattleコンポーネントには、読み込むと自動戦闘となる設定があるので、これを利用した
ORK > Batlle > Battle 3D を作成し、「Start Settings」の「Auto > Start」を有効にする。
そして、このオブジェクトに必要な戦闘設定を行い、プレハブ化する。
画面にUpdateが入ったタイミングでエンカウント判定を行うスクリプトを作成する。
例えば下記のように「GlobalVal.encount」がどこかでtrueになれば、オブジェクトを生成する。
// Update is called once per frame
void Update()
{
public GameObject CallBattle;
// 一定時間ごとにプレハブを生成
if (GlobalVal.encount)
{
GlobalVal.encount = false;
// 生成位置
Vector3 pos = new Vector3(0.0f, 10.0f, 0.0f);
Instantiate(CallBattle, pos, Quaternion.identity);
}
}
DemoDungeonのシーンに移行し、任意のGameObjectを作成する。
このGameObjectに、先ほど作ったスクリプトを関連付け、「CallBattle」変数に先ほど指定したPrehubを設定する。
これで、条件を満たすたびに指定したPrehubを生成して戦闘に入るようになった。
どこか適当なクラス(MoveControllerあたりか)に「Globalval.encount」をtrueにしてやる仕組みを入れればテストできるはず。
戦闘シーンへの移行と戻り
戦闘シーンをAriadneダンジョン内で描写するのは難しいため、シーン遷移を用いる。
これは、公式で用意されているテレポート戦闘開始回路図/終了回路図を使えばいい。
回路図を、先ほど指定したプレハブの「Start/End Schenmatic」に紐づければOK
簡単な歩数エンカウントの実装
歩数をカウント(歩行後に判定を行う)する場合、DemoScenePostMoveChecker クラスが移動の送信をチェックしているので、このクラスの「PostMoveEventFinished」に条件を仕込んでやればいい。
適当な変数を++でカウントさせ、条件を満たしたら先ほどのエンカウントフラグをTrueにすればよい。
現在位置の保存
AriadneのMoveControllerが、シーン遷移から戻ってきた時にダンジョンの初期位置を設定するようになっている。
プレイヤーの位置情報はマニュアルに記載のある通り「PlayerPosition」クラスに設定されており、このクラス自体はpublic staticで定義されているため、シーン遷移されても数値自体は保持されている。
詳しい説明は省くが、MoveController.SetInitPos で初期位置の設定を行っているため、そこに条件値を加えてあげればいい。
具体的には下記のように一度は行ったかどうかを管理する変数を追加し、初回読み込み時以降は更新されないようにすればよい。下線部のもともとコードに記載されている箇所を、フラグで囲ってあげれば良い
initPosは現在位置のX,Y座標
directionは向き
currentFloorIDとcurrentDungeonIdは現在はいっているダンジョンとフロアの情報
bool EnteredDungeon = false; protected virtual void SetInitPos() { Vector2Int initPos = Vector2Int.zero; DungeonDir initDir = DungeonDir.North; if (floorMapData != null) { initPos = floorMapData.entrancePos; initDir = floorMapData.enteringDir; } // 2022-10-30 add PlayerPositionが既に設定されている場合は、再設定を行わない if (!EnteredDungeon) { PlayerPosition.playerPos = initPos; PlayerPosition.direction = initDir; PlayerPosition.currentFloorId = floorMapData.floorId; PlayerPosition.currentDungeonId = dungeonData.dungeonId; EnteredDungeon = true; } UnityEngine.Debug.Log(PlayerPosition.direction); float targetAngle = CurrentDirAngle(); player.transform.eulerAngles = new Vector3(0, targetAngle, 0); SetCameraPos(); }
この作りであれば、他にダンジョンから脱出した際にも、この管理用の変数を更新すれば初期位置にリセットすることが可能…だと思う。
宝箱などのフラグがリセットされないようにする
この状態だとシーンの読み込みを行うたびにイベントフラグがリセットされる。(例えば、デモダンジョンの鍵が戦闘シーンに入るたびにリセットされる)
EventFlagManager.csの[eventFlagDict]にstaticを追加することで解決したが、影響が不明
所持アイテムがリセットされないようにする
戦闘シーンから戻ると入手した鍵がロストしてしまうため、イベントフラグと同様に、アイテムもリセットされないようにする
こちらも同様に、ItemDataManager.csの[holdItemDict]にstaticを追加する
この2つ以外には、踏破データがあるが、こちらは現状でも問題なさそう
問題発生
[holdItemDict]はDemoDungeonシーンのインスペクタで初期化を行っており、単純にstaticを追加するだけだとオブジェクトの生成時・処理時にバグることが判明。
どうしたか
色々いじってみたが、[holdItemDict]のインスペクタを用いた動作は、Ariadneの根本に影響しそうなので変えるのが難しい。
後々、ORKのセーブデータ機能を利用するのだが、この時に保持すべき変数を一括で持っているクラスがあるとやりやすい。
そこで、この段階で、そのクラスを作成することにした。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Ariadne
{
public class KeepAriadneData
{
public static Dictionary<int, int> keep_holdItemDict;
public static int keep_money;
}
}
こんな感じの保持用のクラスを用意。(hold は使われているので、keep という、このクラスで保持されていることがわかりやすいよう命名)
ItemDataManager側にもいくつか手を加える。
保持しなければいけないのは、holdingItemDictとmoneyの2つなので、その2つに変化が起きるタイミングで保持用のkeep変数に値を代入する処理を追加する。
具体的には、
- SetPlayerMoney (所持金の初期化):末尾にKeepAriadneData.keep_money = moneyを追加
- IncreasePlayerMoney (所持金の増減):末尾にKeepAriadneData.keep_money = moneyを追加
- InitialiszeHoldItemDict(アイテムリスト、所持アイテムの初期化)
→itemListの後ろにKeepから所持アイテム状況と所持金を戻すコードを追加
→初期化の最後に、アイテム状況を一時保存するコードを追加
※この部分は正直コードが汚くなってしまうので書きなおしたい
public virtual void InitializeHoldItemDict()
{
/* 中略 */
List itemList = itemDataHolder.GetAllItemData();
//20221101 Add 別クラスで値を保持している場合は、値を元に戻す
if (KeepAriadneData.keep_holdItemDict != null)
{
holdItemDict = KeepAriadneData.keep_holdItemDict;
money = KeepAriadneData.keep_money;
return;
}
/* 中略 */
// 処理後、数値の結果を一時保存先に保存する
KeepAriadneData.keep_holdItemDict = holdItemDict;
}
できあがったもの
戦闘に入ってシーン遷移しても、宝箱を開けられたり、鍵の中身を保持していれば成功。
その他
同じようなやり方で、今後もシーン間遷移で保持する必要がありそうな、Ariadne側の変数(前述のイベント系、プレイヤー座標や、踏破状況の保存)を同じやり方で保持する必要がありそう
