地面に立つ
CoddyのUnityジャーニー「物理演算とゲームプレイ」セクションの一部。レッスン 11/71。
すべての接触には法線があります。これは長さが1の方向ベクトルで、触れた面に垂直に、その面から離れてあなたのオブジェクトの方を向いています。collision.GetContact(0)は最初の接触点で、そのnormalがどちら側に触れたかを示します。平らな地面に立っているときは(0, 1, 0)、右側の壁に接しているときは(-1, 0, 0)、天井に頭をぶつけたときは(0, -1, 0)です。
このコードでは、着地と横からの衝突を判別します。
void OnCollisionEnter(Collision collision)
{
Vector3 normal = collision.GetContact(0).normal;
if (normal.y > 0.5f)
{
Debug.Log("Landed on " + collision.gameObject.name);
}
else
{
Debug.Log("Bumped the side of " + collision.gameObject.name);
}
}テストにnormal.y > 0.5fを使い、ちょうど1とはしないのは、傾斜も地面として扱うためです。60度の傾斜ではyが0.5になり、人が歩いて上れる傾斜より急です。さらに、続いている接触に関するメッセージを2つ追加できます。OnCollisionStayは接触が続いている間、物理演算のステップごとに実行され、OnCollisionExitは接触が終わったときに1回実行されます。接触が終わると何も触れていないため、接触点はありません。そのため、そこでGetContactを呼び出さないでください。
チャレンジ
簡単プレイヤーが何かの上に立っている間だけジャンプできるようにします。
private bool grounded;を追加します。OnCollisionStayでcollision.GetContact(0).normal.y > 0.5fのとき、これをtrueに設定します。OnCollisionExitではfalseに設定します。FixedUpdate()ではif (jumpPressed && grounded)の場合のみジャンプし、そのifの後にjumpPressed = false;を設定して、空中での入力を無効にします。
「プレイ」を押して二段ジャンプを試してみましょう。2回目の入力では何も起きません。その後、「確認」を押します。
自分で試してみよう
using UnityEngine;
public class Hopper : MonoBehaviour
{
public float speed = 4f;
public float jump = 6f;
private Rigidbody rb;
private bool jumpPressed;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
jumpPressed = true;
}
}
void FixedUpdate()
{
float h = Input.GetAxisRaw("Horizontal");
rb.linearVelocity = new Vector3(h * speed, rb.linearVelocity.y, 0);
if (jumpPressed)
{
rb.AddForce(Vector3.up * jump, ForceMode.Impulse);
jumpPressed = false;
}
}
}
物理演算とゲームプレイのすべてのレッスン
自分で練習してみよう: Unityプレイグラウンド