Controlador de jugador planetario basado en cuerpo rígido para Unity

Al crear un controlador de jugador, la gravedad generalmente se aplica en una sola dirección, hacia abajo.

Pero, ¿qué pasa con la gravedad con un punto central? Este es un trabajo para el caminante planetario.

Un caminante planetario es un tipo de controlador que permite al jugador caminar sobre un objeto esférico (al igual que los planetas), con el centro de gravedad en el centro de la esfera.

Pasos

A continuación se muestran los pasos para hacer un andador planetario de cuerpo rígido, con un punto central de gravedad en Unity:

  • Abre la escena con tu nivel circular (en mi caso, tengo un modelo de planeta personalizado y un Skybox personalizado en la escena)

  • Crea un nuevo script, llámalo "SC_RigidbodyWalker" y pega el siguiente código dentro:

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;
    }
}
  • Crea un nuevo script, llámalo "SC_PlanetGravity" y pega el siguiente código dentro:

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);
        }
    }
}
  • Crea un nuevo GameObject y llámalo "Player"
  • Cree una nueva Cápsula, muévala dentro del objeto "Player" y cambie su posición a (0, 1, 0)
  • Retire el componente Capsule Collider de la cápsula
  • Mueva la cámara principal dentro del objeto "Player" y cambie su posición a (0, 1.64, 0)
  • Adjunte el script SC_RigidbodyWalker al objeto "Player" (notará que agregará componentes adicionales como Rigidbody y Capsule Collider).
  • Cambie la Altura del Colisionador de Cápsula a 2 y el Centro a (0, 1, 0)
  • Asigne la cámara principal a la variable Cámara del jugador en SC_RigidbodyWalker
  • Por último, adjunte el script SC_PlanetGravity al objeto "Player" y asigne su modelo de planeta a la variable Planet

Presiona Play y observa cómo el Player se alinea con la superficie del planeta:

Sharp Coder Reproductor de video