物理演算を使いたくない理由
Unityの物理演算(Rigidbody周り)は大変便利な機能ですが、時に制御しきれないときもあります。
意図せず、Collisionを突き抜けてしまったりしますよね。
なにより、**Unityの便利機能に甘えっぱなしな感じがちょっと嫌なので、**今回はRigidbody、Rigidbody2Dを使わず、横スクロールアクションゲームを開発した時のことを書こうと思います。(Collisionは使います。)
不思議の国のアリスが、ハートの女王などが仕掛ける罠をよけるゲームです。
Raycastを使う
本来、Rigidbodyを設定しないと、Collision周りのメソッド(OnCollisionEnterメソッドとか)が反応しないため、「何かに当たったときに、ダメージを負う」的な処理ができません。
なので、結局Unityの機能に甘える形にはなりますが、Rayを使用します。Rayを投げ、当たったCollisionの座標との距離を測ったりして、衝突判定の処理を実装します。
これは、Debug.DrawRay()
メソッドでキャラクターやトラップからRayを飛ばす様子をSceneウィンドウから確認したものです。白い線が当たり判定によるアリスの動きの処理をするためのRayで、鎌から伸びている赤い線が、アリスに当たった瞬間アリスにダメージを与える処理をするためのRayです。
床判定、壁判定
今回作るゲームは、スマートフォン向けのずっと横に走り続けながら、敵をかわしてスコアを伸ばすゲームなので、床の判定と壁の判定が必要になりました。
なので、まずはキャラクターから横向きと、下向きにRayを飛ばします。(左右に動く場合は、左右どちらにもRayを飛ばす必要がありますが、今回はずっと右向きに走るゲームなので、右向き、Vector3(1,0,0)の方向と下向き、Vector3(0,-1,0)の方向のみにRayを飛ばします。)
private bool IsCollision(Vector2 direction,float distance,float adjast = 0)
{
var position = transform.position;
// Rayを飛ばす初期位置を調整する
position.y += adjast;
var raycastHit2D = Physics2D.RaycastAll(position, direction, distance);
Debug.DrawRay(position, direction);
// 何も検知できなかった場合、処理を中断し、falseを返す
if (raycastHit2D.Length == 0)
return false;
foreach (var raycastHit in raycastHit2D)
{
if (raycastHit.collider
&& !raycastHit.collider.gameObject.Equals(gameObject))
return true;
}
return false;
}
※Rayを飛ばすオブジェクト自体にCollisionを付けている場合、Rayを飛ばす位置は自身のオブジェクトも含んで当たったことを通知します。なので自身と子オブジェクトの当たり判定を外す必要があります。
移動の処理
Rigidbodyを使う場合は、velocityなどを使えば簡単にオブジェクトを動かせます。
しかし、Rigidbodyを設定していないため、Tween系のライブラリを使うか、transform.positionを愚直に操作するしかありません。
本来であればTweenなどを使うべきかもしれませんが、面倒くさかったため、transform.positionの値を0.001fずつ動かすというヤバみの深い実装になりました。
(UIとかはTween使うと綺麗に動くので、Tween好きです。)
結論
カジュアルゲーム作るぐらいなら、普通にRigidBody使ったほうが良いと思いました。
ちょっと調べると、Rayも普通に処理として重いそうです。(なので、あらかじめ飛ばす距離などはできるだけ短く指定してあげるとましになるとか、ならないとか・・・)
あと、見た目が2.5Dの場合は、2D用のRayではなく、3D用のRayを使用したほうが開発しやすいのでは・・・と思いました。