色々な接地判定
キャラクターの移動時、地面に接触しているかどうかを判定したいときがある
以前までは地面となるオブジェクトにtagをつけてOnConllisionEnterなどで判定していたけど、他にも色んな判定方法があるらしい。
CharacterControllerを使う
CharacterControllerにはあらかじめ接地判定用にisGroundedプロパティが存在する
docs.unity3d.com
これだけ見るとすごく楽ちんなんだけど実は判定制度が微妙らしい
斜面だとfalseになることがある。厳密な判定が必要なら他の方法を使ったほうがよさそう
Physics.RayCastを使う
ようは真下にレイを飛ばして衝突していれば接地していると判断する方法
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GroundCheck : MonoBehaviour { public float rayDistance = 1.2f; void Update() { Vector3 rayPosition = transform.position + new Vector3(0.0f, 0.1f, 0.0f); Ray ray = new Ray(rayPosition, Vector3.down); bool isGrounded = Physics.Raycast(ray, rayDistance); Debug.Log(isGrounded); Debug.DrawRay(transform.position + new Vector3(0.0f, 0.1f, 0.0f), Vector3.down * rayDistance, Color.red); } }
精度は上がるけどレイの長さを調節したり少しめんどくさいのと、地面にのみ衝突させるときはレイヤーを設定する必要がある
Physics.CapsuleCastを使う
SphereCastやBoxCastでもいいけど今回はカプセル型のオブジェクトを置いているのでCapsuleCastを使用
RayCastを太くしたようなものなのでよりいい感じに判定できるらしい
public class GroundCheck : MonoBehaviour { RaycastHit hit; Vector3 startPos; Vector3 endPos; bool isGrounded; void Update() { startPos = transform.position - transform.up * 0.5f; endPos = transform.position + transform.up * 0.5f; isGrounded = Physics.CapsuleCast(startPos, endPos, 0.5f, transform.up * -1.0f, out hit); Debug.Log(isGrounded); } void OnDrawGizmos() { Gizmos.color = Color.red; if(isGrounded) { Gizmos.DrawRay (transform.position, transform.up * -1 * hit.distance); Gizmos.DrawWireSphere(startPos + transform.up * -1 * hit.distance, 0.5f); Gizmos.DrawWireSphere(endPos + transform.up * -1 * hit.distance, 0.5f); } else { Gizmos.DrawRay (transform.position, transform.up * -1 * 100); } } }
こんな感じで内部にめり込んでるときはfalseになるので、どうにかしたい場合にはcast位置を上げるかCheckSphereなどを使うといいらしい
おわりに
調べると他にも色々あるみたいなので、状況に応じて最適な接地判定が出来るようになりたいですね