Skyrimにはラグドール(Ragdoll)という状態みたいなものがあって、これの扱いを間違えるとActorの挙動がおかしくなってしまいます。こちらのページでも触れられているのですが、ラグドール中は他のアニメーションを再生させるべきではないようです。
遭遇したActorのおかしな挙動の数々
- Actorが空中を平泳ぎする(上半身は別のことをしようとしてるが下半身が平泳ぎの体勢で明らかにおかしい)
- 上半身が起き上がろうとしているが下半身が平泳ぎの体勢でもがきながら起きる(上記と同じ?)
- 死んだはずのActorが起き上がり、その場でずっと駆け足をする
- 死んでいるActorが気を付けの姿勢でピーンとなっている(この状態ではActorをアクティベートできない)
なおしかた
挙動がおかしくなったActorはPushActorAwayでなおります。死んでいるActorはResurrectからのKillでなおります。
推測ですが、ラグドール中というのは何かのアニメーションの再生中ということであり、アニメーションは基本的にシナリオがあって(hkxファイルにて定義されている)、最初から最後まで完走することが前提なので、途中で中断されると各種フラグなどが中途半端な状態のままになってしまうので、色々と不具合が起こるということなのではないのかなと思います。
PushActorAwayでなおるというのも、吹き飛ばしからの起き上がりアニメーションを再生させることで、各種フラグが後始末されて正常な状態に復帰するからなのでしょう。
おかしくしないためには
自作の不死化ModでActorを死なせたい場合の処理では、ラグドール中かどうかを調べて、ラグドール中だったら終わるまで待つということをしていました。Papyrusで待つという処理自体が効率が悪いのと、主にキルムーブなどの後は起き上がるまでラグドール状態が維持されるので、これから死ぬために起き上がるという動作が違和感があって困っていました。
最近というかいまさらですが、ForceAddRagdollToWorld、ForceRemoveRagdollFromWorldいう関数を発見しました。これで実験してみたのですが、確かにForceRemoveRagdollFromWorldを実行すると空中にいようが吹っ飛んでいようが、その場で固まって動かなくなります。ForceAddRagdollToWorldで再び動き出します。
そこで、以下のコードで処理してみました。
Actorを死なせる、ラグドール対策あり (papyrus)
Function MyKill(Actor akTarget)
akTarget.ForceRemoveRagdollFromWorld()
akTarget.ForceAddRagdollToWorld()
akTarget.EndDeferredKill()
akTarget.Kill()
EndFunction
内部的にラグドール状態の初期化が行われることを期待してのことです。いまのところ不具合が出なくなりました。
ForceRemoveRagdollFromWorldでラグドール状態から抜けさせます。このままだと固まったままです。ForceAddRagdollToWorldで再びラグドール状態にします。これで死体が重力によって地面に倒れます。
うまくいったのか
その場で駆け足はいまのところありません。たまたまかもしれませんので、検証は続けていきます。
死ぬときにたまに派手に吹っ飛んでいきます。加速度的なものが初期化されないのでしょう。余談ですが、巨人に倒されるとおかしいくらいに吹っ飛んでいきますが、ギャグでそうなっている訳ではなく、もしかするとベセスダですら変更が難しくてそのままにされた仕様なのかもしれません。
死後硬直のようなものは依然として発生しました。発生条件が不明です。死んだその場で硬直する場合と、ロードを挟むと硬直する場合、ロードを挟むと元に戻る場合がありました。
どうやら死んでいるときのActorはラグドール中になっているのが普通で、それによって掴んで引っ張ったりできるみたいです。死体にForceRemoveRagdollFromWorldを実行すると硬直状態を再現できました。ForceAddRagdollToWorldで硬直がとけました。ラグドール中はGetMassが正の値を返すのですが、これは死体であっても同じようです。よって死体がGetMassで0を返すときはラグドール状態が解除されたおかしい状態ということになるので、ForceAddRagdollToWorldを実行してラグドール状態にしてあげるとよさそうです。
ロードを挟むと硬直する死体は、GetMassが正の値を返し、ラグドール中のようだけど何かがおかしい状態でした。ラグドール中のアニメーションバグが発生したまま死んだActorがロードを挟むとこうなるようです。なんと、この状態でForceAddRagdollToWorldを実行すると、硬直がとけてアクティベート出来るようになりました。
死体を動かす
死体をMoveToで動かしたいときに、そのままでは移動してくれないので、いままではDisableで一時的に無効にして動かしてからEnableで有効にしていました。Disable/Enableは副作用がいくつかあり、特に所持品が初期化されてしまうのが問題でした。
死体が動かないのはどうやらラグドール状態だからのようです。Disable/EnableのかわりにForceRemoveRagdollFromWorld/ForceAddRagdollToWorldを使うと副作用なしに動かせました。