物を押す
CoddyのUnityジャーニー「本格的なゲームを作る」セクションの一部。レッスン 40/56。
CharacterControllerは何かを押すことはありません。Rigidbodyの付いた木箱に向かって歩いても、壁に当たったときのように止まります。その代わり、UnityはMoveが触れたすべてのコライダー(床も含む)に対して、コントローラー自身のスクリプトでOnControllerColliderHit(ControllerColliderHit hit)を呼び出し、何が起こるかはスクリプトが決めます。hit.colliderは触れたもの、hit.moveDirectionはそれに触れたMoveの方向、hit.normalは接触地点でその表面が向いている方向です。これはUnity独自の押すスクリプトです。
public float pushPower = 2f;
void OnControllerColliderHit(ControllerColliderHit hit)
{
Rigidbody body = hit.collider.attachedRigidbody;
if (body == null || body.isKinematic) return; // 押す対象がない
if (hit.moveDirection.y < -0.3f) return; // 足元にある
Vector3 pushDir = new Vector3(hit.moveDirection.x, 0f, hit.moveDirection.z);
body.linearVelocity = pushDir * pushPower;
}それぞれのreturnには理由があります。床や壁にはRigidbodyがないため、それらに対してはbodyがnullになり、ほぼすべてのMoveで触れます。キネマティックボディは自身のスクリプトが動かしたときにだけ移動するので、速度を設定しても何も起きません。下向きに急な方向を指すMoveは足元にあるものに触れたということであり、プレイヤーが乗っている木箱を押してはいけません。
押す方向にはxとzだけを使うため、木箱は地面に押し付けられるのではなく、地面に沿って滑ります。力を加える代わりにlinearVelocityを設定すると、軽い木箱も重い木箱も同じペースで動きます。一方、body.AddForce(pushDir * pushPower, ForceMode.Impulse)では、重い木箱はあまり押されません。
チャレンジ
中級庭でボールを蹴って動かそう。プレイヤーはCharacterControllerを使って歩きます(Walker.cs、準備済み)。PlayerにもKicker.csを作成します。InspectorでkickPower(6)とlift(4)を設定します。
- プレイヤーが押せる物体に歩いてぶつかったとき、その
linearVelocityを歩く方向に設定します。地面に沿った水平な方向にkickPowerを掛け、さらに真上にliftを加えることで、ボールが前方かつ上方に飛ぶようにします。 - 地面とポストにはRigidbodyがありません。エラーを出さずにスキップします。
- プレイヤーの足元にあるボールは蹴られません。
Playを押して赤いボールを蹴り、それからCheckを押します。
自分で試してみよう
using UnityEngine;
public class Kicker : MonoBehaviour
{
public float kickPower = 6f;
public float lift = 4f;
// プレイヤーがぶつかったボールを蹴る
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。