FMassMoveTargetFragment::CreateNewAction 内で PreviousAction が更新されず、MassEntityの歩き始め回避フェード等の挙動が機能しない

お世話になっております。

MassEntityシステムを利用した群衆の実装において、

エージェントが「待機(Stand)」から「移動(Move)」へ遷移し歩き始める際、

回避を一時的に弱めるための機能であるAvoidanceトレイト内のパラメータ「StartOfPathDuration」の効果が発動せず、

エンジン側のコードを確認したところ不具合の可能性があると思われる箇所を発見しました。

【確認した問題点】

FMassMoveTargetFragment::CreateNewAction において、CurrentAction の更新は行われていますが、PreviousAction を更新する処理が記述されていません。

そのため、GetPreviousAction() が常に初期値(EMassMovementAction::Move)を返し続ける状態になっているように思われます。

【挙動への影響】

これにより、UMassMovingAvoidanceProcessorにおいて設計意図と異なる挙動が発生しているのではないかと考えています。

・移動開始時のフェード処理判定が常にFalseとなる

・if(MoveTarget.GetPreviousAction() != EMassMovementAction::Move)

・StartOfPathDuration や StartOfPathAvoidanceScale などのパラメータが無視され、密集からの歩き出し時に回避力が即座に適用される

・発振(左右にプルプル震える)や一時的に反転して後退するなどの見た目が発生する

この他にも、UMassSteerToMoveTargetProcessorにも何かしらの影響が出ているものと思われます。

【質問事項】

・上記の認識は概ね正しそうでしょうか? また、もし不具合でしたら修正の予定はありますでしょうか?

・ソースコードを直接修正する場合、CreateNewAction 内で CurrentAction を上書きする前に PreviousAction = CurrentAction; を追加する対応で問題ありませんでしょうか? また他への副作用は予想されますでしょうか?

ご確認よろしくお願いいたします。

[Attachment Removed]

お世話になっております。

質問1:上記の認識は概ね正しそうでしょうか? また、もし不具合でしたら修正の予定はありますでしょうか?

認識は概ね正しいです。FMassMoveTargetFragment::CreateNewAction は CurrentAction の更新のみで、PreviousAction を書き換えていません。PreviousAction は初期値 EMassMovementAction::Move のまま、コードベース内に他の代入箇所もなく、GetPreviousAction() は常に Move を返します。CreateReplicatedAction でも同様です。そのため UMassMovingAvoidanceProcessor 内の

if (MoveTarget.GetPreviousAction() != EMassMovementAction::Move)は常にfalseとなり、NearStartFade が初期値 1.0 のままです。結果として StartOfPathDuration/StartOfPathAvoidanceScale は実質効かず、待機から移動への遷移時に回避が即座にフル適用されます。修正予定については、当方で把握している公開ブランチにはこの修正は入っておらず、不具合として起票する予定です。

質問2:ソースコードを直接修正する場合、CreateNewAction 内で CurrentAction を上書きする前に PreviousAction = CurrentAction; を追加する対応で問題ありませんでしょうか? また他への副作用は予想されますでしょうか?

ご提案の修正は技術的に妥当です。以下のような変更になることかと思います。

void FMassMoveTargetFragment::CreateNewAction(const EMassMovementAction InAction, const UWorld& InWorld)
{
    // ...
    PreviousAction = CurrentAction;  // 追加
    CurrentAction = InAction;
    // ...
}

副作用・留意点に関して、以下の点をご留意頂けますと幸いです。

・他参照箇所への波及

GetPreviousAction() を使っているのは回避処理のほか、UMassSteerToMoveTargetProcessor(bEnteredFromMoveAction)です。修正後は「Move以外からStandに入った」場合の停止時ステアリングが意図どおり変わるため、歩き出しだけでなく停止時の見た目も併せてご検証頂くことをおすすめします。

・ネットワーク

PreviousAction はレプリケートされておらず、CreateReplicatedAction でも更新されません。サーバ側だけ直すとクライアント側では PreviousAction が Move のままになり得ます。クライアントでも同じ挙動が必要なら、CreateReplicatedAction にも同等の更新を入れる(または PreviousAction をレプリケーション対象にする)検討が必要です。

・初期状態

生成直後の最初の CreateNewAction では PreviousAction に初期値 Move が入るため、スポーン直後からいきなり Move を始める場合は従来どおりフェードが掛かりません。スポーン直後に密集から歩き出す構成では、その点を認識したうえでご検証を進めて頂けますと幸いです。

[Attachment Removed]

ご回答ありがとうございます。

そのように対応いたします。

[Attachment Removed]

ご確認頂きありがとうございます。

本件は https://issues.unrealengine.com/issue/UE\-388548 として登録させて頂きました。修正および更新は本件をご確認いただけますと幸いです。

[Attachment Removed]