地面に立つ
CoddyのUnityジャーニー「物理演算とゲームプレイ」セクションの一部。レッスン 11/63。
すべての接触には法線があります。これは長さが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は接触が終わったときに一度だけ実行されます。接触が終わると、もう何も触れていないため接触点はありません。そのため、そこでGetContactを呼び出さないでください。
チャレンジ
簡単プレイヤーは歩いたりジャンプしたりできますが、Spaceキーは空中でも機能するため、ジャンプを繰り返して空まで登ったり、壁の側面から飛び降りたりできます。(コライダーには摩擦のないマテリアルが設定されているため、壁に張り付かずに滑り落ちます。)何かの上に立っている間だけジャンプできるようにしましょう。
bool groundedを保持します。プレイヤーが接触法線が上向き(y が 0.5 より大きい)になる何かに触れている間はtrue、接触しなくなったらfalseにします。- Spaceキーが押され、
groundedがtrueのときだけジャンプさせます。空中でのキー入力は無視し、着地するまで保存しません。
Playを押し、2回ジャンプしたり壁を登ったりしてから、Checkを押してください。
自分で試してみよう
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;
}
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。