【UE5】EQSを解体する【AI/EQS】
概要
UE5のEQS(Environment Query System)がわかりにくいから解体する
基本的な使い方はAIの移動先として指定するための座標の評価に使う
公式にもリファレンスはあるが、違う、そうじゃないって内容しか無いので噛み砕くことにする。
なお、日本語名は「環境クエリ」
まずEQSって何ができるんだ
座標を返してくれる。
逆に言うと座標を返すだけの仕組み。
物によってはEQS使うより、自分で座標を指定したほうが早いまである。
じゃあ何が強みなんだというと、だいたいこの辺りに行ってほしいなぁという「フワッとした」座標の指定に対してはとても強いのがEQSというもの。
細かいコントロールが効かないのでそのあたりは良し悪し
じゃあEQSってどういう流れで動くんだ

EQS動作の一連の流れは
- 環境クエリアセットの作成
- ジェネレーターにより、上記画像のように丸い[Item]をばら撒く
主な設定項目は[範囲]、[密度]、[高低差の許容量]といったところ
あんまり高密度にすると非常に重い。

-
テストによって上記ジェネレーターで作った[Item]を仕分けしていく

- 最終的に「最も優良だったItem」の座標を返す
↓の場合、四隅の1.0のいずれかが対象となる

これがEQS単体としての機能
BPでEQSを使う場合
EQSは主にAIで使われるが、手軽に実行して確認するにはやはりBPで確認するに限る

わかりにくいが、上記の1.0にあたる場所にSpawnActorができた。
1.0に当たる部分は4箇所あったため、やるたびに指定される位置が違うのもEQSの良さであり悪さでもある。

ジェネレータの種類と設定
もうこの画像でいいや

