Unity용 리지드바디 기반 유성 플레이어 컨트롤러

플레이어 컨트롤러를 생성할 때 중력은 일반적으로 아래쪽 한 방향으로만 적용됩니다.

하지만 중심점이 있는 중력은 어떻습니까? 이것은 행성 워커의 직업입니다.

유성 보행기(Planetary Walker)는 플레이어가 구형 물체(행성과 마찬가지로) 위를 걸을 수 있게 해주는 컨트롤러 유형으로, 무게 중심은 구의 중심에 있습니다.

단계

다음은 무게 중심이 Unity인 행성 강체 보행기를 만드는 단계입니다.

  • 원형 레벨로 장면을 엽니다(제 경우에는 장면에 맞춤 제작된 행성 모델과 맞춤 스카이박스가 있습니다)

  • 새 스크립트를 만들고 이름을 "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);
        }
    }
}
  • 새로운 GameObject를 생성하고 호출합니다. "Player"
  • 새 캡슐을 만들고 "Player" 개체 내부로 이동한 후 위치를 (0, 1, 0)으로 변경합니다.
  • 캡슐에서 Capsule Collider 구성요소를 제거합니다.
  • Main Camera를 "Player" 객체 내부로 이동하고 위치를 (0, 1.64, 0)으로 변경합니다.
  • SC_RigidbodyWalker 스크립트를 "Player" 개체에 연결합니다(Rigidbody 및 Capsule Collider와 같은 추가 구성 요소가 추가된다는 것을 알 수 있습니다).
  • 캡슐 충돌기 높이를 2로 변경하고 중심을 (0, 1, 0)으로 변경합니다.
  • SC_RigidbodyWalker의 플레이어 카메라 변수에 메인 카메라 할당
  • 마지막으로 attach SC_PlanetGravity 스크립트를 "Player" 개체에 연결하고 행성 모델을 Planet 변수에 할당합니다.

재생을 누르고 플레이어가 행성 표면에 정렬되는 것을 관찰합니다.

Sharp Coder 비디오 플레이어