物を押す
CoddyのUnityジャーニー「本格的なゲームを作る」セクションの一部。レッスン 41/60。
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)なら、重い木箱はより小さく押されます。
チャレンジ
中級プレイヤーが歩いてぶつかったボールを蹴れるようにしましょう。
Kicker.csで、void OnControllerColliderHit(ControllerColliderHit hit)を記述し、Rigidbody body = hit.collider.attachedRigidbody;を取得します。bodyがnullまたはキネマティックの場合、あるいはhit.moveDirection.y < -0.3fの場合(足元にボールがある場合)は、returnします。body.linearVelocityを、y成分を0にした歩行方向にkickPowerを掛け、さらにVector3.up * liftを加えた値に設定します。
「プレイ」を押して赤いボールに向かって歩きます。ボールが前方上方へ飛びます。その後、「確認」を押します。
自分で試してみよう
using UnityEngine;
public class Kicker : MonoBehaviour
{
public float kickPower = 6f;
public float lift = 4f;
// プレイヤーがぶつかったボールを蹴る
}
本格的なゲームを作るのすべてのレッスン
自分で練習してみよう: Unityプレイグラウンド