Thruster-Style Movement With "Soft" Speed Limit

I’m trying to create a script that moves a Rigidbody2D in a way similar to thrusters moving a spaceship. A 2D one, anyway. I’ve successfully implemented most of the features I want, but the “soft” speed limit still eludes me.

By soft speed limit, I mean a speed that the Rigidbody2D will never reach through thrust alone. Note that this isn’t a “hard” speed limit. I can’t just clamp the rb.velocity.magnitude, because then the rigidbody would never exceed the speed limit, even if acted upon by external forces (wind, tractor beams, etc.). This would impose unnecessary game design limitations. I also can’t turn off all thrust when velocity exceeds the speed limit, for obvious reasons. Once the rigidbody reached a certain speed, it would just drift endlessly, or until something slowed it down enough to start accepting input again.

This would be an easy problem to solve if, for instance, I limited movement to orthogonal directions. Is the rigidbody moving to the right too fast? Easy, just don’t allow thrust in the positive X direction. Too fast downward? Don’t allow thrust in the negative Y direction. And so on.

But I want movement in any direction. What happens if the rigidbody is moving too fast on a vector of (0.2, 0.8)? Just prevent thrust in that exact direction? That’s basically useless, because a joystick user could input a vector just a few degrees off from that, continue accelerating in approximately the same direction, and easily exceed the speed limit.

Hopefully some of this makes sense to someone. I don’t need anyone to write my code for me. If you could direct me to some helpful examples, point out some obvious vector math I’m missing, or just give general advice, I’d greatly appreciate it.

Maybe it’s just me but you don’t actually explain what you mean by “soft”. You actually just say it’s not “hard” which really doesn’t explain it. So “I mean a speed that the Rigidbody2D will never reach through thrust alone” is also confusing.

I’m not following why you are discussing specific velocties (directions) when you seem to be talking about the speed (velocity magnitude) only. Maybe you mean gradually reducing the forces you apply as you get closer to the limit (speed)? You can create a function that scales the force you apply so that it’s zero as the speed is approximately at its max so you get less force as you approach the limit.

While the velocity exceeds your limit, you could apply a force of (-rb.velocity * the_difference_in_magnitude_between_current_velocity_and_your_limit * how_fast_you_want_it_to_happen).

Edit: or something like that :stuck_out_tongue:

Sorry about the confusion. It was a tough concept to explain in words and I didn’t do a great job. I was able to get the code below working, though. My ship’s thrust force decreases as it approaches the speed limit, so that, again, it never exceeds the speed limit through thrust alone. But because I’m not directly clamping the velocity magnitude, external forces can still act on it freely.

accelerationForce and speedLimit are both serialized floats. baseForce is a readonly float currently set at 500. It’s included in calculations so that the developer doesn’t need to input big values in the editor just to get noticeable acceleration.

    private void Move(Vector2 inputDirection)
    {
        Vector2 moveDirection = inputDirection;

        if (useSpeedLimit)
        {
            Vector2 oppositeDirection = -1 * rb.velocity.normalized;
            float speedToLimitRatio = rb.velocity.magnitude / speedLimit; //how close we currently are to the speed limit
            moveDirection += oppositeDirection * speedToLimitRatio;
        }

        rb.AddForce(moveDirection * accelerationForce * baseForce * Time.deltaTime);
    }
1 Like