Movement Controller - 3D Space Arcade - Speed Bug

Hey, first time poster!

I’m working on a 3D Space Arcade Game and I’ve been having a lot of fun but I’ve run into my first real mental roadblock.

To get the feel I want whilst using the physics system I’ve written the code at the bottom of this post and I would like to point out that I’m new to coding so if you look at this and are horrified I’m truly sorry! XD

My problem is I’m getting a fluctuation of +/- 1 magical unity unit of Vector3.Magnitude which I’m using for speed. Now I did my due diligence and my research into the issue would suggest that using rb.velocity and AddForce isn’t best practice and can lead to issues like this.

I’ve been through the documentation, i’ve found things like Lerp and SmoothDamp but these seem to relate to transform/rb.velocity than addForce. I guess what im asking is whats the best way to fix this?

Should i use transform instead? i’ve read it causes issues when collisions are involved.

Thanks in advance!

void HandleThrottle()
{
    // relevant variables - thrust1D, throttlePosition, throttleIncriment


    if (thrust1D > 0.1f)
    {
        throttlePosition = throttlePosition + throttleIncrement;
        throttlePosition = Mathf.Clamp(throttlePosition, maxReverseThrottle, maxThrottle);
        //UnityEngine.Debug.Log("Throttle Position" + throttlePosition);
    }
    else if (thrust1D < -0.1f)
    {
        throttlePosition = throttlePosition - throttleIncrement;
        throttlePosition = Mathf.Clamp(throttlePosition, maxReverseThrottle, maxThrottle);
        //UnityEngine.Debug.Log("Throttle Position" + throttlePosition);
    }
    else if (throttleCentre != 0)
    {
        throttlePosition = 0f;
    }

    speed = Vector3.Magnitude(rb.velocity);
    int speedFloor = (int)Mathf.Floor(Mathf.Abs(speed));
    UnityEngine.Debug.Log("Speed:" + speedFloor);


    if (throttlePosition >= 0.1f && !boosting && speedFloor <= maxSpeed)
    {
        rb.AddRelativeForce(Vector3.forward * thrust * Time.deltaTime);
        Vector3 clampedVelocity = Vector3.ClampMagnitude(rb.velocity, maxSpeed);
        rb.velocity = clampedVelocity;
    }

    if (throttlePosition <= -0.1f && !boosting && speedFloor <= maxReverseSpeed)
    {
        rb.AddRelativeForce(Vector3.back * reverseThrust * Time.deltaTime);
        Vector3 clampedVelocity = Vector3.ClampMagnitude(rb.velocity, maxReverseSpeed);
        rb.velocity = clampedVelocity;
    }

    if (throttlePosition <= -0.1f && boosting && speedFloor <= maxReverseSpeed)
    {
        rb.AddRelativeForce(Vector3.back * reverseThrust * boostMultiplier * Time.deltaTime);
        Vector3 clampedVelocity = Vector3.ClampMagnitude(rb.velocity, maxReverseSpeed * boostMultiplier);
        rb.velocity = clampedVelocity;
    }

    if (throttlePosition >= 0.1f && boosting)
    {
        rb.AddRelativeForce(Vector3.forward * thrust * boostMultiplier * Time.deltaTime);
        Vector3 clampedVelocity = Vector3.ClampMagnitude(rb.velocity, maxSpeed * boostMultiplier);
        rb.velocity = clampedVelocity;
    }

    if (throttlePosition >= 0.1f && !boosting && speedFloor > maxSpeed)
    {
        rb.velocity -= rb.velocity.normalized * decelerationRate * Time.fixedDeltaTime;
    }

}

You don’t need to use Time.deltaTime when adding forces as it’s already used internally.

You have as many as 14 variables all just for controlling your ship’s velocity. I suggest you redo it and just start with a couple of variables and gradually add more complexity while testing as you go. Although ideally you should only need a throttle variable and a few lines of code.

using UnityEngine;

[RequireComponent(typeof(CharacterController))]
public class PlayerMovement : MonoBehaviour
{
    public float moveSpeed = 6f;            // Speed of movement
    public float rotationSpeed = 6f;       // Speed of rotation
    public float gravity = -9.81f;          // Gravity force
    public float jumpHeight = 1.5f;         // Height of the jump
    public Transform cameraTransform;       // Reference to the camera's transform

    private CharacterController controller;
    private Vector3 velocity;
    private bool isGrounded;

    void Start()
    {
        controller = GetComponent<CharacterController>();
    }

    void Update()
    {
        // Check if the player is grounded
        isGrounded = controller.isGrounded;

        if (isGrounded && velocity.y < 0)
        {
            velocity.y = -2f; // Reset the downward velocity when grounded
        }

        // Get input from WASD keys
        float moveX = Input.GetAxis("Horizontal");
        float moveZ = Input.GetAxis("Vertical");

        // Calculate movement direction relative to the camera
        Vector3 direction = cameraTransform.right * moveX + cameraTransform.forward * moveZ;
        direction.y = 0f; // Keep movement on the horizontal plane

        // Normalize the direction vector to prevent faster diagonal movement
        if (direction.magnitude >= 0.1f)
        {
            // Move the player
            controller.Move(direction.normalized * moveSpeed * Time.deltaTime);

            // Smoothly rotate the player towards the movement direction
            Quaternion targetRotation = Quaternion.LookRotation(direction);
            transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
        }

        // Handle gravity
        velocity.y += gravity * Time.deltaTime;
        controller.Move(velocity * Time.deltaTime);

        // Jumping (optional)
        if (Input.GetButtonDown("Jump") && isGrounded)
        {
            velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
        }
    }
}

Just attach it to the player and get rid of the old movement script