Unity 用 Rigidbody ベースの Planetary Player コントローラー
プレーヤー コントローラー を作成する場合、重力は通常、一方向 (下方向) にのみ適用されます。
しかし、中心点がある重力についてはどうなるでしょうか? これはプラネタリーウォーカーの仕事だ。
プラネタリー ウォーカーは、プレーヤーが (惑星と同じように) 重心が球の中心にある球状のオブジェクトの上を歩くことを可能にするコントローラーの一種です。
ステップ
以下は、重心を Unity に持つ惑星剛体ウォーカーを作成する手順です。
- 円形レベルでシーンを開きます (私の場合、シーンにカスタムの惑星モデルとカスタム Skybox があります)
- という新しいスクリプトを作成し、"SC_RigidbodyWalker" という名前を付けて、その中に以下のコードを貼り付けます。
SC_RigidbodyWalker.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(CapsuleCollider))]
public class SC_RigidbodyWalker : MonoBehaviour
{
public float speed = 5.0f;
public bool canJump = true;
public float jumpHeight = 2.0f;
public Camera playerCamera;
public float lookSpeed = 2.0f;
public float lookXLimit = 60.0f;
bool grounded = false;
Rigidbody r;
Vector2 rotation = Vector2.zero;
float maxVelocityChange = 10.0f;
void Awake()
{
r = GetComponent<Rigidbody>();
r.freezeRotation = true;
r.useGravity = false;
r.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
rotation.y = transform.eulerAngles.y;
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
void Update()
{
// Player and Camera rotation
rotation.x += -Input.GetAxis("Mouse Y") * lookSpeed;
rotation.x = Mathf.Clamp(rotation.x, -lookXLimit, lookXLimit);
playerCamera.transform.localRotation = Quaternion.Euler(rotation.x, 0, 0);
Quaternion localRotation = Quaternion.Euler(0f, Input.GetAxis("Mouse X") * lookSpeed, 0f);
transform.rotation = transform.rotation * localRotation;
}
void FixedUpdate()
{
if (grounded)
{
// Calculate how fast we should be moving
Vector3 forwardDir = Vector3.Cross(transform.up, -playerCamera.transform.right).normalized;
Vector3 rightDir = Vector3.Cross(transform.up, playerCamera.transform.forward).normalized;
Vector3 targetVelocity = (forwardDir * Input.GetAxis("Vertical") + rightDir * Input.GetAxis("Horizontal")) * speed;
Vector3 velocity = transform.InverseTransformDirection(r.velocity);
velocity.y = 0;
velocity = transform.TransformDirection(velocity);
Vector3 velocityChange = transform.InverseTransformDirection(targetVelocity - velocity);
velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
velocityChange.y = 0;
velocityChange = transform.TransformDirection(velocityChange);
r.AddForce(velocityChange, ForceMode.VelocityChange);
if (Input.GetButton("Jump") && canJump)
{
r.AddForce(transform.up * jumpHeight, ForceMode.VelocityChange);
}
}
grounded = false;
}
void OnCollisionStay()
{
grounded = true;
}
}
- という新しいスクリプトを作成し、"SC_PlanetGravity" という名前を付けて、その中に以下のコードを貼り付けます。
SC_PlanetGravity.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SC_PlanetGravity : MonoBehaviour
{
public Transform planet;
public bool alignToPlanet = true;
float gravityConstant = 9.8f;
Rigidbody r;
void Start()
{
r = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
Vector3 toCenter = planet.position - transform.position;
toCenter.Normalize();
r.AddForce(toCenter * gravityConstant, ForceMode.Acceleration);
if (alignToPlanet)
{
Quaternion q = Quaternion.FromToRotation(transform.up, -toCenter);
q = q * transform.rotation;
transform.rotation = Quaternion.Slerp(transform.rotation, q, 1);
}
}
}
- 新しいゲームオブジェクトを作成して呼び出します "Player"
- 新しいカプセルを作成し、"Player" オブジェクト内に移動し、その位置を (0, 1, 0) に変更します。
- Capsule Collider コンポーネントをカプセルから削除します。
- メイン カメラを "Player" オブジェクト内に移動し、その位置を (0, 1.64, 0) に変更します。
- SC_RigidbodyWalker スクリプトを "Player" オブジェクトにアタッチします (これにより、Rigidbody や Capsule Collider などのコンポーネントが追加されることがわかります)。
- カプセル コライダーの高さを 2 に、中心を (0, 1, 0) に変更します。
- SC_RigidbodyWalker のプレーヤー カメラ変数にメイン カメラを割り当てる
- 最後に、attach SC_PlanetGravity スクリプトを "Player" オブジェクトに追加し、惑星モデルを Planet 変数に割り当てます。
[再生] を押して、プレーヤーが惑星の表面に揃うのを観察します。