新規ゲームへの対応手順
はじめに
新規ゲームに対応するためには、Collision Checker のソースコードを適切に書き換える必要があります。 そのための準備として、以下のことを行ってください。
- ダウンロードした Playable! ライブラリの中にある
playable-collision-checker
フォルダを丸ごとコピーし、playable-collision-checker-{新規ゲーム名}
にリネームします。 playable-collision-checker-{新規ゲーム名}/Python
内のalfort
フォルダを{新規ゲーム名}
にリネームします。playable-collision-checker-{新規ゲーム名}/Python
内の各ファイルでfrom alfort import XXXX
やfrom alfort.XXXX import YYYY
となっている部分を 全てfrom {新規ゲーム名} import XXXX
やfrom {新規ゲーム名}.XXXX import YYYY
に置換します。
各種データの用意
- コリジョンチェックの実行結果を可視化するためのツール内で表示するゲーム内マップ画像を用意します。 テストを行いたいマップ単位で別々の画像を用意してください。
- 画像が用意できたら
Python/res/
以下に配置してください。 また、テストを行いたい各マップのコード名 (以降マップ ID と呼びます) を決め、 画像のファイル名が{マップID}.{拡張子}
となるようにしてください。 以降、このマップ ID を Collision Checker を含めた各ツールのコード内で使用することになります。 また、このマップ ID は Map Scanner でも扱われますが、既に Map Scanner 側で決められている場合はそちらに合わせてください。 - 事前準備 を参照し、手順 1~5 を済ませます。
コード変更箇所
alfort/custom_util.py
ゲーム固有の汎用関数が定義されているコードです。
copy_savefile()
- 指定したマップ用のセーブデータを
Python/data/{バージョン ID}/{マップ ID}
フォルダからゲーム側のセーブデータフォルダにコピーする関数です。
ゲームに応じてコピー先を適切なパスに指定してください。 Unreal Engine であれば、コピー先となるセーブデータフォルダはWindowsNoEditor/{ゲームのコード名}/Saved/SaveGames/
以下にあると思われます。
また、ゲームによってセーブデータの仕様が異なる場合があるため、適切な処理を行ってください。 例えば、サンプルゲームではセーブデータのロードには「ファイル名が可変であるセーブデータ本体」と「ファイル名が不変である SharedData.sav」の 2 種類のファイルが必要となります。 - また、当関数の返り値を以下の仕様に合わせてください。
None
(セーブデータのファイル名が一定 or セーブデータが存在しないゲームの場合)- 読み込むべきセーブデータを一意に特定できる何らかの文字列 (セーブデータのファイル名が一定でないゲームの場合)
- 指定したマップ用のセーブデータを
alfort/state_machines.py
テスト中にプレイヤーキャラクターが取る行動のうち、ゲーム固有のものが記述されているコードです。
class DebugMoveState
>step()
- デバッグ移動状態の時に毎フレーム呼ばれる関数です。
self.__case
が 0 ~ 1 の時はデバッグメニューを操作して通常移動モードからデバッグ移動モードに切り替える操作、 3 ~ 5 の時はデバッグ移動が完了した後に行われる通常移動モードに戻す操作に相当します。 2 の時は実際にデバッグ移動を行う操作に相当します。この部分をゲームによって適切に書き換えてください。備考サンプルゲームのデバッグ移動はプレイヤーではなくカメラを移動させるもので、 ビュー ボタン (Unreal Engine の定義だと SpecialLeft) を押すことでカメラと同じ位置にプレイヤーをワープさせることができる仕様となっています。
- デバッグ移動状態の時に毎フレーム呼ばれる関数です。
class DebugMoveState
>move()
- 実際にデバッグ移動を行う時の操作を定義する関数です。
どのボタン or スティックを使えば移動できるかはゲームによって異なるため、仕様に合わせて適切に記述してください。
この関数は上記の
step
関数を経由して毎フレーム呼ばれるものであるため、 1 フレーム単位での操作方法を記述しなければならないことに注意してください。
- 実際にデバッグ移動を行う時の操作を定義する関数です。
どのボタン or スティックを使えば移動できるかはゲームによって異なるため、仕様に合わせて適切に記述してください。
この関数は上記の
svrun_client_logic.py
テスト実行時のクライアントエージェントの挙動を司るコードです。
class CollisionTestAgent
>does_player_drop()
- プレイヤーが奈落落ちした時は
True
、そうでないときはFalse
を返す関数です。 「どのような状態の時に奈落落ちしたと判定するか」の条件式をゲームの奈落落ち仕様に合わせて適切に記述してください。なお、ゲームから「奈落落ち状態の判定材料となるゲーム内情報」が送信できるようになっていることが前提となります。備考サンプルゲームには奈落落ちという概念が存在しないため、エリアごとに z 座標の閾値 (標高が最も低い地点より少し下側に設定) を決めておき、 衝突行動中に z 座標がこれを下回ったら
True
としています。
- プレイヤーが奈落落ちした時は
class CollisionTestUtility
>init_game()
- ゲームの起動、及びリセット後に行われる処理です。
テスト開始前に行うべき操作や設定 (タイトル/ロード画面の突破、無敵化などの各種デバッグオプション設定) を自動操作で実現するために、
クラス
DebugLauncher
で定義した関数群を適切な順序で組み合わせて登録してください。 クラスDebugLauncher
に関する説明は後述のalfort/debug_launcher.py
の項を参照してください。
- ゲームの起動、及びリセット後に行われる処理です。
テスト開始前に行うべき操作や設定 (タイトル/ロード画面の突破、無敵化などの各種デバッグオプション設定) を自動操作で実現するために、
クラス
alfort/debug_launcher.py
ゲーム固有(ここではサンプルゲーム固有)のタイトル画面/ゲーム内メニュー/デバッグメニューの操作アルゴリズムが記述されているコードです。
主にテスト開始前の設定に必要な操作や、テスト中に必要な操作のうちアウトゲーム的な部分に相当します。 ここで必要とされるコードの変更は、ほとんどがゲームによって全く異なると考えられ、決まった手順を書くことはできません。 ゲームの仕様を調べ、それに合うように適切なルール化を行ってください。
class DebugLauncher > step()
self.level = xxxx
の部分で、ゲームから毎フレーム送信される情報を参照し、現在ゲームプレー画面 or タイトル画面などの非ゲームプレー画面にいるのかを判定しています。 この判定ルールをゲームに応じて適切に設定してください。 基本的にはゲームから現在どのレベルにいるのかという情報が送信されるはずなので、それを元に場合分けすれば大丈夫です。
# 命令群
とコメントが書かれている部分以降- 各種メニュー操作を細かな単位に分解したものが定義されています。ゲームに合わせて適切なものを用意してください。例として Alfort では以下のものが用意されています。
- 特定の項目 (引数と一致する文字列) を選択する
- メニューの開閉を行う
- 指定したボタンを 1 回押す など
- 各種メニュー操作を細かな単位に分解したものが定義されています。ゲームに合わせて適切なものを用意してください。例として Alfort では以下のものが用意されています。
# 命令群
とコメントが書かれている部分以前- 上記で定義した細かな単位の操作を組み合わせ、特定のことを行うのに必要な一連の操作を定義してください。
各操作に対応する関数には、ゲームと非同期で操作を行う
XXXX_async
と、ゲームと同期して操作を行うXXXX_sync
が存在します。 既存のコードを参考にして両方用意してください。例として Alfort では以下のものが用意されています。- セーブデータをロードするために必要な一連のパッド操作
- 特定のデバッグ機能を ON/OFF するために必要な一連のパッド操作 など備考
class Order
及びOrder
を継承しているクラスの多くは Playthrough Tester、Map Scanner と共通して使えるため、 他のツールで既に変更対応が済んでいればコピペするだけでよいです。 ただし、他のツールでは必要のない操作が Collision Checker では必要となることも考えられるので注意してください。 なお、これらのクラスはsvrun_client_logic.py > CollisionTestUtility > init_game()
をはじめとした同コード内の各所やresult_viewer.py > Main_Model > run_exe()
からDebugLauncher.instance.XXXX
を経由する形で呼び出されています。
- 上記で定義した細かな単位の操作を組み合わせ、特定のことを行うのに必要な一連の操作を定義してください。
各操作に対応する関数には、ゲームと非同期で操作を行う
utils/assert_window_watcher.py
ゲームのウィンドウを常に監視し、ポップアップウィンドウが出現したら自動で閉じるためのコードです。
サンプルゲームでは現在は使用されていませんが、今後エラー状況の記録が必要になる場合を想定しサンプルとして実装してあります。 なお、以下で説明する変更対応を行っても動かない可能性が考えられるため、ゲーム毎にカスタマイズしてください。
__set_foreground_handler()
# ウィンドウのタイトル名が XXX から始まる
とコメントにある通り、if name.find('Alfort') >= 0:
の部分で監視対象となるゲームのウィンドウ名の先頭文字列を指定してください。
get_window_handle()
handle = win32gui.FindWindow(32770, "ASSERT")
の部分で、第 2 引数を自動で閉じたいウィンドウの名前を指定してください。 また、第 1 引数に閉じたいウィンドウのウィンドウクラスを指定してください。備考ウィンドウ クラスについて - Win32 apps
https://learn.microsoft.com/ja-jp/windows/win32/winmsg/about-window-classes
Unreal Engine 側の変更
こちらの資料に従って CollisionTest プラグインの導入を行ってください。