メインコンテンツまでスキップ
バージョン: 1.3.0

Step2-3:Collision Checker を使用したコリジョンチェックの実行

はじめに

この Step では、Collision Checker を使用するための事前準備と、Collision Checker を使用してコリジョンチェックを実施する手順を確認します。

Playthrough Tester の設計

Collision Checker は、マップ上のすべての壁に衝突して当たり判定に問題がないかチェックする自動テストツールです。
大量のゲームインスタンスを並列起動し、広大なマップのあらゆる場所の当たり判定を自動で、かつ再現可能な形でチェックします。 従来人手で行われていた作業をコンピュータで代替するだけでなく、人手では確認困難なコリジョンの抜けも網羅的に発見できます。

具体的には以下の流れでテストを行います。

ヒント

より詳しい構成や技術仕様については、こちらをご覧ください。

環境構築

まだ環境構築を行っていない場合は、Step1をご覧ください。

事前準備

ダウンロードした Collision Checker には Alfort(サンプルゲーム)に対応した実装コードが含まれています。
そのため、Unreal Engine 5 の Third Person Template Projects(以下、プロジェクトと呼称)に適用するために、いくつかのコード変更、設定変更が必要となります。

ヒント

それぞれの実装意図や各パラメーターの詳細については、こちらをご覧ください。

プロジェクトに利用するための実装コードを準備する

