今回の記事でも引き続きブロック崩しを作成していきます。
前回はUnityの入力処理とRigidBodyを用いた物理エンジンの利用法を習得しましたね。
前回の記事:
今回はボールを動かしてみましょう!
物理エンジンを使ってボールを動かしてみよう。
それでは早速ボールを動かしてみましょう!
初めにシーン上に配置した「Ball」にRigidBodyコンポーネントをアタッチしてください。
アタッチできましたら、RigidBodyを次のように設定してください。
- Use Gravityをオフにする
- ConstraintsのFreeze PostionのX、Y以外にチェックする。
設定したらBallという名前のスクリプトを作成し、オブジェクトの「Ball」にアタッチしてください。
Ballコンポーネントの内容は次のようにしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// … using UnityEngine; public class Ball : MonoBehaviour { [Range(0, 1000)] public float Speed = 1000f; public Vector2 Direction = new Vector2(0, 1); void Start() { var rigidBody = GetComponent<Rigidbody>(); rigidBody.AddForce(Direction.normalized * Speed * Time.deltaTime, ForceMode.Impulse); } } |
スクリプトのコンパイルに成功しますと、再生と同時にボールが動き出します。
Speedは小さいとゆっくりと動くので大きくするのがおすすめです(1000だと早すぎるかもしれないので値は調整してください)。
また、このまま再生するとボールは何かに当たった時にそのまま止まってしまいます。
これについては後ほど解決します。
Colliderについて
ボールはColliderをアタッチされたGameObjectとしか衝突しません。
これはUnityの物理エンジンの仕様になります。
UnityEngine.Collider
コンポーネントを継承したものをアタッチしたGameObjectのみが物理エンジンによる当たり判定の対象になります。
Colliderには代表的なものとして次が挙げられます。
- BoxCollider
- SphereCollider
- MeshCollider
今回の記事で作成したBallオブジェクト(Sphereオブジェクト)には作成された初期段階で既に形状にあったColliderがアタッチされているため当たり判定が機能します。
また、次に紹介する物理マテリアルをColliderのMaterialに設定することで衝突や反射などの物理演算を簡単に取り入れることができます。
物理マテリアルについて
ここからは、ボールが何かに当たった時に跳ね返る設定を作っていきましょう。
跳ね返りを設定するときは物理マテリアルを使用します。
作り方はメニューのEdit > Create > Physics Materialをクリックします。
作成した物理マテリアルの名前はボールに設定するので「BallPhysicsMaterial」と名付けましょう!
作成したら、次のように設定してください。摩擦をないものとして、完全弾性運動をするように設定しています。
- Dynamic Frictionを0に
- Static Frictionを0に
- Bouncinessを1に
- Friction CombineをMimimumに
- Bounce CombineをMaximumに
ちなみに物理マテリアルで指定できるパラメータは次のものになります。
- Dynamic Friction:動いている時の摩擦力
- Static Friction: 止まっている時の摩擦力
- Bounciness:弾性係数。跳ね返りの強さ
- Friction Combine:当たった時の摩擦係数の適応の仕方
- Bounce Combine:当たった時の跳ね返り係数の適応の仕方
設定が終わったら、ボールに「BallPhysicsMaterial」を設定しましょう。
物理マテリアルはColliderコンポーネントのMaterialに設定します。
プレイヤーにも物理マテリアルを設定する 球が反射するようになる
ボールの設定はできましたが、今のままだとプレイヤーに当たった時にボールが止まってしまいます。
こちらも物理マテリアルによって解決できますので、プレイヤーにも物理マテリアルを設定をしてきましょう。
プレイヤーに設定する物理マテリアルはボールのものと反対の設定し、プレイヤーのColliderのMaterialに設定してください。
プレイヤーに設定する物理マテリアルのパラメータは次のものにです。
- Dynamic Frictionを1に
- Static Frictionを1に
- Bouncinessを0に
- Friction CombineをMaximumに
- Bounce CombineをMinimumに
また、プレイヤーのRigidBodyのMassを100などボールより大きくなるように設定してください。ボールと同じくらいのMassだとボールと当たった時にボールが止まってしまいます。
物理マテリアルの設定はボールと同じなので省略します。作成した物理マテリアルの名前は適当なものにしてください。
プレイヤーの操作と物理エンジンの注意点
注意点としてプレイヤーのPlayerコンポーネントのCurrentTypeをTransformだと、ボールがぶつかった時の力がRigidBodyに蓄積していき、操作していないのに移動したり、反対の方向に移動してしまいます。
これはPlayerコンポーネントが物理エンジンとは異なるところで処理を行なっているのが原因になります。物理エンジンによって発生した移動量や加速度などが蓄積していき徐々にその力が大きくなっていき、プレイヤーの操作に干渉していくからです。
このような動作を避けるためには物理エンジンを使うときはRigidBodyを利用してGameObjectを動かすようにしてください。そうすると、プレイヤーを操作した時に発生する力が物理エンジンと組み合わさり、おかしな挙動をしづらくなります。
それでも、他のGameObjectが衝突した時に発生する力は生じるので若干操作しづらくなる場合も出てくるので注意してください。
また操作性もTransformの時と異なってくるので、移動の速さが遅い時はSpeedを大きくしたり、慣性が大きい時はRigidBodyのDragを1にしてみるなどパラメータを調節してください。
完全弾性運動させるには? 当たり判定のコールバックについて
ここまででボールの挙動は大体問題ないものになりましたが、何かとぶつかるたびにスピードが遅くなってしまいます。
これはUnityの物理エンジンによるもので、物理的には正しいのですが、今回のブロック崩しではボールが途中で止まってしまうなど少し困った挙動を生み出します。
そのためブロック崩しではスクリプトを使い一定の速さになるよう制御する方が動作が安定します。
一定の速さにするにはUnityEngine.MonoBehaviourの当たり判定に関するコールバックを利用すると簡単です。
当たり判定に関係するコールバックは次のものがあります。
- OnCollisionEnter: 当たった時
- OnCollisionStay:当たり続けている時
- OnCollisionExit:離れた時
また、IsTriggerを有効にしたColliderは当たり判定を表すだけになり、物理演算を行わなくなります。
その際の当たり判定のコールバックはOnTriggerXXX系になりますので注意してください。
- OnTriggerEnter:Trigger指定されたColliderに当たった時
- OnTriggerStay:Trigger指定されたColliderに当たり続けている時
- OnTriggerExit:Trigger指定されたColliderから離れた時
それでは実際に当たり判定のコールバックを使用しボールの速さを一定にしてみましょう!
次のサンプルコードではOnCollisionEnterメソッドで当たった時にSpeedの速さになるよう処理しています。
また、Updateメソッドの中でボールが動かなくなるのを防ぐための処理も行なっています。
完全に物理エンジンに任せると思わぬ挙動が発生するかもしれないので、実際のゲームではUpdateメソッドのような物理エンジンの動作を安定させる処理も必要になるかもしれません。
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 |
// … using UnityEngine; public class Ball : MonoBehaviour { [Range(0, 1000)] public float Speed = 1000f; private Vector2 Direction = new Vector2(0, 1); private Rigidbody rigidBody; void Start() { rigidBody = GetComponent<Rigidbody>(); rigidBody.AddForce(Direction.normalized * Speed * Time.deltaTime, ForceMode.Impulse); } private void Update() { if (Mathf.Abs(rigidBody.velocity.y) <= 1) { rigidBody.velocity += Vector3.up * 5f * (rigidBody.velocity.y >= 0 ? 1 : -1) * Time.deltaTime; } } private void OnCollisionEnter(Collision collision) { rigidBody.velocity = rigidBody.velocity.normalized * Speed * Time.deltaTime; } } |
余談になりますが、ブロック崩し程度の挙動ならスクリプトから全て計算するのもいい方法です。
が、数学的な知識が必要になってくるのでここではUnityにお任せしましょう。
全て計算する際も当たり判定系はUnityの物理エンジンに任せるのがいいでしょう。当たり判定の実装は難しいものになるので、そこだけ物理エンジンに任せるようにゲームを作るのも一つの方法になります。
まとめ
今回の記事ではボールの移動処理、当たり判定処理を作ってきました。
Unityの物理エンジンはゲーム用途のものなので、正確性より処理の速さを優先しています。そのためすり抜けたり、思ったような動きにならないなどの問題が発生することもあります。
実際にゲームを作るときはこうした物理エンジンの背景を理解しながら作っていきましょう!
記事をまとめると次のようになります。
- Unityの物理エンジンではUnityEngine.Colliderを継承したコンポーネントをアタッチしたGameObjectしか当たり判定の対象にならない。
- 物理マテリアルを使用するとより細かい物理エンジンの挙動を制御できる。
- スクリプトから当たり判定の結果を受け取りたい時は専用のコールバックを使用する。Unityの物理エンジンは実行速度を優先しているので、物理エンジンの処理の背景を理解しながら作るのがおすすめ。
それでは次の記事に行ってみましょう!
コメント