今回は、今まで何となく使っていた重力の計算を考えてみようと思います。
物理の計算とか考えるだけでも疲れてしまいますが・・・、重力値の加味に関してあいまいに使っていたので、検証して正しく使ってみる事にします。
ただし、ゲームの世界なのでリアルな重力を働かせなくてもそれらしい重力を使っても問題ありません(._.)
今までの重力計算が正しいか検証する
まずは今までやってきていた重力値の計算が正しく出来ているのかどうかを検証してみます。
重力値の計算はCharacterControllerでキャラクターを動かしている場合は自分で計算しなければいけません。
この自分で計算という部分で間違いが混入してしまいがちです。
Rigidbodyを使ってキャラクターを動かしている場合はRigidbodyのインスペクタでUse Gravityにチェックを入れるだけで、キャラクターに勝手に重力を加味してくれます。
という事で、ヒエラルキー上に二つの3DオブジェクトのCubeを作成し、
スクリプトから重力値を計算するCubeをScriptCube
Rigidbodyの自動重力計算機能を使うCubeをRigidCube
という名前をつけます。
上のようになります。
ScriptCubeがRigidbodyCubeと同じように落下すれば正しくスクリプトが組めているという事になります。
ScriptCubeには上のようにGravityという新しいスクリプトとCharacterControllerコンポーネントを追加します。
Gravityスクリプトは後で作成します。
RigidCubeにはRigidbodyコンポーネントを付け、Use Gravityにチェックを入れます。
今回は落下だけを計算するので、回転や横への移動などはさせないようチェックを入れます。
わかりやすいようにScriptCubeの色を赤色、RigidCubeの色を青色にしました。
今までの間違っていた重力計算スクリプト
ScriptCubeに設定するGravityスクリプトを作成します。
間違い処理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | using UnityEngine; using System.Collections; public class Gravity : MonoBehaviour { private CharacterController characterController; private Vector3 velocity; void Start () { characterController = GetComponent<CharacterController>(); velocity = Vector3.zero; } void Update () { velocity = Vector3.zero; velocity.y = Physics.gravity.y; characterController.Move(velocity * Time.deltaTime); } } |
上のUpdate関数内の処理がわたくしがよくやっていた処理です。
Updateが呼び出される度に移動距離をリセットし、そこに重力値(Physics.gravity.y)を足して最後にTime.deltaTimeをかけて1秒間の速さを計算しCharacterControllerの機能を使って移動させます。
Unityの実行ボタンを押して試してみます。
青色のRigidbodyに比べ赤色のスクリプトで計算した重力の方はやたら落ちてくるのが遅いです。
そもそも重力値(Physics.gravity.y)に1秒間辺りのTime.deltaTimeをかけていないのでおかしい事になっているんですが・・・、ただでさえ落ちるのが遅いのにTime.deltaTimeをかけたらさらに遅くなります。
混乱してきました。(^_^;)
そもそも重力はどうやって計算してるのか?という所を考えなきゃいけません。
そもそも重力はどうやって計算するのか?
重力での落下速度は
落下速度 = 初速度 + 重力加速度 * 時間
なのでCharacterControllerのMoveの引数に渡す速度の所に落下速度を加えなければいけません。
Physics.gravity.y * Time.deltaTime
は前回Updateメソッドが呼ばれてからの時間での落下速度なので、この瞬間の落下速度(Update1回での落下速度)を計算しているに過ぎません。
その為、毎回Updateメソッドで計算したY軸の速度は足さなければいけません。
またvelocityをVector3.zeroで毎回0に初期化していると、前回計算した落下速度のデータが消えてしまう為、落下速度を表す事が出来ません。
今までの重力の計算は完全に間違っていました!(+_+)
重力を正しく計算したスクリプト
ということで、Updateでyの値を初期化せず、Physics.gravity.yにTime.deltaTimeをかけた処理に変更します。
正しい処理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | using UnityEngine; using System.Collections; public class Gravity : MonoBehaviour { private CharacterController characterController; private Vector3 velocity; void Start () { characterController = GetComponent<CharacterController>(); velocity = Vector3.zero; } void Update () { velocity.y += Physics.gravity.y * Time.deltaTime; characterController.Move(velocity * Time.deltaTime); } } |
落下速度は時間経過と共に足していく必要があります。
トータルの落下時間を別途作成するとよりわかりやすい処理になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | using UnityEngine; using System.Collections; public class Gravity2 : MonoBehaviour { private CharacterController characterController; private Vector3 velocity; private float totalFallTime = 0f; void Start () { characterController = GetComponent<CharacterController>(); velocity = Vector3.zero; } void Update () { totalFallTime += Time.deltaTime; velocity.y = Physics.gravity.y * totalFallTime; characterController.Move(velocity * Time.deltaTime); } } |
こちらの場合は落下時間を足していき、速度のY軸は+=ではなく=にしています。
それでは確認してみます。
上のように重力がかかるタイミングが違うので多少ズレていますが、同じ速さで移動しているのがわかります。
重力について
検証してわかった事ですが、今までの重力の計算をしていた処理が全部間違っていました。(^_^;)
移動速度ではなく距離と考えてスクリプトを組んでいたのがそもそも間違っていたのかも。
今回は重力加速度が9.8↓にかかるという風に現実的な重力で計算していますが、ゲームに合わせて重力値を変えたり、そもそも重力を使わないという選択肢もあります。
Physics.gravity.yを使わなくても数値として-3.0fの重力加速度を加えたりしてもいいわけです。
ゲームに合わせて変更してください。