Gravity randomly does not work
I'm trying to do a third person player movement script using a CharacterController. Ground movement seems good, as does the rotation of the character and camera. However, the ability to jump has plagued me with headaches for days now. I don't know if the gravity just randomly refuses to work (sometimes it takes up to 5 minutes for gravity to "kick in") or if the jumping itself is bugged. It seems more likely to act up when I modify terrain or place new objects in the world.
My script code is as follows, minus a few details unrelated to the problem. It's not shown here, but the Jump function is triggered by an animation event in the jump animation. The character squats first, before it jumps. Additionally, the raycast in FixedUpdate was suggested by my teacher, but I don't see any difference in behavior. My problem seems to be beyond his scope, though.
A bit of a disclaimer: this is not part of my original lesson, which is a top-down twin stick shooter that I went ahead and turned into an almost full-fledged third person shooter because I wanted to challenge myself further. My teachers encourage me to add my own take on lessons, and for the most part, this works just fine. It's only the jump behavior that I'm having difficulty with. Additionally, the ConsoleReadyBehaviour this inherits from is simply an abstract class extending MonoBehaviour to add a few things unrelated to this problem that I wanted all my components to have.
Also, my apologies if the code seems mashed together. The question editor seems to strip away blank lines.
using UnityEngine;
public class PlayerController : ConsoleReadyBehaviour
{
[Header("Movement Physics")]
public float turnSpeed = 10f;
public float jumpStrength = 1f;
public float moveSpeedMultiplier = 2f;
public float gravityScale = -3f;
public float groundDistanceFactor = 10f;
Animator animator;
Quaternion freeRotation;
Vector3 controllerVelocity;
Vector3 input;
CharacterController controller;
float moveSpeed = 0f;
float velocity;
void Awake()
{
animator = GetComponent<Animator>();
controller = GetComponent<CharacterController>();
}
void Rotate()
{
Vector3 forward = Camera.main.transform.TransformDirection(Vector3.forward);
forward.y = 0f;
if (input.z < 0f) forward = -forward;
Vector3 targetDirection = input.x * Camera.main.transform.TransformDirection(Vector3.right) + input.z * forward;
bool movement = input != Vector3.zero && targetDirection.magnitude > 0.1f;
if (movement || Input.GetAxis(GameManager.FIRE_1) == 1f)
{
if (movement)
{
Vector3 lookDirection = targetDirection.normalized;
freeRotation = Quaternion.LookRotation(lookDirection, transform.up);
}
else // fire button
freeRotation = Quaternion.LookRotation(Camera.main.transform.forward, transform.up);
float rotationDifference = freeRotation.eulerAngles.y - transform.eulerAngles.y;
float eulerY = transform.eulerAngles.y;
if (rotationDifference < 0f || rotationDifference > 0f) eulerY = freeRotation.eulerAngles.y;
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(new Vector3(0f, eulerY, 0f)), turnSpeed * Time.deltaTime);
}
}
private void FixedUpdate()
{
if (controllerVelocity.y < 0f)
if (Physics.Raycast(transform.position, -Vector3.up, out _, groundDistanceFactor))
controllerVelocity.y = 0f;
}
void Move()
{
controllerVelocity = controller.velocity;
moveSpeed = Mathf.Clamp(/*input.x + */input.z, -1f, 1f);
moveSpeed = Mathf.SmoothDamp(animator.GetFloat(GameManager.SPEED_HASH), moveSpeed, ref velocity, 0.1f);
animator.SetFloat(GameManager.SPEED_HASH, moveSpeed);
input.z = Mathf.Abs(input.z); // no moonwalking!
controller.Move(freeRotation * input * moveSpeed * moveSpeedMultiplier * Time.deltaTime); // apply movement
if (Input.GetMouseButtonDown(2)) animator.SetTrigger(GameManager.JUMP_HASH);
controllerVelocity.y += Physics.gravity.y * Time.deltaTime;
controller.Move(controllerVelocity * Time.deltaTime); // apply the gravity
}
void Update()
{
input = new Vector3(Input.GetAxis(GameManager.HORIZONTAL), 0f, Input.GetAxis(GameManager.VERTICAL));
Rotate();
Move();
}
public void Jump()
{
controllerVelocity.y += Mathf.Sqrt(jumpStrength * gravityScale * Physics.gravity.y);
controller.Move(controllerVelocity * Time.deltaTime);
}
}