Alfort(サンプルゲーム)に対応した実装コードを複製して、プロジェクトのための実装コードを準備します。
具体的には以下の手順を取ります。

  1. Python/custom/ フォルダ以下にある alfort フォルダをコピーし、フォルダ名をプロジェクト名にリネームします。
    この Step では、プロジェクトの名称は「template」とします。

  2. Python/custom/**init**.py の 1-5 行目を以下のように変更し、コードの読み込み先を上記フォルダに変更します。

    - from .unity_demo.custom_wrapper import \*
    - from .unity_demo.custom_util import \*
    - from .unity_demo.debug_launcher import \*
    - from .unity_demo.state_machines import \*
    - from .unity_demo.custom_wrapper import \*

    * from .template.custom_wrapper import \*
    * from .template.custom_util import \*
    * from .template.debug_launcher import \*
    * from .template.state_machines import \*
    * from .template.custom_wrapper import \*

マップ画像を用意する

Collision Checker ではマップ画像を使用しますが、プロジェクトにはマップ画像に相当するものが存在しません。

そこで、エディタ上でスクリーンショットを撮影したものをマップ画像として使用します。

マップスキャンデータを用意する

Step2-2 で作成したマップデータを \Python\data{ゲーム ID}_{テスト ID} 以下に配置します。
この Step では {ゲーム ID}_{テスト ID} で表すディレクトリ名を template_test とします。

以下のようなディレクトリ構成となっていることを確認してください。

Python/

└ data/
└ template_test/
└ {template}/
└ road_data/
└ wall_data/
└ water_data/
└ _is_close.npy
└ _search_map.npy
└ _map_list.yaml
ヒント

_map_list.yaml の設定は step2-2 と同様です。
それぞれのパラメーターの詳細については、_map_list.yaml 設定ファイルおよびmap_param_calcをご覧ください。

プロジェクトで実装されていない操作に紐づく処理を削除する

\Python\custom\ 内で、主にセーブ機能やタイトル画面に関連する実装の削除・変更を行います。
実装例を示しますので、それに従って対応を行ってください。

custom_util.py

プロジェクトにはセーブデータが存在しません。
そのため、9-37 行目 copy_savefile() について、コードコメントのとおり、返り値を None とします。

def copy_savefile(folder_path: str, env_path: str, map_name: str) -> str:
return None

debug_launcher.py

12-38 行目 CustomDebugLauncher.load_savedata_async()

ゲーム起動後にロード画面を操作するための関数です。 Third Person テンプレートではタイトル画面やロード画面が存在しないため、以下のようにこれらに関わる操作を全てコメントアウトしてください。

    def load_savedata_async(self, callback: Callable = None) -> bool:
"""セーブデータのロード (非同期処理)

Args:
callback (Callable, optional): 処理終了時に呼ばれる関数. Defaults to None.

Returns:
bool: 処理が終了したなら True、そうでないなら False
"""
if self.status == "waiting":
- # if self.level == "game":
- # self.order_list.append(OpenGameMenu())
- # self.order_list.append(SelectMenuButton("タイトルへ戻る"))
- # self.order_list.append(WaitBackToTitle())
- # self.order_list.append(WaitSec(1))
- # self.order_list.append(SelectMenuButton("ロード", check=False))
- # self.order_list.append(WaitSec(1))
- # self.order_list.append(SelectSaveData(self.savename))
# ここより下は変えない
self.order_list.append(WaitLoading())
self.state = "Executing Order"
self.callback = callback
return self.status == "waiting"
40-66 行目 CustomDebugLauncher.option_debugfunc_setup_async()

ゲーム画面へ遷移した後、テストに必要なデバッグ機能などの設定操作を行うための関数です。 Third Person テンプレートではデバッグ機能やゲームオプションが存在しないため、以下のようにこれらに関わる操作を全てコメントアウトしてください。

    def option_debugfunc_setup_async(self, callback: Callable = None) -> bool:
"""各種デバッグ機能の設定 (非同期処理)

Args:
callback (Callable, optional): 処理終了時に呼ばれる関数. Defaults to None.

Returns:
bool: 処理が終了したなら True、そうでないなら False
"""
if self.status == "waiting":
if self.level == "game":
- # self.order_list.append(SwitchDebugMenu())
- # self.order_list.append(WaitSec(1))
- # self.order_list.append(SelectMenuButton("EnemyAI停止", check=False))
- # self.order_list.append(WaitSec(1))
- # self.order_list.append(SelectMenuButton("Player無敵切り替え", check=False))
- # self.order_list.append(WaitSec(1))
- # self.order_list.append(SelectMenuButton("バグコリジョン切り替え", check=False))
- # self.order_list.append(WaitSec(1))
- # self.order_list.append(SelectMenuButton("マップチェンジトリガー切り替え", check=False))
- # self.order_list.append(WaitSec(1))
- # self.order_list.append(SelectMenuButton("全ての扉を開放する", check=False))
- # self.order_list.append(WaitSec(1))
- # self.order_list.append(SwitchDebugMenu())
# これより下は変えない
self.callback = callback
return self.status == "waiting"
204-231 行目 CustomDebugLauncher.SwitchDebugMove(Order)
     """
デバッグ移動モードの ON/OFF 切り替え
"""

def __init__(self):
super().__init__()
self.start_frame = None # デバッグ移動モードの切り替え操作を開始した時間 (フレーム)

def execute(self, game_dict: dict) -> Tuple[bridge.PseudoPadInput, bool]:
pad_input, done = super().execute(game_dict)
if self.start_frame is None:
- self.start_debugmove_state = game_dict["Alfort"]["DebugCamera"]["DebugCameraMode"] # 操作開始前のデバッグ移動ON/OFF状態
+ self.start_debugmove_state = game_dict["DebugCamera"]["DebugCameraMode"] # 操作開始前のデバッグ移動ON/OFF状態
self.start_frame = self.elapsed_frame
if self.elapsed_frame - self.start_frame > 20:
pad_input.LeftTriggerThreshold = True
pad_input.RightTriggerThreshold = True
if self.elapsed_frame - self.start_frame > 40:
pad_input.LeftThumb = True
if self.elapsed_frame - self.start_frame > 60:
pad_input.LeftTriggerThreshold = False
pad_input.RightTriggerThreshold = False
pad_input.LeftThumb = False
- if game_dict["Alfort"]["DebugCamera"]["DebugCameraMode"] != self.start_debugmove_state:
+ if game_dict["DebugCamera"]["DebugCameraMode"] != self.start_debugmove_state:
done = True # 操作開始時とON/OFFが切り替わっていることを確認
else:
self.start_frame = self.elapsed_frame # 切り替えに失敗したら操作を一からやり直し
return pad_input, done

コリジョンファイルを生成する

衝突すべき壁がある箇所を抽出し、その箇所をテスト対象として設定する役割を持つコリジョンファイルを生成します。

以下のコマンドを実行してください。

$ cd {playable-collision-checker のディレクトリ}/Python
$ python make_colfile.py --data ./data/template_test/ --dist 75 --map all
ヒント

それぞれのコマンドオプションの詳細はこちらをご覧ください。

実行が完了したら、Python/data/template_test/template 以下にコリジョンファイル collision_completed_75.json があることを確認してください。
生成されたファイルを collision_completed.json にリネームしてください。

Collision Checker を実行する

プロセスを起動する

Map Scanner の実行時と同様に、この Step ではクライアント・サーバーともに同一の PC で実行を行います。

Anaconda Prompt を起動後、以下のコマンドを実行して Map Scanner 用の仮想環境に切り替えてください。

$ conda activate collisionchecker  # 仮想環境の切り替え
$ cd {playable-collision-checker のディレクトリ}/Python # ディレクトリの移動

以下のコマンドでサーバープログラム、クライアントプログラムをそれぞれ起動します。
上述のとおり複数のクライアントサーバーを用いて並列稼働させることを想定していますが、それぞれのプログラムを同一のコンピューターで実行することも可能です。

$ python svrun_server.py -n 1 -m template -d ./data/template_test/ #サーバープログラムの起動
$ python svrun_client.py -n 1 -d ./data/template_test/ #クライアントプログラムの起動
ヒント

上記では-n 1 -d となっていますが、この 1 の部分を任意の起動したいスレッドの数に変更するとスレッドを増やすことが可能です。

Collision Checker には GUI の操作画面は存在しないため、クライアントプログラムを実行するコマンドを入力すると、ゲームが起動しコリジョンチェックが開始されます。

ヒント

それぞれのコマンドオプションの詳細はこちらをご覧ください。

後処理を行う

Collision Checker の実行完了後、テスト結果の確認、及び結果確認のために必要な準備を行います。

ビューワーの実行に必要なデータを用意する

各マップのテスト結果ファイル template__reach_log.json が作成されていることを確認します。 このファイルを Python/data/template_test/template 以下にコピーし、reach_log.json にリネームします。

Collision Checker Result Viewer で結果確認を行う

step1 と同様に、Collision Checker Result Viewer を起動してコリジョンチェックの結果を確認します。

$ python result_viewer.py

以下のような結果が得られれば完了です。

ヒント

Third Person テンプレート上の青い立方体は、プレイヤーを衝突させることで押すことができます。
その結果、本ツールで「壁」とみなす対象の位置が変わることになるため、接触点 (黄緑色の直方体) の位置が上図とは異なる場合があります。

次のステップ

おつかれさまでした!

次の Step では Playthrough Tester を利用し、通しプレイの実行方法について学びましょう。
チュートリアル Step2-4 へ