(この記事の使用環境: Unity5.4.2f2 Personal、Windows10


今回はキャラクターをしっかりと地面に立たせるためにRayを使ってみた話。
全画面キャプチャ 20170119 143045

設定次第だとは思いますが、3Dキャラクターモデルおよびそれ用のアニメーションを使っていて、キャラクターがしっかりと地面に接して立たずにふわふわと浮いたようになることがありました。その原因はいまいち特定できていないのですが、とりあえずRayを使ってしっかり接地させることができたので、今回はその紹介です。

「しっかりと地面に接して立たない」とはどういう状況か、まずはNG事例を2つ挙げます。

1つ目。Cubeをよじ登った後、足が地面に接しておらず、ふわふわと浮いてしまっています。


2つ目。Cubeから降りた後、空中に立ってしまっています。


今回はこの2つの現象を解決してみました(対症療法的かもしれませんが)。

解決後はこんな感じ。Cubeによじ登った後も、Cubeから降りた後も、しっかりと地面に接して立つことができています。

 
スクリプトの該当部分のみ紹介していきます。

まずは「よじ登り」後の接地処理はこんな感じ。

        // --- よじ登りアニメーションが終わった時の処理 ----------------------------
        if (anim.GetBool ("Climb") == false)  
        {
            _state = eState.Default;
            rb.isKinematic = false;

            Ray ray = new Ray (transform.position + transform.up * 1f, -transform.up);
            RaycastHit hit;
            if (Physics.Raycast (ray, out hit))
            {
                transform.position = new Vector3 (transform.position.x, hit.point.y, transform.position.z); // 接地位置あわせ
            }
        }

Rayをプレイヤーの体からまっすぐ下に伸ばし、地面とぶつかった位置のY座標をプレイヤー位置のY座標にしています。こうすることで、「よじ登り」アニメーションが終わったとき、しっかりと地面に接して立つことができます。

次に、Cubeから降りたときの接地処理はこんな感じ。

        // --- 接地していなければ接地するまで落ちる ---------------------------------------
        Ray ray = new Ray (transform.position + transform.up * 1f, -transform.up);
        RaycastHit hit;
        if (Physics.Raycast (ray, out hit))
        {
            if(transform.position.y > hit.point.y + 0.01f)
            {
                transform.Translate (0f, -0.15f, 0f);
            }
        }

これも同様に、Rayをプレイヤーからまっすぐ下に伸ばし、地面との接点のY座標を取得しています。ただし高さのあるところから降りるので、一瞬で接地するのではなく、更新処理のなかで(ほぼ)接地するまでプレイヤーのY座標を下げ続けるようにしています。

これらのアイデアは、StandardAssets>Charactersのなかにあるスクリプト「ThirdPersonCharacter.cs」を参考にさせてもらいました。「ThirdPersonChatacter.cs」では、Bool型の変数「m_IsGrounded」(=接地しているかどうか)を定義し、各所でその値を使用しています。

今回は以上です。