この記事は Unreal Engine (UE) Advent Calendar 2022 の 3 日目の記事です
Character クラスは人型キャラクター用の汎用クラスです
…が、とりあえず動かすのにこれ以上の楽な実装はそうありません
なので人型以外(四足歩行など)で Character クラスを使うときの悩みを解消します
とりあえず、ThirdPersonTemplate の BP_ThirdPersonCharacter
の Mesh を四足歩行の動物にしてみましょう
シカとかどうですかね?
まあこうなります
これをそのまま動かそうとすると、当然こういう悲劇が起こります
流石にこれは…だめですね
これの対策、正攻法で行くなら以下の 2 択になります
- SkeletalMesh を少し後ろに下げて、頭と前足を Capsule に入れるようにする
- Capsule 自体を大きくして、全身が Capsule に入るようにする
前者が一番マトモな方法ですね
ただし尻がはみ出すことは許容しなければなりません
後者もありなのですが、今度は幅が広くなりすぎていい感じにならない…
そこで、AutoWeld の仕組みを使った裏技で、Collsion を追加する方法を提案します
AutoWeld を使った Collision の合成 #
まずは SkeletalMesh をカバーできるように、Collsion を追加してください
追加する際は、Capsule の直下にします
SkeletalMesh の下ではありません
今回はこんな感じにします
もうちょい丁寧な方法は各自でどうぞ…
そして、BeginPlay で、一瞬だけ Capsule の SimulatePhysics を ON にします
Delay Until Next Tick
はなくても動きますがまあ念のため
これらの実装をすることで、追加した Collsion が合成され、Collsion をカバーすることができるようになります
どうしてこういう事が起こるのか #
UnrealEngine では、ひとかたまりの Object(RigidBody)は、ひとかたまりで動くように物理シミュレーション空間内に登録する仕組みがあります
これを AutoWeld といいます
Weld…溶接です
この AutoWeld が動作する条件が、物理シミュレーションを ON にしたとき、というわけです
そして AutoWeld は、物理シミュレーションが ON になった Component(PrimitiveComponent)の子供の Collision を再帰的に検索し、まとめて 1 つになるように合成します
Capsule の直下に合成したい Collision を配置した理由がこれです
SkeletalMesh やその子 Component が AutoWeld されない理由について #
SkeletalMesh は PrimitiveComponent ではあるのですが、SkeletalMesh の Collision(PhysicsAsset)は AutoWeld の対象になりません
SkeletalMesh の Collision は、その構造が理由で、PrimitiveComponent の RigidBody の扱いではないからです
SkeletalMesh の Collision、いわゆる Ragdoll は、RigidBody を Constraint で繋ぐ構造になっています
このあたりは PhysicsAsset を見てもらえばわかるかと思います
その構造が、PrimitiveComponent が持つ RigidBody の構造に収まらないため、SkeletalMesh は RigidBody を独自の変数で管理しています
PrimitiveComponent が用意している RigidBody の変数には入りません
なので、処理上 RigidBody はないとみなされ、AutoWeld が起きなくなります
そもそも、Weld してしまうと、物理シミュレーション上で自由に動かせなくなってしまうので、Weld しないようになっている、という理由もあります
SkeletalMeshComponent の子 Component が AutoWeld されない理由は、SkeletalMesh の時点で AutoWeld の再帰処理が途切れてしまうので、それ以下の Collsion は処理が行われないためです
これは SkeletalMesh 以外にも、Collision を持たない SceneComponent を挟んだときにも起こるので、注意しましょう
Weld 周りの処理は C++が読めればわりと簡単に理解できるので、興味がある人は追ってみると良いでしょう
追加:Animation に合わせて動かす #
AutoWeld で合成しましたが、Component としては独立しているので、実はここから Animation(Bone)に合わせて動かすことができます
GetSocketLocation 等で、参照したい Bone の位置を取得し、その位置に Collision を動かせば、Collision の位置を変更できます
これなら複雑に変形するロボット等にも対応できますね