今回はAnimator ControllerのState(状態)の項目にあるSpeed、Mirror、Foot IK項目を見てみたいと思います。
Speedはこの状態でのアニメーションクリップの再生速度でスクリプトから変更するにはAnimatorControllerからAnimatorStateを取得し変更します。
Mirror項目はチェックを入れるとアニメーションが反対になります。
Foot IKは足のIKを有効にします。
MirrorとFoot IKはAnimation TypeがHumanoidに設定されている場合だけ有効になります。
その他の項目についてはよくわからなかったので説明は除外させて頂きます・・・・(^_^;)
Foot IK
さてFoot IK項目ですがこれは文字を見る限り足のIKを有効にするということみたいです。
IKはInverse Kinematicsの略で手や足の位置や角度に応じて腕や太もも等が連動して動く機能ですね。
IKに関しては
等を参照してください。
AnimatorStateのFoot IKは足にIKを働かせる為の項目のようです。
例えばStandardAssetsに入っているキャラクターEthanに使われているIdleというアニメーションは足を微妙に横にずらしています。
AnimatorControllerを作りIdleという状態を作ってこのアニメーションクリップを設定してみると、
↑のように足元が左右に揺れているのがわかります。
AnimatorControllerのIdleのFoot IKのチェックを入れると
↑のように足元がIKで固定され動かなくなります。
スクリプトからStateの設定を変更する
ゲーム中に個々の状態でのアニメーションの再生速度やミラーの設定等を変更したい事もあると思いますので、スクリプトから操作してみましょう。
キャラクターには移動スクリプトとAnimatorControllerの設定をしておきます。
AnimatorControllerの設定
AnimatorControllerの遷移は
↑のような遷移を作っておきます。
アニメーションパラメータにFloat型のSpeed、Trigger型のJumpを作成します。
Idle→WalkはSpeedが0.1より上
Walk→IdleはSpeedが0.1より下
Idle→JumpはJump
Walk→JumpはJump
Jump→Idleは条件はなしです。
Jump→IdleだけHas Exit Timeにチェックを入れ、その他はチェックを外しておきます。
キャラ移動とAnimatorStateの項目を操作するスクリプト
次に移動とジャンプが出来るキャラクターにAnimatorStateの項目を操作するスクリプトを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | using System.Collections; using UnityEditor.Animations; public class AnimationStateChara : MonoBehaviour { private Animator animator; private CharacterController cCon; private float x; private float y; private Vector3 velocity; public float walkSpeed; public float jumpPower; // Walk状態を入れるフィールド private AnimatorState state; void Start () { animator = GetComponent<Animator>(); cCon = GetComponent<CharacterController>(); velocity = Vector3.zero; // 今使っているAnimatorControllerを取得 AnimatorController animCon = animator.runtimeAnimatorController as AnimatorController; // AnimatorControllerのレイヤーを取得 var layers = animCon.layers; foreach (var layer in layers) { // Base Layerレイヤーを探す if (layer.stateMachine.name == "Base Layer") { var animStates = layer.stateMachine.states; foreach (var animState in animStates) { // Walk状態を探して状態を保持 if (animState.state.name == "Walk") { state = animState.state; break; } } } } } void Update () { // マウスの左クリックをしたらWalk状態のSpeedを変更する if (Input.GetMouseButtonDown (0)) { state.speed = (state.speed == 1f) ? 2f : 1f; // アニメーションプロパティとAnimatorメッシュデータのリバインド animator.Rebind (); // マウスの右クリックで足のIKのオン・オフをする } else if (Input.GetMouseButtonDown (1)) { state.iKOnFeet = !state.iKOnFeet; animator.Rebind (); // マウスのスクロールボタンクリックでミラーのオン・オフをする } else if (Input.GetMouseButtonDown (2)) { state.mirror = !state.mirror; animator.Rebind (); } // キャラクターコライダが接地、またはレイが地面に到達している場合 if(cCon.isGrounded) { // 地面に接地してる時は初期化 velocity = Vector3.zero; x = Input.GetAxis("Horizontal"); y = Input.GetAxis("Vertical"); var input = new Vector3(x, 0, y); // 方向キーが多少押されている if(input.magnitude > 0.1f && !animator.GetCurrentAnimatorStateInfo(0).IsName("Attack1") && !animator.GetCurrentAnimatorStateInfo(0).IsName("Attack2") && !animator.GetCurrentAnimatorStateInfo(0).IsName("Attack3") ) { animator.SetFloat("Speed", walkSpeed); transform.LookAt(transform.position + input); velocity += input.normalized * 1.5f; // キーの押しが小さすぎる場合は移動しない } else { animator.SetFloat ("Speed", 0f); } // ジャンプ if(Input.GetButtonDown("Jump") && !animator.GetCurrentAnimatorStateInfo(0).IsName("Jump") && !animator.GetCurrentAnimatorStateInfo(0).IsName("Attack1") && !animator.GetCurrentAnimatorStateInfo(0).IsName("Attack2") && !animator.GetCurrentAnimatorStateInfo(0).IsName("Attack3") && !animator.IsInTransition(0) // 遷移途中にジャンプさせない条件 ) { animator.SetBool("Jump", true); velocity.y += jumpPower; } } velocity.y += Physics.gravity.y * Time.deltaTime; cCon.Move(velocity * Time.deltaTime); } } |
キャラクターの移動スクリプトに関しては
ジャンプに関しては
を参照してください。
AnimatorStateの部分を見てみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // 今使っているAnimatorControllerを取得 AnimatorController animCon = animator.runtimeAnimatorController as AnimatorController; // AnimatorControllerのレイヤーを取得 var layers = animCon.layers; foreach (var layer in layers) { // Base Layerレイヤーを探す if (layer.stateMachine.name == "Base Layer") { var animStates = layer.stateMachine.states; foreach (var animState in animStates) { // Walk状態を探して状態を保持 if (animState.state.name == "Walk") { state = animState.state; break; } } } } |
Startメソッドでanimator.runtimeAnimatorControllerをキャストしAnimatorControllerを取得します。
取得したAnimatorControllerのレイヤーを取得し、そのレイヤー群からBase Layerという名前のレイヤーを探します。
レイヤーが見つかったらその中のWalkという状態を探しstateフィールドに保持しておきます。
保持したAnimatorStateを使って項目を操作します。
項目を操作しているのがUpdateメソッドの中で
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // マウスの左クリックをしたらWalk状態のSpeedを変更する if (Input.GetMouseButtonDown (0)) { state.speed = (state.speed == 1f) ? 2f : 1f; // アニメーションプロパティとAnimatorメッシュデータのリバインド animator.Rebind (); // マウスの右クリックで足のIKのオン・オフをする } else if (Input.GetMouseButtonDown (1)) { state.iKOnFeet = !state.iKOnFeet; animator.Rebind (); // マウスのスクロールボタンクリックでミラーのオン・オフをする } else if (Input.GetMouseButtonDown (2)) { state.mirror = !state.mirror; animator.Rebind (); } |
マウスの対応するボタンを押した時に保持しているAnimatorStateの項目を操作しています。
左クリックした時はstate.speedが1fの時は2fにそれ以外の時は1fに設定しています。
見慣れない構文だと思った方もいるかもしれませんが、
(条件式) ? 条件式がtrueの時に返す値 : 条件式がfalseの時に返す値
という風になっているのでstate.speedが1fだった時は2fが返ってきてそれをstate.speedに代入しています。
普通のif文を使って書き換えても問題はありません・・・・(._.)
マウスの右クリック、スクロールボタンのクリックではFoot IK、Mirror項目のオン・オフをしています。
それぞれのAnimatorStateを変更するとAnimatorの状態をリバインドする必要があるので、
animator.Rebind();
を呼び出しています。
これでスクリプトが出来たので実行して確認してみましょう。
↑のようになりました。
正直なところWalk状態のFoot IKをオンにしたり、Mirrorにチェックを入れても解り辛いですね・・・(^_^;)
Foot IKはIdle、MirrorはJumpで確認した方がよかったですが、各自お願い致します。(._.)