UnityのIKを使ってキャラクターがはしごを登るアニメーションを作る

今回はUnityのIKを使ってアニメーションをスクリプトから操作してみようと思います。

今まではアニメーションクリップを作成し、アニメーターによってアニメーションの遷移を行っていました。

しかし、キャラクターが物を持とうとした時に物のオブジェクトとアニメーションの手の位置がうまく合ってくれなかったりします。

しかしIKを使えば手の位置を物の位置や角度に合わせて調整するという事が出来るようになります。

今回はその機能を使ってキャラクターがはしごを登るようにしてみます。

スポンサーリンク

キャラクターが昇るはしごの設定

はしご1

上のようにはしごを設置し、RightHand、LeftHand、RightFoot、LeftFoot、StartArea、StandPosition、EndArea、WarpPositionを作成します。

HandとFootと名のついたものはここに手と足がくる位置になります。ここを移動させて手と足の位置を動かしていきます。

StartAreaは、はしごに登るのを開始する検知エリアです。EndAreaははしごを登りきったのを検知するエリアです。
StandPositionははしごに登るのを開始するキャラクターの位置を指定するものです。
WarpPositionははしごを登りきった時にキャラクターを移動する場所です。登りきった後に地面がある所に移動させないと重力で落下してしまう為に用意してあります。

はしご2

はしごは上の画像のようなものを用意しました。これから作成するスクリプトははしごの大きさによってパラメータを変更する必要があります。しかもかなり細かく・・・(^_^;)

ただ一度作ってしまえばそのはしごをプレハブ化して使い回しがききますので、安心してください(はいてますよ)。

まずはStartAreaの検知エリアを作っていきます。BoxColliderを追加してください。

はしご3

上のように小さいエリアにしておきます。
なぜなら敵に追われている時に誤ってエリア内に入ってはしごを登らせない為です。

キャラクターを検知したらはしごを登る準備をするスクリプトStairs

StartAreaにStairsという新しいスクリプトを作成します。

publicで右手や左手等の位置を設定出来るようにし、Start関数内で初期値を保存しておきます。
ここで保存しておかないと、一度はしごを使ってrighHandやleftHandを移動してしまうと、2度目にはしごを登ろうとした時にrightHandやleftHandが移動した位置から開始してしまう為です。

move.GetStairs関数はMoveスクリプト内で記述する関数で、はしごを昇っているかどうかを取得します。
昇っている状態であればResetStairs関数を呼び出して、状態をリセットします。
これらの関数は後で作成します。

階段を昇っていない状態であれば右手の位置等を置く場所をリセットし、はしごを昇る準備をします。
SetStairs関数に渡す引数は右手の位置などの情報です。

キャラクター操作スクリプトMoveに関数を追加

次はキャラクター操作スクリプトMoveに処理を追加します。
まずは設定関数を見ていきます。

これらは状態を変更したり、設定をしている処理です。

basePositionははしごをゲーム上のどこに設定してもパラメータによって値を変更する必要がないように初期のy座標の位置を記憶しています。

キャラクターの手足のIKを設定する処理を追加

ではここからがメインの処理になります。

まずははしごを昇る状態になった時(stateがState.stairs)に関数OnAnimatorIK内で右手、左手、右足、左足のIKのウエイトを1にする必要があります。
IKのウエイトが1になると位置を指定すればアニメーション本体とは関係なくそこに右手や左手がそこに移動するようになります。

また位置だけでなく角度も変更が出来ますので、まずはその処理を記述します。
OnAnimatorIK内に以下の記述を足します。
OnAnimatorIK関数がない場合は足すのと、アニメーターコントローラのレイヤーでIK Passのチェックを入れる必要があります。

最初にそれぞれのIKの位置と角度のウエイトを1に設定します。weightは1として宣言しています。
ウエイトを変更したらそれぞれのIKの位置と角度をrightHandObj等の位置と角度に設定します。

すると例えばキャラクターの右手がrightHandオブジェクトのある位置に移動します。
rightHandObj等はStairsスクリプト内で渡したオブジェクトの位置がSetStairsで指定してあります。

