シンプルなアクションゲームを作ってみようの第19回です。
今回はプレイヤーキャラクターにジャンプ機能を付けたいと思います。
前回は大砲を作成し、弾を定期的に発射する機能を作成してプレハブにしました。
シンプルなアクションゲームを作ってみようの他の記事は
シンプルなアクションゲームを作るのを通してUnityの使い方を学ぶカテゴリです。
から参照出来ます。
PlayerControllerスクリプトにジャンプ処理を追加する
PlayerControllerスクリプトにジャンプする処理を追加していきます。
フィールドの移動の速さの下あたりにジャンプ力を表すjumpPowerを宣言します。
1 2 3 4 5 | // ジャンプ力 [SerializeField] private float jumpPower = 6f; |
次にUpdateメソッドのMoveメソッドを呼んだ後にJumpメソッドを呼び出す処理を追加します。
Jumpメソッドはこの後作ります。
1 2 3 4 | // ジャンプ処理 Jump(); |
Jumpメソッドを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 | // ジャンプ処理 private void Jump() { // 接地している場合 if (isGrounded) { // ジャンプ処理 if (Input.GetButtonDown("Jump")) { isGrounded = false; rigidBody.velocity = new Vector3(rigidBody.velocity.x, jumpPower, rigidBody.velocity.z); } } } |
ジャンプ出来るのは接地している時なのでisGroundedがtrueかどうかを確認し、Input.GetButtonDown(“Jump”)でJumpのボタンが押されているか判断し、押されていればisGroundedにfalseを入れ、RigidbodyのvelocityにjumpPowerを反映して設定しています。
Input.GetButtonDownは引数で指定された名前のボタンが押された時にtrueが返されます、JumpはInputManagerの設定でデフォルトでSpaceキーが割り当てられている為、Spaceキーを押すとジャンプするようになります。
Rigidbodyのvelocityは直接操作をするのはあまりよくないと以前の記事で書きましたが、ジャンプに関しては一つの例外に当たります。
Vector3のXとZはそのままrigidBodyのvelocityのxとzを指定し、YにはjumpPowerを指定します。
rigidBodyのvelocityを操作しなくても自分で作ったvelocityフィールドのyにジャンプ力を入れて操作することでも同じような感じに作れますが、少し面倒な処理を入れる必要があるためやめました。
これでスペースキーを押すとプレイヤーがジャンプするようになりました。
またジャンプ中でも移動キーを押してそちらの方向に移動出来ます。
ジャンプ中には移動出来ないようにしたい場合はMoveメソッドで移動入力値の計算を接地している時だけ計算するようにするといいと思います。
現時点でジャンプするとIsGroundedがtrueのままになっているのでジャンプ中にもう一回ボタンを押すと2段階目のジャンプが出来ます。
これは意図して2段階ジャンプを出来るようにしたわけではないんですが・・・(^_^;)
これはジャンプしてすぐ後にCheckGroundメソッドで接地しているかどうか確認してしまってすぐにIsGroundedがtrueになってしまうのが原因だと思われます。
これに関しては後で条件を加える事で2段階目のジャンプを出来ないようにします。
その上で意図して2段階目のジャンプも出来るようにします。
Playerアニメーターコントローラーに状態と遷移を追加する
プレイヤーをジャンプさせてもRigidbodyのY方向の速度を変更しただけなのでアニメーションは前のアニメーションのままジャンプをしています。
そこでジャンプ中はジャンプアニメーションを再生するようにします。
ヒエラルキーでPlayerゲームオブジェクトを選択し、Animatorウインドウを開きます。
アニメーションパラメータ―を3つ作成します。
Trigger型のJump
Float型のJumpPower
Bool型のIsGrounded
を作成しました。
Jumpはジャンプした時にジャンプ状態に遷移する条件として使います。
JumpPowerはジャンプの過程(飛び上がり、宙に浮き、落下する)の変化をさせる為の条件に使います。
IsGroundedは着地アニメーションを再生する時の条件として使います。
次にAnimatorウインドウの右の状態が表示されている部分で右クリックしCreate State→From New Blend Treeを選択し、新しいブレンドツリーを作成し、インスペクタで名前をJumpに変更します。
ブレンドツリーはその状態でアニメーションパラメーターの値によってアニメーションのブレンドを変化させる時に便利です。
JumpをダブルクリックしてJumpブレンドツリーを開きます。
ブレンドツリーを選択します。
インスペクタで名前をJumpBlendTreeと変更し、ParameterはJumpPowerに変更してJumpPowerアニメーションパラメータの値によってアニメーションブレンドをすることにします。
また、Motionの+ボタンを押し、Add Motion Fieldを選択を3かい繰り返し3つのモーションを設定出来るようにします。
最初のMotionにはHumanoidFallを設定します。
次のMotionにはHumanoidMidAirを設定します。
最後のMotionにはHumanoidJumpUpを設定します。
次にAutomate Thresholdsのチェックを外し、Threshold(しきい値)を自分で設定出来るようにします。
HumanoidFallのThresholdは-6
HumanoidMidAirのThresholdは0
HumanoidJumpUpのThresholdは6
と設定します。
ParameterでJumpPowerを指定しているので、この値が-6の時は完全にHumanoidFall、0の時はHumanoidMidAir、6の時はHumanoidJumpUpのアニメーションになり、その間はアニメーションがブレンドされます。
フィールドのjumpPowerを6とした場合は以下のような感じでアニメーションがブレンドされます。
HumanoidMidAirのアニメーションクリップはジャンプアニメーション時に基点がOriginalになっていて、地面から離れて見えるようになっています。
このままでもいいんですが他のジャンプアニメーションクリップと同様にアニメーション自体は足元が地面にあるようにします(Apply Root Motionにチェックを入れてる場合はしない)。
Assets/Standard Assets/Characters/ThirdPersonCharacter/Animation/HumanoidIdleJumpUp.fbxを選択します。
インスペクタのAnimationタブでHumanoidMidAirを選択し、Root Transform Position(Y)のBased UponをFeetにし、Applyボタンを押します。
これで足元が地面にあるようになりました。
Animatorウインドウでは以下のように表示されます。
Base Layerを押し、元の状態と遷移の画面に戻ります。
次にJumpへの遷移を作ります。
Idle状態を右クリックしてMake Transitionを選択し、Jumpを選択します。
Walk状態を右クリックしてMake Transitionを選択し、Jumpを選択します。
遷移条件はJumpがTriggerされた時を設定し、以下のようなアニメーションブレンドとします。
IdleからJumpもWalkからJumpもほぼ同じにします。
次に接地した時の状態を作ります。
Animatorウインドウ内で右クリックからCreate State→Emptyを選択し、インスペクタで名前をLandingとします。
MotionにはHumanoidCrounchIdleを設定し、FootIKにチェックを入れます。
次にJump状態からLandingに遷移を繋げて設定をします。
ブレンドではJumpアニメーションの終了付近からLandingアニメーションの最初とブレンドします。
次にLandingからIdleへと遷移を繋げます。
Has Exit Timeのチェックを外し、Interruption SourceをNext Stateにし次の条件が成立したらすぐさま遷移するようにします。
またIdle状態へと遷移する条件はSpeedが0.1以下の時です。
次にLandingからWalk状態へと遷移を繋げます。
こちらもLandingからIdleへの遷移とほぼ同じですが、遷移条件にSpeedが0.1以上の時を設定しています。
これでPlayerアニメーターコントローラーへの追加が終わりました。
PlayerControllerスクリプトにアニメーションパラメータ―の操作処理を追加する
PlayerControllerスクリプトにアニメーションパラメータ―を操作する処理を追加していきます。
まずはJumpメソッド内に処理を追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // ジャンプ処理 private void Jump() { // 接地している場合 if (isGrounded) { // ジャンプ処理 if (Input.GetButtonDown("Jump")) { isGrounded = false; animator.SetBool("IsGrounded", isGrounded); //velocity.y += jumpPower; //rigidBody.velocity = new Vector3(rigidBody.velocity.x, rigidBody.velocity.y + jumpPower, rigidBody.velocity.z); rigidBody.velocity = new Vector3(rigidBody.velocity.x, jumpPower, rigidBody.velocity.z); animator.SetTrigger("Jump"); } } // ジャンプ力をアニメーションパラメータに設定 animator.SetFloat("JumpPower", rigidBody.velocity.y); } |
Jumpボタンを押した後isGroundedにfalseを入れた後にアニメーションパラメータ―のIsGroundedにisGroundedの値を渡しています。
またRigidbodyのvelocityを操作した後にJumpアニメーションパラメータ―をトリガーしています。
Jumpメソッドの最後にアニメーションパラメータ―のJumpPowerにrigidBodyのvelocityのyの値を設定しています。
次にCheckGroundメソッドに処理を追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // 地面のチェック private void CheckGround() { if (isGrounded) { return; } // アニメーションパラメータのRigidbodyのYが0.1以下でGroundまたはEnemyレイヤーと球のコライダがぶつかった場合は地面に接地 if (animator.GetFloat("JumpPower") <= 0.1f && Physics.CheckSphere(rigidBody.position, myCollider.radius - 0.1f, LayerMask.GetMask("Ground")) ) { isGrounded = true; velocity.y = 0f; } else { isGrounded = false; } animator.SetBool("IsGrounded", isGrounded); } |
アニメーションパラメーターのJumpPowerが0.1以下の時という条件を加えて接地しているかどうかを確認するようにします。
接地しているかどうかにかかわらずアニメーションパラメーターのIsGroundedの値を設定しています。
Rigidbodyのvelocityのyについて
ここでアニメーションパラメーターのJumpPowerに設定しているrigidBody.velocity.yの値について見ていきたいと思います。
rigidBody.velocity.yにはジャンプした際にjumpPowerの値を設定しています。
jumpPowerには6が設定されているので、ジャンプボタンを押した瞬間にrigidBody.velocity.yは6になります。
そのまま飛び上がり、重力が働いてrigidBody.velocity.yが0になった時が落下していく状態です。
落下していき着地する時にはrigidBody.velocity.yが-6になります。
つまりCheckGroundメソッドで接地を確認している条件文に
1 2 3 | animator.GetFloat("JumpPower") <= 0.1f |
という条件を加えているのはもうすぐ落下に転じ、落下している状態の時だけ接地を確認するという風になります。
なので先ほど2段階ジャンプが意図せず出来てしまいましたが、この条件によってそれが出来なくなりました。
またアニメーターコントローラーのJumpBlendTreeでジャンプ中のアニメーションのブレンドの条件で-6、0、6で設定したのは飛び上がり時、最高到達点、着地時のアニメーションと、その間のブレンドを作る為だったことが分かります。
2段階ジャンプ機能を作成する
ジャンプ機能が出来たので次は2段階ジャンプ出来る機能を作成します。
2段階ジャンプの機能はPlayerControllerスクリプトに処理を追加するだけで出来ます。
まずはフィールドを追加します。
1 2 3 4 5 6 7 8 | // 2段階目のジャンプ力 [SerializeField] private float doubleJumpPower = 5f; // 最初のジャンプをしているかどうか [SerializeField] private bool isFirstJump; |
doubleJumpPowerは2段階目のジャンプのジャンプ力を設定します。
isFirstJumpは最初のジャンプをしているかどうかです。
次にJumpメソッドに処理を追加します。
分かり辛いのでJumpメソッド全文を載せました。
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 | // ジャンプ処理 private void Jump() { // 接地している場合 if (isGrounded) { // ジャンプ処理 if (Input.GetButtonDown("Jump")) { isGrounded = false; animator.SetBool("IsGrounded", isGrounded); isFirstJump = true; //velocity.y += jumpPower; //rigidBody.velocity = new Vector3(rigidBody.velocity.x, rigidBody.velocity.y + jumpPower, rigidBody.velocity.z); rigidBody.velocity = new Vector3(rigidBody.velocity.x, jumpPower, rigidBody.velocity.z); animator.SetTrigger("Jump"); } // ダブルジャンプ } else if (isFirstJump && Input.GetButtonDown("Jump") //&& -jumpPower <= animator.GetFloat("JumpPower") && animator.GetFloat("JumpPower") <= jumpPower - jumpPower * 0.5f ) { isFirstJump = false; // こちらでも出来るが2段階目のジャンプのタイミングを制限する場合に使い辛い //velocity.y += jumpPower; // 前回のRigidbodyの速度に足すとジャンプ→2段階目のジャンプを連続して押した時に最大の到達点になってしまう //rigidBody.velocity = new Vector3(rigidBody.velocity.x, rigidBody.velocity.y + doubleJumpPower, rigidBody.velocity.z); rigidBody.velocity = new Vector3(rigidBody.velocity.x, doubleJumpPower, rigidBody.velocity.z); // 2段階ジャンプの場合はブレンドツリー内で状態が変更されるのでトリガーしない //animator.SetTrigger("Jump"); //animator.ResetTrigger("Jump"); } // ジャンプ力をアニメーションパラメータに設定 animator.SetFloat("JumpPower", rigidBody.velocity.y); } |
接地している時にJumpボタンを押した場合にisFirstJumpをtrueにして最初のジャンプ中であるとします。
isGroundedがfalseの時でisFirstJumpがtrueでJumpボタンを押した時にダブルジャンプをさせます。
if文の条件でコメントにしてありますがJumpPowerに値によってはダブルジャンプをさせないことも出来ます。
これは最高到達点に到達する前だけジャンプ出来るようにしたいといった時に使えるかもしれません。
rigidBodyのvelocityでの設定では元のvelocity.yにdoubleJumpPowerを足すのではなく、そのままdoubleJumpPowerを指定します。
こうすることでどの位置で2段階目のジャンプをしても同じジャンプ力でジャンプ出来ます。
2段階目のジャンプではJumpアニメーションパラメーターをトリガーする必要はありません。
これは既にジャンプ中なのでJump状態におりJumpPowerの値によってジャンプ中のアニメーションのブレンドが行われるからトリガーする必要がありません。
実行して確認してみる
機能が出来たので実行して確認してみましょう。
上のようになりました。
終わりに
今回はアニメーターコントローラーのブレンドツリーを使ってアニメーションのブレンドをし、ジャンプ機能と2段階目のジャンプ機能を作成しました。
ジャンプ機能を取り付けたことでスタートから一気にゴールエリアに侵入出来てしまいます。(^_^;)
次回はゲームのポーズ機能を作成していきます。