障害物を自動で避ける仕組みを実装してみた
前回のあらすじ
MovementComponentを作り始めてみた - yamonメモ.cpp
MovementComponentの基礎部分は実装できたので、
続いて、歩いているアクターが進行方向にある障害物を見つけると
自動で左右に避ける仕組みを作ってみることにした。
アクターAから見たアクターBが右側にいるかどうかを判定する
まず、必要になる情報が、
・LineTraceで前方に伸ばしたレイでヒットした障害物の原点
・現在進行中のアクター自身の回転値
アクターAからアクターBへの回転値(Yaw)を計算し、
自分の回転値(Yaw)と比較して大きければ右方向、小さければ左方向。
ソースだとこんな感じ。
auto LineTraceComp = Actor->GetLineTraceComponent(); if (!LineTraceComp) { return; } FVector CurrentVel = Actor->GetVelocity(); if (CurrentVel.IsZero()) { // 動いていないアクターは対象外 return; } // LineTraceでHitしたアクター位置を取得 FVector HitActorLocation = FVector::ZeroVector; if (!LineTraceComp->GetNearestForwardHitActorLocation(&HitActorLocation)) { return; } const FRotator CurrentRot = Actor->GetCurrentRotation(); const FVector Dir = HitActorLocation - Actor->GetCurrentLocation(); const FRotator TargetRot = Dir.Rotation(); if (CurrentRot.Yaw > TargetRot.Yaw) { // 対象はアクターから見て右にいる } else { // 対象はアクターから見て左にいる }
現在の移動速度に計算した避け具合を反映させる
対象が右にいるなら左に、左にいるなら右に移動値を反映する。
単純に現在の速度に加算してみた
避ける瞬間に加速する見た目になってしまった。
(避けられた方イラっとするだろうな…)
単純な速度の加算だとそうなってしまうので、
現在の速度から再設定を行うようにしてみる。
アクターの回転値をとってきて、
少し回転させた状態で同じように速度を与えてみる。
if (CurrentRot.Yaw > TargetRot.Yaw) { // 対象はアクターから見て右にいる CurrentRot.Yaw += AvoidAddYaw; } else { // 対象はアクターから見て左にいる CurrentRot.Yaw -= AvoidAddYaw; } const FVector NewVel = CurrentRot.Quaternion().GetAxisY(); Actor->SetVelocity(NewVel * Speed);
これでうまくいく避けてくれる感じを出すことができた。
向かい合わせてもそれっぽく避けてくれる。
気になる点
同じ速度のアクターを縦に連ねて配置し、後ろを追従させた場合、
追い抜けないのに横にずれてしまう。
当たりそうな対象の速度も見て追い抜けそうなら横にずれ、
追い抜けなさそうならそのままを維持するようにしてみたい。
前が詰まっている時(どこに避けてもぶつかってしまう場合)は
「止まる」を選択肢に入れる実装もしてみたい。
また今度気になったらやってみよう。
雑談
先日
「UE4製TPSアクション EDF: IR事例解説セミナー in 大阪」
に行ってきました。
感想
ABPの設計って本当に難しい!
変に共通化しようとしても身動きとり辛いし…
コントローラー入力からモーションのブレンドに繋げる発想
凄い柔軟だしTPSにマッチしてて感動した。
Entryから空State(Entry)に繋くとTポーズの補間がかかってどうしようって問題。
自分も経験したことあるけど、
結局ゴリ押ししたような気がする(EntryにIdleのモーションを入れておくだけ)w
99秒の補間は盲点だった。
SubAnimInstanceって相当便利そうだな。
あまり個人だと使う機会少ないかもしれないけど。
感想終わり!楽しかった!
次は移動関連とはまた違うことがやりたいな。
・Statの表示を試してみる。
・フラスタムカリングを実装してみる。
・マーケットプレイスからアセットを取り込んでみる。
・ポーズ機能を実装してみる
どれかをやります!