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?
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.
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).
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.
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.
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.
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.
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.