Hoy haremos que nuestro Character Controller se deslice por cuestas tal y como decidisteis en la votación del video anterior!
Aprenderemos a detectar el ángulo de la pendiente y a deslizarnos mas o menos deprisa dependiendo del mismo.
Espero que os sirva de ayuda y que las explicaciones sean lo suficientemente claras para que podáis implementarlo en vuestros proyectos.
No te lo pierdas la serie y aprende a crear tus propios videojuegos con el motor Unity 3D y aprendamos juntos el maravilloso arte del desarrollo de videojuegos.
Script PlayerController:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
//Variables movimiento
float horizontalMove;
float verticalMove;
private Vector3 playerInput;
public CharacterController player;
public float playerSpeed;
public float gravity;
public float fallVelocity;
public float jumpForce;
//Varaibles movimiento relativo a camara
public Camera mainCamera;
private Vector3 camForward;
private Vector3 camRight;
private Vector3 movePlayer;
//Variables deslizamiento en pendientes
public bool isOnSlope = false;
private Vector3 hitNormal;
public float slideVelocity;
public float slopeForceDown;
// Cargamos el componente CharacterController en la variable player al iniciar el script
void Start()
{
player = GetComponent<CharacterController>();
}
// Bucle de juego que se ejecuta en cada frame
void Update()
{
//Guardamos el valor de entrada horizontal y vertical para el movimiento
horizontalMove = Input.GetAxis("Horizontal");
verticalMove = Input.GetAxis("Vertical");
playerInput = new Vector3(horizontalMove, 0, verticalMove); //los almacenamos en un Vector3
playerInput = Vector3.ClampMagnitude(playerInput, 1); //Y limitamos su magnitud a 1 para evitar aceleraciones en movimientos diagonales
CamDirection(); //Llamamos a la funcion CamDirection()
movePlayer = playerInput.x * camRight + playerInput.z * camForward; //Almacenamos en movePlayer el vector de movimiento corregido con respecto a la posicion de la camara.
movePlayer = movePlayer * playerSpeed; //Y lo multiplicamos por la velocidad del jugador "playerSpeed"
player.transform.LookAt(player.transform.position + movePlayer); //Hacemos que nuestro personaje mire siempre en la direccion en la que nos estamos moviendo.
SetGravity(); //Llamamos a la funcion SetGravity() para aplicar la gravedad
PlayerSkills(); //Llamamos a la funcion PlayerSkills() para invocar las habilidades de nuestro personaje
player.Move(movePlayer * Time.deltaTime); //Y por ultimo trasladamos los datos de movimiento a nuestro jugador * Time.deltaTime
//De este modo mantenemos unos FPS estables independientemente de la potencia del equipo.
//Debug.Log("Tocando el suelo: " + player.isGrounded); //Descomenta esta linea si quieres monitorizar si estas tocando el suelo en la consola de depuracion
}
//Funcion para determinar la direccion a la que mira la camara.
public void CamDirection()
{
//Guardamos los vectores correspondientes a la posicion/rotacion de la carama tanto hacia delante como hacia la derecha.
camForward = mainCamera.transform.forward;
camRight = mainCamera.transform.right;
//Asignamos los valores de "y" a 0 para no crear conflictos con otras operaciones de movimiento.
camForward.y = 0;
camRight.y = 0;
//Y normalizamos sus valores.
camForward = camForward.normalized;
camRight = camRight.normalized;
}
//Funcion para las habilidades de nuestro jugador.
public void PlayerSkills()
{
//Si estamos tocanto el suelo y pulsamos el boton "Jump"
if (player.isGrounded && Input.GetButtonDown("Jump"))
{
fallVelocity = jumpForce; //La velocidad de caida pasa a ser igual a la velocidad de salto
movePlayer.y = fallVelocity; //Y pasamos el valor a movePlayer.y
}
}
//Funcion para la gravedad.
public void SetGravity()
{
//Si estamos tocando el suelo
if (player.isGrounded)
{
//La velocidad de caida es igual a la gravedad en valor negativo * Time.deltaTime.
fallVelocity = -gravity * Time.deltaTime;
movePlayer.y = fallVelocity;
}
else //Si no...
{
//aceleramos la caida cada frame restando el valor de la gravedad * Time.deltaTime.
fallVelocity -= gravity * Time.deltaTime;
movePlayer.y = fallVelocity;
}
SlideDown(); //Llamamos a la funcion SlideDown() para comprobar si estamos en una pendiente
}
//Esta funcion detecta si estamos en una pendiente muy pronunciada y nos desliza hacia abajo.
public void SlideDown()
{
//si el angulo de la pendiente en la que nos encontramos es mayor o igual al asignado en player.slopeLimit, isOnSlope es VERDADERO
isOnSlope = Vector3.Angle(Vector3.up, hitNormal) >= player.slopeLimit;
if (isOnSlope) //Si isOnSlope es VERDADERO
{
//movemos a nuestro jugador en los ejes "x" y "z" mas o menos deprisa en proporcion al angulo de la pendiente.
movePlayer.x += ((1f - hitNormal.y) * hitNormal.x) * slideVelocity;
movePlayer.z += ((1f - hitNormal.y) * hitNormal.z) * slideVelocity;
//y aplicamos una fuerza extra hacia abajo para evitar saltos al caer por la pendiente.
movePlayer.y += slopeForceDown;
}
}
//Esta funcion detecta cuando colisinamos con otro objeto mientras nos movemos
private void OnControllerColliderHit(ControllerColliderHit hit)
{
//Almacenamos la normal del plano contra el que hemos chocado en hitNormal.
hitNormal = hit.normal;
}
}
Descarga los archivos del proyecto aqui: Script


Podrias actualizar esto al nuevo input system!