これでStartAreaの範囲内に入ったらrighHandやleftHandの位置に右手や左手が置かれるようになります。

なんとなくはしごを昇らせるやり方がわかりましたか?
あまり綺麗な動きにはなりませんのであしからず・・・・

キャラクターがはしごを昇っていく処理の追加

では次にキャラクターがはしごを昇っていく処理を作成します。

Moveスクリプト内の状態で処理を分岐している個所に以下のスクリプトを記述します。
他の状態に移行してしまう個所がある場合ははしごを昇っている時は作用しないような条件を加えるようにしてください。

キーの↑↓を押した時に垂直方向の動きに設定します。

現在のキャラクターの位置(Y座標)からbasePositionの位置を引いた値が一定の範囲に来た時に右手、左手、右足、左足用のオブジェクトの位置を移動させます。

このパラメータはかなり細かくみていく必要があります。
実行しながらキャラクターのY座標の位置と手や足の位置があっているか見ながら修正してください。

手や足がありえない方向に曲がっている場合はrighHandやleftHandの角度が反対方向を向いている可能性があるので、
Y座標の角度を変更してください。

最後に実際にキャラクターを移動させている個所を修正します(キャラクター操作スクリプトMoveスクリプト内)。
はしごを昇っている時は重力値等は加味したくない為、状態によって分岐させます。

これではしごを昇っている状態の時だけ↑↓のキーだけに反応して動くキャラクターになります。

はしご4

上のようになりました。

細かく調整はしていないので近くで見るとはしごに手足が食い込んでいる可能性もあります。(^_^;)

はしごを昇りきった判定はEndAreaで行っていますが、検知した場合にWarpPositionの位置に移動させて状態をはしごを昇っている状態からwait状態に遷移させるだけです。

手足の移動をなめらかにする処理

-- 以降追記 --

はしごを登る時に一定の範囲に来たらすぐに目的の位置へ手や足を移動させていますが、
目的の位置までなだらかにアニメーションしたい方もいると思います。
その為の処理を追加します。

変数に

public var stairSmoothFlag : boolean;
public var stairSmoothValue : float;

を追加します。
stairSmoothFlagはスムースな処理を行うかどうか
stairSmoothValueはスムースの度合い
になります。

スムーズの度合いを小さくしすぎると、目的の位置に少しづつ手や足を動かしている間に次の目的地を再設定してしまう為に、足がずっと伸びた状態ではしごを登っているように見えてしまいます。

なだらかな処理をさせる場合は、はしごを登る時Y座標の移動量を減らすかスムースにする度合いを大きくする必要があります。

またrightHandBaseとleftHandBaseはfloat型で宣言し使用していましたが、これをVector3型に変更し手や足の位置のX、Y、Zの位置を記憶させるようにします。

上のように初期値を設定します。

階段を登る時の手や足の位置を設定する処理を変更します。

すごい長い処理ですね・・・(^_^;)
キャラクターが一定のY座標の値にきたら手足の位置を設定しているだけなので難しく感じる必要はありません。
一度作ったらもう見たくない処理ではありますけどね・・・。

Mathf.Lerp(現在の位置, 目的の位置, 度合い);

を使って現在値を少しづつ目的の位置に近づけていった値を現在値に設定します。
度合いは0~1の間で設定されるので、Time.deltaTimeを指定すると1秒後に目的の位置になります。
Time.deltaTimeにstairSmoothValueをかける事で移動スピードを上げる事が出来ます。

今回の追加に伴い、手や足の目的地の設定を細かくしたり、EndAreaの位置を変更しました。

処理が完成したので、インスペクタでstairSmoothFlagのチェックを入れ、stairSmoothValueに値(今回は8を設定)を設定してください。

Unityの実行ボタンを押して確認してみましょう。

はしご5

一気に駆け上がろうとすると目的地に手や足が来る前に次の目的地が設定されてしまう為動きがぎこちない感じになってます。

Y座標の移動値を少なくしたり、stairSmoothValueの値を大きくするとぎこちなさは取れます。
もっといい方法はないもんですかねぇ・・・・

スムースにやらない方がよく見えるような気もします・・・・(^_^;)