はじめに
UENightはUnrealEngineのちょっとニッチな技術や機能について語り合ったり討論したりするイベントです。月に一度程度の間隔で開催しています。この記事は10/12に開催されたUE5 Logic Nightのログです。
開催場所のDiscordの招待リンクはこちら
初心者からガチプロまで誰でも参加可能です。
過去に開催されたお題
・GAS
・Rig
・最適化&デバッグ
・Logic(クラス設計やコーディング)
※こちらのイベント/レポートの整合性、動作などの一切内容の保障は致しかねます
※筆者のスキルが追い付いていないため、一部自分の中で要約している部分がありますが、もし間違いなどあればお気軽にTwitter(@Gisu_Love)、Discord(Tukigase)、Qiitaの編集リクエストなどでご連絡ください
本編
pause中にSet Timer by Eventが動かなくなるが、Tickで代用する以外にいい方法はあるか?
Set Timer by Event はTimer managerで時間を見ている。
Timer ManagerはWorld Tickで呼ばれていて、World TickはPauseが入るとTimer Managerを呼ばなくなるので動かなくなる。(Delayも同じ扱い)
また、Set Global Time Dilation,Set Custom Time Dilationなども影響する
C++で改造するしかない。
Tickでやるのが正統っぽい。
Timer的にTickを使うのって…?
繋がる先による。
空Tickが残っているほうが悪
(詳しくはこちらの記事を参照)
ゴースト状態に戻す方法
ActorのSelfを選択した状態で詳細のアクタティックで「Start With Tick Enable」をFlaseにするとTickをオフにできる。が、上のような見た目ゴースト状態には戻らない模様…
他にも
Tick IntervalからTickが発行される間隔(0.0で毎フレーム)
Allow Tick Begore BeginPlay(BeginPlay前にもTickを有効にする)などの項目がある。
Tickとn秒ごとのカウントを両立したい
Set Timer by Eventのループか、Tickで1秒たった…などカウントする関数を作ってカウントする。
Actorとコンポーネントでは別のTick Intervalを設定できるのでそこで分ける。
プレイヤーが作成したActor同士での継承
公式のサンプルLyraでは継承が多用されている(この記事参考)が、
継承より合成を進める記事もあるがUEでも継承せず、コンポーネントで組んでいくほうがいいのか?
設計次第
UE(Epic)ではコンポーネント指向を推しているっぽい…が、チュートリアルとかでは教えにくいので継承されている場合が多い。
UEの場合、BPでコンポーネントにしてもパフォーマンスが上がるか?と言われるとそうでもない。
コンポーネントが増えれば増えるほどロードも重くなるし、規模がある程度大きくないとメリットも少ない。
BPはActor単位でしか同時に触れないため、担当者分割のために分ける意義はあり。
大体人型、とか大体敵、ぐらいでよくて継承を挟みすぎるのも…?
GamePlay Ability System(GAS)でふるまいをわけることも可能。
複数で参照しているオブジェクトで、特定のActorを取得したいとき
AI TaskやGAS、AnimNotifyなどからCharactorを取得したいときなど、
・Cast(Blueprint)
・Cast(C++の基底クラス)
・コンポーネント
・Interface
などがあるがどれが良いのか。
Castでよい。依存関係を気にするならInterface。
UobjectへのCastはBPでもC++でも変わらない?
ちょっとBPのほうがコストが高いが気にするほどではない。毎Tick呼ぶとかでなければ気にしなくてよい
(BPはC++より確認の手順が多い?)
C++を使う場合、Interface、基底クラス、EnumなどはC++で定義しないとめんどくさい
BP側で作るとC++で利用できない。
構造体もUEEditorで作成した構造体AssetはC++には存在しないので頑張らないといけない。
C++が使える人はこの辺だけでもC++で書いたほうが安全かも?(ちょっと前も構造体があるとパッケージ化できないみたいなバグありましたね)
どこに書けばいいの?
構造体や列挙子はUEの場合クラスやネームスペースでなく構造体名.hやCharactorDefine.hみたいなのを作って書くのが通例?らしい
BPのコンポーネントを取得したい
コンポーネント階層の親から子のコンポーネントを全て取得したい場合は、"GetChildrelComponens"で取得することができる。
(余談)コンポーネントではなく、アタッチされたActorを取得する場合は"GetAttachedActors"ノードを利用する。
イベントディスパッチャーを使うときの方針
イベントディスパッチャーでどこがどれを参照しているかわからなくなりがち
運用方針などあるか?
方針という意味で言えば、UIのリストビューのような用途で言えば
親(ビュー)から子(要素)の場合→子を制限したいのでInterfaceで、子(要素)から親(ビュー)にMouseClickなどを通知する→イベントディスパッチャーを使い分ける。
なお、C++ではDelegateが同じような機能となる。
Delegateなら関数の引数として渡すことができるので、非同期処理等において簡潔にロジックを記述することが可能。
言い換えればBPの関数でDelegateを使いたくなった時に、その代わりとして使うのがイベントディスパッチャーとなる。(個人的な意見として「BPの引数にイベント型が渡せれば処理がスマートになるのに」と常々思っている)
そうでなければインターフェースで用途は満たせるはず。
Delegate参考記事
大学生の子がSNSで「今月生活費やばいよ~」とつぶやいてるのを見て、親が仕送りを勝手に送ってくれる(自分のイベントを発火しただけで親が実行してくれる)
という例えがありました(?)
widget上に反映する必要のある数値などはどこに書くべきか、どういう経路で反映するべきか
PlayerControllerで反映を行う。
Add to ViewportやAdd to ScreenもPlayerControllerでやったほうが良い。
PlayerControllerはレベルを移動するまでなくならないため
マルチ対応のためにもそのほうが良い
敵などは別(PlayerControllerに送られても困る)
ロックオンなどはPlayerControllerでよい
WidgetComponentを敵に持たせる
制限時間や敵の数などの流動的な数はGameStateに書く。→Server/Client上両方でとれるため。
Game StateはCastで参照すればよい。
※GameModeはホストしかアクセスできないので注意
基本的にネットワークに乗せれるよう設計を組むのが良い。
Enhanced Inputで一時的に違うMapping Contextを使用したい場合。
プライオリティで上からかぶせる。
UIなどでその時だけの設定を入れたい場合はUIを開いたときにAddして消したときにRemoveするなど。
Enhanced Inputを書く場所
EpicのではCharactorに書いていることがあるがどこに書くのがいいのか。
Charactorに書く。(Charactorによって操作方法が変わるなどがあるので)
BeginPlayでなくPossesed(ポーンにPlayerControllerが接続されたとき)に呼ばれるようにする。
PlayerControllerを変えることはよっぽどないので逆に書かないほうがいい。
プレイヤーが設定したキーコンフィグを保存するには
Player Mapping Input Configurationというものがある。
最近Enhanced Input User Settingsというセーブゲームを継承したシステムができた。(こんな記事ありました「【UE5.3】Enhanced Input User Settingsという新しい仕組み」)
Enhanced Player Input(プレイヤーごとに持っているマッピング設定)に対して変更があった時のイベントや追加のマッピングや削除をおこなうことができる。
ゲーム中にCharactorを変更する処理はどこに書く?
ケースによる。
Collisionに当たったときなどならそのコリジョンのActorに書いてもよいし、専用の管理Actorに書いてもよい。PlayerControllerに書いてもよい。
※専用のActorを作った場合、キーボードからの入力を直接受け取ることができない(Enterとかで検索すると出てくる赤いイベントノードで受け取ることができない)ので経由する必要がある。
ゲームパッドでクリックイベントを起こす
CommonUIでできる?[UE5] プラグイン「Common UI」:ボタンスタイルの制作工程
UINavigationプラグインを使う
Widgetのボタンが押されたとき(キーが押されたとき)、カテゴリアクセプトのキーが来たの判断をNavigation Action From KeyでそのKeyをNavigation Configからとっている?のでConfigを編集することで変えることができる?
アクセプトキーは入力方法?(入力に対してアクセプトキーが合致するものがあった場合、例えばプレスなどが発行される)
上で設定されている。入れ替えできない。
プラットフォームによってオーバーライドで変更可能?
MAPを直接Emplaceしてしまっている?
KeyActionRulesを書き換えるとできるかも?
LocalPlayer->GetSlateUser() で FSlateUser が取れる
何をGASで書くべきか?
GameplayAbilityという名前から「プレイヤーの能力」のように「技が使えるか」だけでしか利用できないように感じてしまうが、実際はもっと広域的な使い方ができる。
そうなると、GameplayAbilityって色々な所で使えそうなので、どんな風に使うのか迷子になってしまっている。
AbilitySystemComponentをどのクラスが持っているかによる。
例えば、PlayerControllerに付与したAbilitySystemComponentであれば、ワールドに入ってからいつでも使える機能の制御に使えるし、Charactorに付与したAbilitySystemComponentであればPossesしている間に使える機能の制御に使える。
例えばLyraではGameStateにAbilitySystemComponentがあり、ゲーム全体のルールを管理している。
Abilityという名前に左右されずに使ったほうがいい(剣が振れるとかに限らない)
Tagという単位で管理できるのでいろんなところで使える。
マルチプレイだとRep権限があるので注意。