Is there a simple way to clamp the maximum movement speed of a physics object?
I’m making a simple “Asteroids” game and I want full freedom of the ship to float around with whatever force is applied with no friction or dampening, however, naturally when force is continually applied the object will quickly reach game breaking speeds and I just want to cap this to something reasonable.
This example seems like a good start:
Instead of reducing velocity by 10%, you would reduce it by however much you need to reach the cap you set. The example is a collision, so I suppose you would need to modify it further. E.g. apply a force in the opposite direction of current velocity to offset.
Thank you but I just simply want to cap the max speed, not apply an opposing force - a speed cap is simple and direct to the point and doesn’t open up any room for error. I can just program my own velocity and adjust the position myself and cap my own speed that way but I just thought the would be a speed cap somewhere in the physics settings. If there isn’t then I’ll move the object myself, no issue. Just didn’t want to reinvent the wheel.
And although that will work for this game, I want to avoid doing that on principal because it means I circumvent the benefits of the advanced physics system such as fine detailed collisions with rotated shapes and angular velocity.
Perhaps you can use b2d.body.set_linear_velocity()?
Get the velocity first, adjust the length, then set it back.
Thank you, I was thinking this sort of thing might be the solution, I’m going to try that.
This works perfectly, thank you! I didn’t know about the b2d API.
Here’s what I came up with, for anyone else’s benefit;
- First you need to be able to get the “b2b body” of the collision, something like this;
self.body = b2d.get_body("#collision")
- Then you need a handy function to clamp the velocity (I put this in a utility module)
function M.clamp_vector_length(v, max_length)
local length = vmath.length(v)
if length > max_length then
-- Normalize the vector and scale to max_length
return vmath.normalize(v) * max_length
else
-- Return the vector as is if within the limit
return v
end
end
- in your update or fixed_update, you want to apply the clamping after you’ve done all your other movement code;
local speed = b2d.body.get_linear_velocity(self.body)
speed = util.clamp_vector_length(speed, MAX_SPEED)
b2d.body.set_linear_velocity(self.body, speed)
As a side note, using a dynamic physics simulation might not be the right fit for an asteroids style game.
If you don’t need realistic bouncing or sliding, it would be simpler to use go.set_position() and go.animate() to move the game objects, instead of trying to make dynamic objects act in a non-physical way.
If it does have to be dynamic, I’d suggest tweaking linear and angular damping properties of the collision object instead of trying to control the velocity with code.
Thanks - that’s what I normally would’ve done, but I’m trying to turn over a new leaf and not “do everything myself”, my last project took 100 times longer than it should’ve when I could’ve used the features of the Unity engine.
Maybe this is why the physics engine doesn’t have a speed cap built in, and I should just do my own velocity. I’ll keep it in mind to re-do it at some point but it’s working now for the prototype.
I hear you! I’m on the same path myself.
Box2D does have an upper limit for velocity, but it’s really high and not configurable as fr as I know.
For future reference, if you were to dabble in dynamic physics again, a speed cap can be set by using the linear and angular damping properties, and move the object with impulses. It takes a little time getting it right, but for some game types this is a good approach.
Thanks, that also sounds like a good idea, I’ll keep that in mind.