I’m trying to wrap my head around Collider2D.normalImpulse. If I understood correctly (provably not) this value is the linear impulse the rigidbody recieves in the collision. This linear impulse could then be added to the velocity to solve the collision. But I’m getting way too high values for this to make sense.
using UnityEngine;
static class PhysicsUtils
{
public static Vector2 computeUniformlyAcceleratedMovement(Vector2 position, Vector2 velocity, Vector2 accelerated, float time) =>
position + velocity * time + 0.5f * accelerated * time * time;
public static Vector2 computeAcceletaredVelocity(Vector2 velocity, Vector2 accelerated, float time) =>
velocity + accelerated * time;
}
When I hit play, the green circle falls to the floor and rests there. The red circle falls on top of the green one and I would expect it to lay there (which is what happens when both circles are dynamic and the physics engine handles the whole situation). But instead it recieves an upward velocity of over 400 and shoots high in the sky.
Could somebody shed some light about the meaning of normaImpulse? Is it possible to solve Kinemic vs dyamic collisions with this approach?
It seems normalImpulse is always zero when using a kinematic rigidbody2D. Also, the physics engine doesn’t simply add the normal and impulse to the velocity because if it did then everything would fly apart upon contact. The bounce settings will partly determine how the velocity is changed.
What’s likely happening with your circles is that the green circle is being pushed back out of the ground and generating contacts with the red circle and your script is applying the green circle’s contact normal and impulse to the red circle’s velocity.
As far as I can tell, normlaImpulse is 0 when a kinematic hits a static or another kinematic (or colliders without a rigidbody). Of course, only when “Use full kinematic contacts” is ticked, otherwise the collision doesn’t even register. But when hitting a dynamic normlaImpulse can be non-zero. I added an OnEnterCollision2D to test it in my test component:
As stated, I’m a bit lost about the meaning of normalImpulse (I thought it could be interpreted as a speed differential), so if anyone has some directions that would be super useful.
I attach my test project in case it helps at all. PhysicsTest.zip (105.6 KB)
Normal Impulse is the impulse the solver applies to the contact point along the collision normal to keep things separated i.e it’s part of the contact constraint and informs you of what impulse the solver applied. It’s an impulse meaning it’s the force scaled by the time-step.
These impulses are applied to any Dynamic body involved in a contact. Obviously Static and Kinematic bodies don’t have forces/impulses applied to them by definition.
So, since normalImpulse is a force by time, If I want my Kinematic red ball to react to the collision with the Dynamic green ball the same way both were dynamic, how should I go about it?
Should I extract the acceleration by dividing by time-step (let’s assume both balls have a mass is 1 for now) and apply an uniformly accelerated movement in the normal direction for a time-step duration?
Can I assume time-step is equivalent to Time.fixedDeltaTime?
You’ll not get the exact same behaviour as Dynamic because velocity changes are only one part of what the solver does. Per-contact impulses also affect rotation alongside the friction impulse, then there’s position adjustment etc.
Time-step is whatever the simulation step is so if the scene is automatically simulated using fixed-update then yes, use “Time.fixedDeltaTime”, if update then “Time.deltaTime” or manually via script then whatever you pass in there. You absolutely must scale the impulse by the time-step though.
Be aware though that you’ll be missing important things such as sleeping so you should be cautious about issue MovePosition if you’re not actually going anywhere.
So I just took a quick look at your code and yes, just scale those impulses by “Time.fixedDeltaTime”.
Note though that your “OnCollisionEnter2D” reports after the simulation has run which is after your previous MovePosition and that FixedUpdate runs before the simulation. Just ensure you don’t get those confused.
You should always refer to the Rigidbody2D.position NOT the Transform.position as the source of truth on position
Unlike 3D physics, in 2D you can directly write the linear velocity of a Rigidbody2D to cause movement. You don’t need to use MovePosition. You can use this to store the current velocity.
I see, it’s a more involved process than I assumed. I’m trying to manually replicate the dynamic collision reaction behavior so that my red kinematic ball stays on top of the green dynamic one instead of pushing it out of the way and falling through the floor. This is just an experiment to allow me to understand how to handle kinematic VS dynamic collisions using Unity simulation data (rather than trying to solve it my own cumbersome way), and I though this scenario would be the simplest one to begin with (I used balls so I can ignore rotation and one falling right on top of another to ignore friction).
Thanks a lot for taking the time to check this sample so thoroughly @MelvMay, I learnt a lot of interesting stuff. It still doesn’t work just like the dynamic VS dynamic solution (as expected, since you already mentioned there is more to it than just impulses), but it’s much closer. This has been on my mind for quiet a while.
Yes, It looks credible but it’s much bouncier than when setting the red circle as dynamic (which in this specific scenario doesn’t bounce in any visible way). I’ll need to dig deeper before trying something more complex.
Of course. I’m working on a player controller that needs to be able to push dynamic boxes (for physics-based puzzle-platforming shenanigans). It’s a substantially more complex target than this simple experiment but I need to get the basics right. I want to make it kinematic so I can have as much control over the player movement as possible. I still can’t rule out switching to a dynamic controller, but it would be quiet a setback.
What is it about a Dynamic body you don’t have control over? I’m just ensuring you’re not participating in the myth that a Dynamic body doesn’t give you control!
Hard to know the details but you can always use a Dynamic body then after the simulation step, modify where the body pose or something else so use those results to essentially get what the solver decided and then do whatever with it.
It sound like it all comes down to what you’re loosing by using Dynamic.
Hmmm… it has been a while since I tried the dynamic controller approach. There were many problems I remember being able to overcome in rather hacky ways (such as making the player stand still in a slope). But I also remember having problems with the collide&slide movement (mainly not being able to stop at the exact collision point in a slope).
Then again, it’s not like a kinematic character controller doesn’t come with its own set of challenges.
Perhaps you’re right regarding the idea of having an attached dynamic rigidbody drive the interactions with other dynamic objects, although I’m a bit worried about being able to stay in sync. It’s worth giving it a shot, nonetheless.
Thanks a lot for your help @MelvMay, it was really interesting.