Unityでインディゲームを作る!

Unityでのゲーム制作を目指し、それに関わる話題についてのブログ

Unity2021.3 | OnCollisionEnterを使ってボールを跳ね返す壁を作る[ relativeVelocity ]

Unity_OnCollisionEnter_Reflection_Cover

 UnityにおいてColliderが衝突した時に呼び出されるOnCollisionEnterを利用して、ボールが綺麗に跳ね返る、あるいは反射する壁を作ってみました。ここでのボールとはRigidbodyコンポーネントを持ち、物理挙動をするボールのことです。

Ball_Reflection_Movie_GIF

 単純にボールがバウンドするような壁はPhysic Materialでも作れないことは無いと思いますが、今回はそれとは違う、よりゲーム的に都合が良い結果が出せるであろうアプローチを取っていきます。 

 

ボールの向きを反射する

Ball_Reflection_Wall

 シーンにcubeを追加して、スケールを変更し横長の壁を作ります。そしてBallReflectionWallというC#スクリプトを作って追加します。

 

 このスクリプトの中で行われる処理の流れとしては、OnCollisionEnterに入力されるCollisionからContactPointをGetContactメソッドで取得し、接触面のnormalを利用してボールのvelocityを反転(Reflect)させて再入力する、ということになります。

Ball_Reflection_Wall_Script

 また衝突がボールによって起きたのかを検知するためにCompareTagメソッドを使いますが、"Ball"タグを作成してボールに設定しておく必要があります。

 言葉で説明するとややこしい感じがしますが、上画像にあるようにコードとしては十行ほどで意外と短く収まります。

 

 Rigidbodyの進む方向とスピードは、その方向と長さを掛け合わせた三次元ベクトルの形で、velocityというVector3変数に格納されており、逆にそこに代入すれば思うがままにRigidbodyを動かすことが出来ます。いきなりその速度になるので、徐々に加速するという表現には合いませんが、弾の発射などを再現するには十分だと思います。(もちろんAddForceメソッドでも同様な挙動は再現できますが)

 

relativeVelocityとは

 このようなボールを跳ね返す壁を作る際には、このvelocityをそのまま反転させて再入力することを考えますが、OnCollisinEnterが呼び出されるのは衝突の後なので、そこからボールのRigidbodyに対してvelocityを取得しても当然止まってしまっています。

 

 なので、Collisionインスタンスに含まれるrelativeVelocityを利用します。これは衝突した2つのオブジェクトの相対的な速度ですが、ここから衝突してきたボールのvelocityを取得することができ、これをVector3.Reflectで反転させることで、跳ね返ったボールの向きとスピードを求めることが出来ます。

 相対的、ということは壁は当然止まっているので、必然的に壁に突っ込んできたボールのスピードがここから取得できるということです。

 

 また、このコード内でvelocityに1.0以上の数値を掛け合わせると衝突時よりも速いスピードでボールを跳ね返すことができ、ピンボールにおけるバンパーのようなゲームとして面白いギミックが作れそうです。反転させたvelocityに掛ける新たな変数を追加するだけで、この機能を追加できます。

 

まとめ

 以上で、ボールを綺麗に反射する壁を作ることが出来ました。ここに機能を追加していけば、跳ね返す時に音を出したり壁が動くなどのアニメーション的表現も可能になりますが、今回はひとまずC#スクリプトを作成して基本的動作を作った感じです。

 

 物理演算はコントロールが難しいですが、やはり面白い挙動が作れますね。物理演算を上手く利用したゲーム、あるいは機能が作れるように頑張りたい!