SimpleGrid
- GridHalfSize
- 配置する半径
- SpaceBetween
- 何cm間隔で配置するか
- GridHalfSize x GridHalfSize / SpaceBetWeenでItemの生成数となる
- GenerateAround
- Itemを配置する中心点
- デフォルトではEQS自身(AIキャラクター)を中心とする設定
- EnvQueryContextによって専用の座標を指定可能
- ProjectionData
- Itemの並べ方設定
- TraceMode
- Navigation
- その高さにそのまま並べていく
- Geometry~
- 床などに沿って並べていく
- トレース設定で床を選べる
- Navigation
- ProjectDown/Up
- 配置するItemの上限・下限
- 階層のあるマップだと結構設定が大変そう(上の床にItem出たりする
- Post Projection Vertical Offset
- NavMesh関連らしいが…
テストの種類と内容
Distance
中心からの距離によって評価するテスト
- TestMode:評価する方向
- Distance3D
-
高さを考慮した直線距離。
ジェネレータの設定がGeometryじゃないとあまり意味がないかも
※平面ではなく立体にItemを配置するジェネレータがあればその限りではない
-
- Distance2D
- 高さを無視した直線距離。ゲームによってはコレで何も問題ない
- DistanceZ
- 純粋な高さのみの評価。
中心からの高低差で評価
- 純粋な高さのみの評価。
- DistanceZ(Absolute)
- 純粋な高さのみの評価。
中心からではなく、ワールドからの高さで評価する
GetActorLocationのZそのままを使うということ
- 純粋な高さのみの評価。
- Distance3D
- DistanceTo
- 評価を開始する中心点
- Contextクラスによって評価の中心点を設定できる
- DistanceZ(Absolute)はワールド座標の0地点に補正をかける感じ
- FilterType
- 特定の範囲のItemを評価しないフィルターの設定
- この設定の範囲外となったItemはどんなにいい位置にあっても選ばれない(評価0に固定される)
- Range
- Min~Max範囲で評価する。それより外側は全部評価0に。
- Minimum
- Min以上の範囲で評価する。Min以下は人権なし
- Maximum
- Max以下の範囲で評価する。Max以上はデカすぎて出禁
- 特定の範囲のItemを評価しないフィルターの設定
- スコア関係
- ScoringEquation
- Constant
- 100点か0点かの2極。ちょっとでも条件満たしていればOK!なぐらいガバガバ評価
- Linear
- 0~1をまっすぐ評価する一番素直な設定
- 特に理由がなければコレでOK
- InverseLinear
- Linerarの逆。1~0として評価する
- 近いほど~を遠いほど~に変える時とか。
- ほかはまぁ…ええか
- Constant
- ScoringFactor
- スコアにかける倍率
- -1にすると評価を反転させられる
- 場合によっては1.0以上の値にすることも可能
- NormalizationType
- スコアの範囲設定
- 基本的にどちらを選んでも、Itemごとの順位は変わらない
- Absolute
- 与えられた範囲でそのまま点数をつける
- Relative to Score
- 全ての評価できるItemの中で0~1範囲を設定する
- 必ず0点を100点が生まれ、その間もいる評価
- Clamping
- スコアのしきい値を作るらしいが、どうにもうまく扱えない。
- 特定のスコア以上を全部1にするとか0にするタイプの処理だとは思うんだが。
とりあえず今回はここまでにしておこう
ドキュメント読むより、触っていくほうが早いわこれ
ドキュメントが進次郎構文みたいになってて役に立たないというのもあるけど。
【UE5】アイリスアウト演出を作成する【Widget/Material】
今回作るのはこれ
ブログのネタをサクっとね
— ネリスさん (@NelisLuna) 2024年3月29日
任意位置に任意サイズで配置可能な「アイリス・アウト」の実装方法
チュートリアルなどの注視用やフェードアウト、ゲームの演出にも使えるかな?#UE5 #UE5Study pic.twitter.com/qcLfk5zO1g
古風な「もうこりごりだ~」と共にフェードアウトしていくあの演出を作成していく。
ここ最近だとダンジョン飯のこのシーンのアレ
アイリスアウトと呼ばれるらしい。

そんなに複雑な事をしないのでサクっとね
続きを読む
【UE5】アイテム取得表示Widgetを作成しよう【Widget】
要するにこれを作る
ドロップアイテム表示処理を実装
— ネリスさん (@NelisLuna) 2023年9月30日
経験値は表示する必要はないけど、にぎやかしに今は表示。(アイテム扱いではある)
手癖で作るから同じようなものができちゃうけど、ままえやろ#UE5 pic.twitter.com/rgbqerhmAa
アイテムを入手した時にニュっと生えてきてシュっと退場するやつ。
続きを読む【UE4/UE5】3D人さんのポストプロセスの覚え書き
自分向けのためざっくり
Stylized Post Process for Unreal Engine 5 - UE5で手軽に使えるStylizedポストプロセスマテリアル!無料公開!https://t.co/3gvKRI44hv
— 3D人-3dnchu- CG情報ブログ (@ymt3d) 2023年6月8日
お待たせいたしました。
Gumroadページに載せる適用画像募集中です#3dnchu #UE5 #UnrealEngine #UnrealEngine5 #無料 #Free pic.twitter.com/nLxVUFk2xs
個人的にサンプルの01,03,07,09が使いやすいと感じた
順番にサンプルの03、07、01、09を無調整で使用
— ネリスさん (@NelisLuna) 2023年6月8日
影にハッチングが乗る都合上、顔とかにかかると結構おかしく見えてしまうから、RectLightを当てるなどで回避しようかな
アウトライン周りは浮きやすかったので要調整したいところ。#UE5 https://t.co/rQY6zpXXG0 pic.twitter.com/wp2bInZ7m0
VRM4Uでインポートしたモデルについてはマテリアルの設定をちゃんとしないとこのポストプロセスにうまく合わないため調整が必要
VRM4UのMToonLitでNormal to Lightを1.0にした状態
— ネリスさん (@NelisLuna) 2023年6月11日
それにOverlayMaterialでアウトラインを付けるととても安定した絵になる。
そこに例のポスプロを調整してかけると割となじむ感じになった。#UE5 #UE5Study pic.twitter.com/4l6dj2nBIl
【UE4】アンリアルエンジンにおけるMOD実装・対応について ②【備忘録】
【UE4】アンリアルエンジンにおけるMOD実装・対応について ①【備忘録】
最近では珍しくもないMODの実装について、自分なりにまとめることにした。
方法の記載は確かにあるけど、情報源が足りない…
というか「作る」情報はあっても、ゲーム内でそれを引き出して扱う情報が足りないと思う。
なのでUEにおけるMODとはどういうものか説明を残しておきたい。
※この記事はゲーム本体を完成させパッケージ化できていることを前提にしてるのでご了承を。
記事にする実装内容は大きく分けて5つ
ただし長いので分割する予定。今回は1~2当たりの内容となる
- MODを作成するには
- MODをゲームで適応させるには
- Steamワークショップ対応①MODのアップロード
- Steamワークショップ対応②MODのインストール
- インストールしたMODの削除について
実装までの前置きが長いので不要な人は序盤を飛ばしても大丈夫です
目次
前置き:MODとは?
①「MOD」ってなんぞや?
これを見ているゲーム開発者にはわざわざ言うまでもないが、Modificationの略であり、ゲームの改造を行うためのデータの事を指す。
ゲームのキャラを書き換える、パラメータを変更する、新しいシステムを導入するなど、Steam等のPCゲーマーには身近な存在である。
特に日本人的には海外製ゲームを日本語化するMODは特にありがたいので重宝している。
MODでトーマスが人気なのはよくわからんけど…

当然だが、ゲームの改造という性質上MODを適応した場合に関しては開発側はサポートすることは無い。MOD開発者のほうに聞いてねということになる。
MOD適応下でのゲームのバグまで調査してたらキリがない…
このMODだが、制作側に来た場合には「ユーザーが作成したコンテンツ」
UGC(User Generated Contents)
と呼ばれる事が多い。というか公式側は基本的にこの名称を使っている事が多いため、検索する場合はこちらの名称で調べたほうが正しい情報にたどり着きやすい。
MODで検索かけてもせいぜい作り方とか、作ってる時のパッケージでのバグとか、どちらかといえばユーザーとしての情報ばかりが出てくるのが厄介なところ。
知りたいのは作り方ではなくゲーム本体側の実装なんだけどなぁ。となりがち…
②そもそもUEにおけるMODって何を指すのか?
簡単に言うとゲームの素材などが入っている拡張子が.pakのファイルのこと
そしてその中でも
プラグインコンテンツをパッケージ化したもの
をMODとして扱う。
ゲームをパッケージ化した人なら知っていると思うが、パッケージ化されたフォルダの中にはコンテンツが含まれている.pakという拡張子を持つファイルが存在する。
「Content/Pak/○○.pak」みたいなやつ。
←こいつね
ゲーム起動時に「Content/Pak/」以下に存在するファイルをすべて読み込んで使うため、ここに.pakファイルを置くだけでその中のデータが適応されることになる。
(拡張子が違っても読み込みは正常に行われるから書き換えて.modとかでもいい)
ただし追加したMODである.pakファイルが読み込まれると言っても、ゲーム本体側は本来存在しないデータであるためSpawnしたりレベルを移動したりできないのが実際のところである。
Developmentでパッケージ化するなどしてコンソールコマンドからMap移動等するなどすればMODが適応されたMapで遊べたりはするが、それはちょっと違うよねってなる。
やはりShippingでパッケージ化されたゲーム本体がMODのデータを動的に混ぜることができる対応がベストだろう。
MODの下準備
まずはゲーム本体の適応などは考えずに
MODデータを作りパッケージ化するところまでを実行していく。
プラグインコンテンツの作成
前述したとおりMODとはプラグインをパッケージ化したものなのでまずはプラグインを作る。

右下の「新しいプラグイン」を選択してプラグイン作成ウィンドウを表示する

「コンテンツのみ」を選択し、MODに使うプラグイン名を指定する
この名前は後に使うため、わかりやすいものにすること。

これでプラグインのフォルダが完成。
もし見えない場合はコンテンツブラウザの右下にある「表示オプション」から
「プラグインコンテンツを表示」を選択して探そう

基本的にここで作成したプラグインコンテンツのフォルダ内のものが
そのままMODとしてゲームに認識される事になる。

逆に言うと、MODのコンテンツはそのフォルダ内で完結している、或いはゲーム本体のデータを利用していないとパッケージ化した際にデータが足りなくなるため注意が必要。
MODのMapや装備なんかを自分のアセットを使って作ったけど、フォルダ内に入れ忘れた結果適応した時に何もでなかったりエラーを吐いたりする。
MODのパッケージ化
参考にした動画をそのまま貼っちゃう…。
設定内容は動画のものに従い、余計な設定はしない方が賢明。
プロジェクトランチャーを使いゲームのパッケージ化を行い、
そのあとでプラグインのパッケージ化を行うことで.Pakファイルが作成される。
必ずゲーム本体のパッケージ化を行った後にプラグインのパッケージを行う必要があるので注意。
ちなみに、ゲーム本体のパッケージ化について
こちらの方法は関係がないので横着しないこと。
ちゃんとプロジェクトランチャーでパッケージ化しよう。

成功すれば
Plugins\MyMOD\Saved\StagedBuilds\WindowsNoEditor\MODTest\Plugins\MyMOD\Content\Paks\WindowsNoEditor\
の中に.pakのファイルが生成されているはず。
とても深い場所に生成されるから探すのが面倒。

これが事実上のMODファイルとなる
ファイル名は機能に影響がないので自由に書き換えてOK
パッケージ化したファイルを指定したフォルダに配置する
パッケージ化したMODは適当に名前を変えて
パッケージ化したゲーム本体のContent/Paksフォルダ以下に置けばOK
これだけで起動時に作成したMODが読み込まれる
![]()
MODをゲーム内で使うためには?
※ここからはC++での作業が必須となるので注意
ゲーム起動後に特定のパッケージ内のデータを取得できるようにする
.pakを置くだけで起動時に読み込まれるとはいえ、ゲーム本体はMODのデータのことを知らないためそのままではゲームに影響を与える事ができない。
そのため、ゲーム側にMODがある場合の動作を組み込む必要がある。
(コンソールコマンドでMODの中のMAPに対してOpenLevelするなどの方法はあるが、邪道の類なので今回は除外する)
今回はGameInstanceにMOD内のクラスを引き出せるようにする処理を追加する。
まずC++クラスの追加からGameInstanceのベースクラスを作成する。
もしすでにベースクラスを作っているのであればそれを使う。

まずはScanUGC関数を宣言して

cpp側にEngine/ObjectLibraryをincludeしたうえで
以下の処理を記述する

この処理でmyMODという名前のプラグインで作られたMODの中身を取得できるようにした。
準備は整ったのでこのMyGameInstanceを継承したGameInstanceを作成して
プロジェクトに設定する

プロジェクト設定>マップ&モードのGameInstanceメニュー内から変更できる

その後Init時にScanUGCを呼び出すことでプラグイン(MOD)が読み込まれる

そしてGetAssetRegistryノードからGetAssetbyPathノードを繋いで以下の図のようにすればMODアセットが配列として取得できる。

ただ、このままだとクラスとして扱えないためアセットデータをクラスに変換する処理をC++で記載する
まずはヘッダにGetClassfromAssetData関数を追加

中身はこんな感じに、アセットデータが持つパスからクラスを取得してそれを返す内容

あとはこれを使ってクラスを取得してCastすればアセットデータの中の任意のクラスを引き出すことができる。

やれる人ならクラスが取れれば後はなんとでもできそうではある。
①既存アイテムに追加する方法:例
※アイテムの管理などをデータテーブルで行っていることを前提としての話
データテーブルの代わりになるものを作る。
データテーブルは構造体をキーで管理しているため、その気になればMAP型で再現ができる。MAP型の扱いに関しては別で覚えてほしい。
とりあえずこんな感じでアイテムデータテーブルのようなものを作成。


GameInstanceのメンバ変数としてこんなものを作る。
これが今回のDataTableの代わり

まずはこの配列を元々のデータテーブルで埋める

これによって、Findノードを使うことでデータテーブルとほぼ同等の扱いができるようになった。

つまり、ここにデータを足していくだけでアイテムリストの追加が可能になる
こんな感じに、アイテム追加用クラスを用意してやり、それがMODデータ内にあればCastに成功するためアイテムの追加が完了する

先述した通りデータテーブルと同様の振る舞いが可能なのでGetDatatableRowノードを置き換えてやればMODアイテムが自動的に増やせる
自分はこんな感じにインターフェースを作成し任意の場所からアクセスできるようにしたりしている。

あとはMODアイテムを含んで販売する商人を置いたり、ドロップアイテムとするなりすればゲーム内にMODアイテムが導入できる。
アイテム以外でも敵の種類なども同様。
②既存クラスを置き換える方法:例
クラスの置き換えができるようにする
ざっくり言うと元々のクラスをキーとして、MODクラスを返す関数を作り
そのSpawn処理の前に割り込ませることで特定のクラスをMODクラスに置き換えてしまうという手法。
ただちょっと長くなりすぎているので一旦ここで公開してしまう。
賢い人は今の説明でも何をすればいいかを理解してくれる…はず。
つづく。