梅雨入り
気温は高くないのに蒸し暑く不快指数が高いのでゲーム制作に身が入らない繊細な皆さんこんにちは。かと言ってエアコンを点けると寒くなるし、つけないと汗ばんでイライラするし、エルデンリングDLCは難しいし、と様々な理由でゲーム制作の進捗が進みません。まぁ殆どエルデンリングDLCの所為ですが。
ダウンロードコンテンツ
というわけで、最初の発表から一年ぐらい待ちに待ったDLC(ダウンロードコンテンツ)が発売されたので、早速初日0時からPS5をフル稼働させて遊んでいます。
巷では高難易度ゲームと喧伝されているこのゲーム。本編はオンラインやらNPC、アイテム等の救済措置が数多く用意されているのでゲーム下手な私でもなんとかエンディングまで見る事が出来たのですが、今回のDLCは更に難易度が高くなっており、ボス戦はもちろんフィールド探索中も不意に現れる強敵に何度も倒され続けます。
どうやら今回のDLCはキャラクターのレベルじゃなくゲーム周回数(クリア数)とDLCフィールド内で手に入る「影樹の加護」というステータスによってレベリングされているようで、たとえ高レベルのキャラクターでも周回数が高かったり「影樹の加護」のレベルが低いと敵から2,3回攻撃を受けるだけでゲームオーバーとなってしまいます。
この為、自身のキャラクターがDLC外の本編エリアでは無双状態だったとしてもDLCフィールドではしっかりとしたプレイングが求められ、誰でも歯ごたえのあるゲームプレイを体験する事が出来ます。
特にボス戦は難易度が高く、高火力の攻撃に慣れるまでは何度も倒されてしまうので人によっては挫折しそうになるかもしれません。しかしその強さに理不尽感はなく、試行錯誤を重ねていけば次第と対応できるようになり、いつの間にか攻撃を見切ってこちらからダメージを与えらえるようになります。
こうした戦闘のバランスはさすがフロムらしく素晴らしい調整になっていると思いますし、また、DLCで新しく用意された武器やスキルは数多く個性的な物ばかりなのでそれらを収集するだけでも楽しいですし、立体的に入り組んだフィールドは探索し甲斐がある物ばかりです。
DLCとしてはソコソコのお値段(4,400円)ですがそれ以上のボリュームと価値はあるのではないでしょうか。
シーン遷移
Unityでシーン遷移を行う場合はSceneManagerを使ってシーンのロード、アンロードを行います。シーンの切替のみを行いたい場合はSceneManagerでも特に問題ありませんでしたが、シーン間でデータを受け渡したい場合やシーン遷移の前後で何かしら処理を行いたい場合などはちょっとした工夫が必要でそれなりに実装に時間が掛かりました。
最近、それらの処理をもっと簡単に実現するためのアセットが個人ゲーム制作者の方より開発、公開されています。
このアセットはシーンの遷移・管理を行う為のフレームワーク的アセットで以下の機能が柔軟に行える設計されているようです。
- 基本的な遷移操作
- 遷移履歴管理
- シーン間データ受け渡し
- 柔軟なシーン遷移演出
- 単一シーン起動
- 割り込みシーン操作
導入にはUniTaskが必須となっているようで、事前にUniTaskを開発プロジェクトにインストールしておく必要があります。
Navigathena
上記のリンク内で紹介されているアセット「Navigathena」はGlobalSceneNavigatorとSceneEntryPointという二つのモジュールによって構成されています。
GlobalSceneNavigatorは主にSceneManagerと同様なシーン遷移のAPI-IFを提供しており、SceneEntryPointではシーン遷移に伴うイベントのコールバックIFを提供しています。
NavigathenaではGlobalSceneNavigatorで呼び出されたシーンを履歴として管理しており、それによりシーンが複数存在する場合の遷移を簡単にし、シーン遷移ロジックの簡略化を実現します。
GlobalSceneNavigatorはシングルトンのモジュールでシーン内にGlobalSceneNavigatorアッタチされたオブジェクトがない場合でも、ゲームを実行すると自動的に生成されDon'tDestroyオブジェクトとしてゲーム内に残り続けます。
ゲーム実行中に自動生成される
使い方
単純にシーンを遷移したい場合は、最初にBuildSettings の Scenes in Build の項目に対象となるシーンを登録
それぞれのシーン内にSceneEntryPointBaseを継承したスクリプトがアッタチされたオブジェクトを作ります。
SceneEntryPointBaseはシーンのライフサイクルを監視するためのコンポーネントで前述のようにシーン遷移に伴うイベントのコールバックIF(ISceneEntryPoint)が提供されています。
public interface ISceneEntryPoint { // 遷移演出の開始後に呼び出されます。 UniTask OnInitialize (ISceneDataReader reader, IProgress<IProgressDataStore> transitionProgress, CancellationToken cancellationToken); // 遷移演出の終了後に呼び出されます。 UniTask OnEnter (ISceneDataReader reader, CancellationToken cancellationToken); // 遷移演出の開始前に呼び出されます。 UniTask OnExit (ISceneDataWriter writer, CancellationToken cancellationToken); // 遷移演出の開始後に呼び出されます。 UniTask OnFinalize (ISceneDataWriter writer, IProgress<IProgressDataStore> transitionProgress, CancellationToken cancellationToken); #if UNITY_EDITOR // エディタ内での実行時、一番最初にロードされたシーンで`OnInitialize`の前に呼び出される。 (エディタ専用) UniTask OnEditorFirstPreInitialize (ISceneDataWriter writer, CancellationToken cancellationToken); #endif }
各コールバックは非同期処理となっている事に注意してください。
また、このSceneEntryPoint(SceneEntryPointBaseを継承したスクリプト)は各シーンに一つだけ配置可能なコンポーネントである為、シーン遷移で行いたい処理は一旦このコンポーネント内に集約する必要があります。
そしてSceneEntryPointコンポーネントがアタッチされたオブジェクトはシーン遷移を行う全てのシーンで存在しないといけません。
今回はお試しの為、OnEnterをoverrideしたスクリプトを作成し、TestA,Bどちらのシーン内にも配置しました。
シーンの遷移処理は以下のように実装しました。
BuiltInSceneIdentifierのNewに遷移先のシーン名を渡してISceneIdentifierを取得、このISceneIdentifierをGlobalSceneNavigatorのReplaceメソッドに渡してシーン遷移を行います。
前述のように各シーンはGlobalSceneNavigator内で履歴として管理されておりReplace以外にもPush(新たなシーンをロードして、履歴に追加)やPop(履歴の先頭のシーンを削除して、一つ前のシーンをロード)などのメソッドが用意されていますが、今回のように単一シーンの遷移で良い場合はReplaceで十分だと思います。
実際の動作(TestSceneAからBへ)
データの引き渡し
シーン間でデータの引き渡しを行いたい場合はISceneDataを継承したデータクラスを作成し、それを使用することでデータの引き渡しを行います。
今回の場合、下図のように上の入力フィールドで入力された内容を遷移先のシーンへ引き渡し、下のフィールドに表示する、といったパターンを考えます。
最初にデータクラスを作成
遷移処理では上のデータクラスをシーン遷移時に生成し、入力フィールドの入力内容を設定、Replaceメソッドに渡します。
遷移先のSceneEntryPointのOnEnterに渡されるので、それを取得して下のテキストフィールドに設定します。
これを動作するとこんな感じ。入力フィールドに入力した内容が遷移先シーンに引き渡されている事が確認できました。
最後に
Navigathenaを導入する事でシーン間のデータ引き渡しが簡単に行えることが分かりました。こういったシチュエーションはゲーム内で結構多いと思うのでデータ引継ぎに悩んでいる方は導入を検討されてはどうでしょうか。
また、Navigathenaの作者さんのHPでは他にも色々な使用例が紹介されていますが、基本的にシーン遷移管理を行う為だけのシーンを作り、その下でシーン遷移を行うような想定となっているようです。
このような場合、シーン遷移管理専用のシーンは常に存在し続ける為、それが許容できるプロジェクトやこれから開発を始めるプロジェクトにおいては、Navigathenaを導入し、紹介されている使用例を参考すると利便性を高いシーン管理システムが実現できるではないでしょうか。