Unityで3Dでのプレイヤーのジャンプ
Unityで3Dゲームを作る際のプレイヤーがジャンプする方法を紹介していく。以前の記事でTPS視点でのプレイヤーの移動と追従するカメラを実装し以下のような動作が可能となった。
今回はこれにジャンプ機能を追加していこうと思う。以前の記事を読んでない場合はまずはそちらを確認してほしい。
TPSのキャラ移動
詳しく説明するつもりだが、さすがに操作やC#など基礎がわかってない場合は理解が難しいと思うので、以下を確認してほしい。
Unityの基礎まとめ
C#の基礎まとめ
3Dでのプレイヤーのジャンプ方法目次
Rigidbody・Collider追加スクリプト記述
追記(ジャンプアニメーション追加)
目次にもどる
Rigidbody・Collider追加
まず、PlayerにRigidbodyとCapsule Colliderを追加する。RigidbodyやColliderがわからない人は以下の記事を確認してほしい。
Rigidbody基礎
Capsule ColliderのCenter、Radius(半径)、Height(高さ)を調整して以下のようにPlayerをすっぽりと覆うようにしよう。
具体的には以下のように設定した。
続いてRigidbodyのコンポーネントを見てほしい。
Constraintsの左の三角ボタンを押して開き、Freeze Rotationのx、y、zにチェックを入れよう。
チェックをつけることでX軸、Y軸、Z軸の回転に対して重力が影響しないようにできる。
ここにチェックをつけないと、例えば以下のようにマウスを操作してキャラを傾けた場合、重量が作用してここから操作しなくてもだんだん傾いていってしまう。
よってチェックはつけておこう。
それとMassについては65に設定しておこう(Rigidbodyがついている物体の重量を示す。単位はkg)。Playerの体重は65kgとなる。
目次にもどる
スクリプト記述
以下のようにスクリプトに記述してPlayerにアタッチした。以前の記事で紹介したWASDまたは矢印キーの移動に加えて、以下の記述を加えたことでスペースボタンを押すことでジャンプすることが可能となっている。
ジャンプ中にジャンプできるのもゲームによってはアリだが、今回は禁止したい。そのためにはPlayerが地面にいるか空中にいるのか判断する必要がある。
そこで、RayCast系の関数の一つであるSphereCastを使用した。
RayCastがよくわからない場合は以下の記事を確認してほしい。
RayCast基礎
なぜ線の光を放つRayCastではなく、球形の光を放つSphereCastを使用するかというと、ある程度広い範囲を探知したいからだ。
今回はRayを真下に放ち、プレイヤーのすぐ下に地面となるゲームオブジェクトがあるかどうかを確認する。
RayCastでは以下のような場面で、ゲームオブジェクトの上にPlayerが乗っているにもかかわらず、放った線が当たらないので地面がないと判断してしまう。
ただ、SphereCastを使う際にも注意点がある。Rayの発射位置にあるゲームオブジェクトは探知しない点である。
今回使っているPlayerのアセットの原点は足元にある。つまり普通にPlayerからSphereCastを放てば、足下のゲームオブジェクトを探知できない可能性がある。
よって、最初に以下の処理を行っている。
raykeisanという変数に今のPlayerの位置を代入。raykeisanのY座標に0.5fを加算する。
その上でSphereCastでの条件分岐を行う。
raykeisanの位置に半径0.3の球のRayを作り、Vector3.downつまり(0,-1,0)で真下に向かって0.6fの距離まで放つ(一応、Rayが衝突したゲームオブジェクトの情報をzimenへ取っているが、ひとまず使うことはない)。
0.3の半径の球ができても、raykeisanのY座標を0.5f上げていることで、足下付近がRay開始位置に含まれずにすむ。
raykeisanのY座標を0.5f上げたことを考慮し0.6fの長さのRayを撃っている(上下への向き変更で微妙にY座標が変化することも考慮)。
足下付近に放たれたRayが、もしゲームオブジェクトに当てればIf文の中身の処理が行われる。
中身はif (Input.GetButtonDown("Jump"))とあり、「スペースボタンが押されていたら・・・」という意味となる(InputManagerでデフォルトで割り当てられている)。GetButtonDownとなっているのでキーを押した瞬間を検知することができる。
スペースボタンを押した際は中身のzyuuryoku.AddForce(Vector3.up * jumpSpeed, ForceMode.Impulse);の処理が行われ、ジャンプを行う。
zyuuryokuにはPlayerのRigidbodyの値が格納されており、AddForceでRigidbodyがついているゲームオブジェクトに力を加えることができる。
AddForceがよくわからない場合は以下の記事を確認してほしい。
AddForce基礎
Vector3.upの部分で力がかかる向きを指定している。キャラが向きを変えて上や下を見られるようになっているため、transform.up(ローカル座標の上方向)では都合が悪い。例えば以下のような体勢でスペースボタンを押した場合、前方に低く飛んでしまう。
身体の向きによってジャンプの方向を変えたくないので、ワールド座標の上方向を示すVector3.upを指定し、それにjumpSpeedをかけている。
そして、ForceMode.Impulseとしている。この部分は重力の与え方を指定している。4つのモードがありその中でImpulseは質量を考慮して瞬間的に力をかけてくれる。
Rigidbodyのコンポーネントのmasを65に設定したためPlayerは65kgある。それを考慮した力が上向きにかかることでジャンプが行われる。
以上のスクリプトをPlayerにアタッチして再生すると以下のような動作が可能である。
スペースボタンを押すことでジャンプが可能。プレイヤーが床から落ちたら落下していく。だいぶ3Dゲームらしくなってきた。
目次にもどる
追記(ジャンプアニメーション追加)
ジャンプができるようになったのはいいが、ジャンプ時に移動すると走っている時のモーションとなるので、かなり違和感がある。そこで、以下のようにPlayercontrollerにJumpのステートを追加し、Jumpのステートにいる間は2Hand-Sword-JumpのAnimationClipを出すように設定。
Bool型のパラメータJumpを作成し、Jumpのパラメータがtrueの時に停止時や移動時からJumpへ遷移するように設定。逆にJumpがfalseになったらIdleに遷移するように設定しよう。
そして、以下のようにスクリプトのジャンプ時の記述を書き換えた。
大した変化はない。地面についた状態ならGroundtukuをtrue、そうでないならfalseにするように記述している。これについては後々使うことになるので書いているが、ひとまずは必ずしも必要ない。
地面についた状態ならanim.SetBool("Jump", false);、地面についていないならanim.SetBool("Jump", true);と記述。空中に浮いているならアニメーションが切り替わるようになる。
今後の記事で攻撃アニメーションに遷移させる内容も出てくるが、その際は移動だけでなく今回作ったJumpから攻撃のステートに遷移させるようにしてほしい。
続きの記事は以下。
ダッシュ実装