Unity キャラクター接地判定(空中ジャンプ禁止)

Unityのキャラクターが空中でジャンプできてしまう問題が意外と解決できなくて、すこし悩みました😱


CharacterControllerを使えばできるらしいのですが、あんまり使いたくなかったのでRigitbodyを使ってキャラクターの接地判定をする方法を考えました😏参考程度に聞いてください

先にアイディアだけを説明すると、キャラクターの下にColliderを敷いてそのColliderの接触判定を使って接地したかどうかを判定させました。

今回は、簡単にplaneとcubeだけ用意しました。planeが地面で、cubeがキャラクターのつもりです。
f:id:ingentity:20180430180152p:plain

cubeにはRigidbodyをつけてあげましょう。キャラクターがずっこけないようにFreez Rotationには三つともチェックを入れましょう。
f:id:ingentity:20180430181850p:plain


今回はジャンプの機能だけを作ります。
ジャンプ用スクリプトはこんなかんじ。

using UnityEngine;

public class TestJump : MonoBehaviour {

    public Rigidbody rb;
    public float JumpPower;

    private void Start()
    {
        OnGround = false;
    }

    //RigitbodyをいじるためFixedUpdateで処理を行う
    private void FixedUpdate()
    {
        if (Input.GetButtonDown("Jump"))
        {
            rb.velocity = transform.up*JumpPower;
        }
    }
}


上のスクリプトをcubeにアタッチして、Rigitbody、JumpPowerの設定をしましょう
f:id:ingentity:20180430180340p:plain


いざ実行!👉
f:id:ingentity:20180430180958g:plain


もちろん接地判定を行っていないので無限にジャンプして画面から消えてしまいました👋


では、接地判定を作っていきましょう!まず、新たなcubeを作成し、元あったcubeの子供にしてください👶
f:id:ingentity:20180430181314p:plain


名前は、Footとかにしましょう👣
f:id:ingentity:20180430182805p:plain


そして、Transformを下のように設定しましょう。ついでにBox ColliderのIs Triggerにもチェックを入れてください。
f:id:ingentity:20180430181541p:plain


cubeの底に張り付く感じになればOKです👌
f:id:ingentity:20180430182933p:plain


そして新たにスクリプトを作ります。

using UnityEngine;
using UnityEngine.Events;

public class GroundChecker : MonoBehaviour {

    //接地した場合の処理
    public UnityEvent OnEnterGround;
    //地面から離れた場合の処理
    public UnityEvent OnExitGround;
    //接地数
    private int enterNum = 0;

    private void OnTriggerEnter(Collider collision)
    {
        Debug.Log("OnGround!");
        enterNum++;
        OnEnterGround.Invoke();
    }

    private void OnTriggerExit(Collider collision)
    {
        Debug.Log("ExitGround!");
        enterNum--;
        if (enterNum <= 0)
        {
            OnExitGround.Invoke();
        }
    }

}


上のスクリプトをFootにアタッチしましょう。


上のスクリプトでenterNumを増やしたり減らしたりしているのは、複数のオブジェクトがTrigger内にEnterする場合もあるのでこのような処理になりました。


これで、Footが何かColliderを持つオブジェクトに触れたとき、OnEnterGroundが呼ばれ、Footがどのオブジェクトにも触れなくなった時OnExitGroundが呼ばれるはずです。


そこで、もう一度TestJump.csを開いて編集しましょう。

using UnityEngine;

public class TestJump : MonoBehaviour {

    public Rigidbody rb;
    public float JumpPower;
    //接地判定
    public bool OnGround { get; set; }//追記

 //追記
    private void Start()
    {
        OnGround = false;
    }

    //RigitbodyをいじるためFixedUpdateで処理を行う
    private void FixedUpdate()
    {
        //接地していればジャンプできる
        if (Input.GetButtonDown("Jump")&&OnGround)//追記
        {
            rb.velocity = transform.up*JumpPower;
            //ジャンプした瞬間接地判定を解除
            OnGround = false;//追記
        }
    }
}


OnGroundを設置状況に応じて変更するため、GroundCheckerのイベントを登録しましょう。
f:id:ingentity:20180430184542p:plain
f:id:ingentity:20180430184822p:plain
f:id:ingentity:20180430184838p:plain


いざ、実行!👉👉
f:id:ingentity:20180430185139g:plain

うん!よさげ!!


Footの位置やサイズやフィールドの状況次第で不具合は起きる可能性があります😭参考程度でよろしく