How do I keep my movement speed constant when moving against colliders?

I am making a top-down game with standard left, right, up, down, and 45-degree diagonal movement. My movement vector is normalized via inputMovementVector.Normalize(). I am also changing velocity directly in order to move the player: playerRigidbody.velocity = playerMovement. Moving diagonally when not moving against a collider is the same speed as moving vertically or horizontally.

When moving against a collider, such as moving right and coming into contact with a wall, and then pressing up or down to move along the wall vertically, the character slows down to about half the speed. Also, when moving against a diagonal collider, my characters moves diagonally automatically along the diagonal collider, which is my desired behavior, but also at half the speed.

This is fixable in a hack-y way, such as changing speed when in contact with a collider and during such an event, but there should be a better way to do this. Is there something that I am missing that will easily resolve this issue? Maybe something to do with the player’s Rigidbody or another way of moving the player?

Add a physics material and set the friction to 0

3 Likes

You just saved me from a bunch of unnecessary work! Thank you!

EDIT: It works for the most part. It is still slower, but much improved.

1 Like

No problem

Do you know what else may be slowing down movement? Both the wall and the character have 0 friction Physics2D Material. When checking velocity, normal speed should be 200, but I get 141 along a non-diagonal wall.

Well there is a wall and you are pressing up against it, so I would say Physics is happening.

2 Likes

Haha, thanks, I know. Perhaps this is just what will happen when using Unity Physics.

But perhaps someone else has an idea or ran into a similar problem before?

If you’re setting the velocity directly along the surface tangent then Box2D won’t affect this as there’s no opposing force. If you’re just setting the velocity directly which directs the body/collider(s) into another collider then impulse-forces will be used to stop them from colliding.

Box2D uses impulse forces to stop the objects colliding (instead of magic). :wink:

These forces will obviously affect the velocity. Without this, if you were pushing against a collider, it’d go straight through. Know that by modifying the velocity directly, you’re stomping on Box2Ds solution to the collisions but in the end, whatever works for what you’re doing.

1 Like

Thanks for the detailed explanation, MelvMay.

What does Unity consider optimal for movement when physics effects are not desired? Would it still be using forces via Rigidbody2D.AddForce, or transform.Translate, or setting the velocity directly?

Depends what you’re referring to when you say ‘physics effects’. I can only guess you mean that you don’t want the physics system to produce a collision response but you want to do that yourself instead?

If so, how you move an object has no bearing on it. Kinematic bodies can only be moved by setting the transform directly or setting their velocity direction. Dynamic bodies (non-kinematic) should never have their transform set and you should use forces to move them although you can directly modify the velocity if you know what you’re doing. Static bodies should never be moved.

If you don’t want collision response then you must set the appropriate colliders to be triggers.

1 Like

I see what you mean - basic collision is physics in itself, so I am generating physics by having rigidbodies, colliders, and collisions between them.

What I meant by “physics effects” are effects that go beyond basic collision and having dynamic bodies. So things like something getting blown up and its pieces flying around, or playing with gravity effects, or even objects being nudged by moving against them. I do like the directness and ease of having rigidbodies and box/polygon/circle/edge colliders to handle my collisions, and access to functions that work with Physics2D like Physics2D.OverlapCircle, etc.

In such a case, why should I use forces? What can happen if I set the velocity manually? Why the recommendation to use forces?

The physics system uses forces to modify the velocity of bodies. It does this to apply gravity and to stop colliders overlapping. By modifying the velocity directly, you’re potentially stomping over what it is doing.

You can be safer and just take the current velocity, modify it and then write it back so you don’t overwrite the velocity that contains changes coming from the physics system but this is just what adding an impulse force is doing i.e. change the velocity immediately (scaled by the inverse-mass).

As an example, if I were to set the linear velocity of an object so that it caused the object to move either left or right, no matter what you set the world gravity to, the 2D physic system would update the velocity but you’d then stomp over it.

Another example might be you setting the velocity in a direction that would cause an overlap with another collider. The physics system would apply an impulse which changed the velocity to move it out of the overlap (although this often doesn’t happen in a single physics update) and you’d then stomp over the velocity. This would be ‘seen’ as colliders ‘jittering’ in/out of walls and other effects. Note that this wouldn’t happen if you used continuous collision detection.

When you apply a non-impulse force, it doesn’t get applied immediately. It’s added to the total custom force until the next physics update, at which point it’s then applied for that time-step (scaled by the inverse-mass). This means it works in harmony with other forces that the physics system applies to solve the simulation.

You can use impulse forces which do modify the velocity immediately and can conceivably cause similar problems; the difference of course is that the force is adding to the current velocity and doesn’t directly overwrite it.

Of course, you can modify the velocity and do what you want because you may not be interested in gravity or your collisions may be simple detection set-ups but if you do so, don’t expect simulations where it matters to work correctly such as stacked objects under gravity etc.

In conclusion; if you want to modify the velocity then try to do so and see if you get problems. If you don’t then all is well. If not then try to not overwrite the velocity but instead modify it in a way that ensures you’re taking into account its current value by doing so directly or indirectly by using forces.

1 Like

Thanks for the thorough explanation, MelvMay. I will bookmark this thread for future reference as it is very helpful.

I think that I will switch to using forces just in case, with just enough linear drag to avoid getting that sliding effect and excessive acceleration. I’m assuming that I can reduce the sliding to pretty much zero with a high enough linear drag value. Is this the way to go to reduce that sliding effect?

If you want things to change direction instantly rather than slowly decelerate which is what I presume you’re talking about when you say ‘sliding’ then just use a force high enough to stop the object instantly (or quickly).

A non-impulse force changes the velocity using the following formula(during the physics update):

vel += (elapsed-time * force * 1/mass)

An impulse force changes the velocity using the following formula (when you call it):

vel += (force * 1/mass)

The only difference is that an impulse force is applied immediately and that it isn’t integrated (scaled) by any time-slice because it’s an ‘instant’ impulse force.

Given the above you could easily calculate a force that modifies the velocity in a certain way such as stopping horizontal movement or reversing direction.

1 Like

When you say “use a force high enough to stop the object instantly (or quickly),” what “force” or method are you referring to? Is this Rigidbody2D.AddForce? Or are you referring to Rigidbody2D.drag, which a high value nearly instantly stops the sliding?

Thanks for the formulas. Are these and others documented anywhere?

Using Rigidbody2D.AddForce instead of changing velocity directly via Rigidbody2D.velocity introduces a new problem: sub-pixel movement, or non-integer/non-whole number movement. Basically, the game object’s transform.position often show that it is in a decimal position. Because this is a pixel art game, non-integer positions may be a problem. Should I assume this?

I’m assuming that with the way forces work, the force interpolates and moves the game object at non-int/whole number values. There’s a quick hack in transforming the game object’s position at every Update frame to a nearest int value, but it seems to me like it would be better to prevent such non-int movement in the first place. Is this possible to do while using Rigidbody2D.AddForce? I can’t seem to find an answer to this particular question.