- Home /
rigidbody2d.AddForceAtPosition Doesn't Add Horizontal Movement?
I have a simple rigidBody2D object in my scene. When I click on the screen I do a ray cast from the bottom of the screen to the top at the x-position of where my mouse click was. If the ray cast hits the rigidbody then the rigidBody does this:
rigidbody2D.AddForceAtPosition(Vector2.up * 100.0f, impactPoint);
Where impactPoint is the point where the ray cast hit the collider. What I want is this to act like a bullet was fired straight upwards, hitting the rigidBody and imparting velocity and angular velocity on it. So when the ray cast hits the far right edge of the collider I want the rigidbody to move upwards, to the left, and to spin counter-clockwise.
However the actual result of AddForceAtPosition is just that the object moves perfectly straight upwards and starts spinning around its center.
Why isn't the rigidbody moving to the left or right? Is AddForceAtPosition not able to simulate being hit by a very small, very fast traveling object?
Answer by gfoot · Mar 29, 2014 at 10:45 PM
If you apply an upwards force, then the body will only move upwards. If you want it to move sideways you need to apply a sideways force as well. The "at position" bit doesn't change this, it just make it add a torque as well.
In reality the end result of this kind of collision depends hugely on the bounce angle of the bullet, assuming it bounces off at all. It's probably not worth you worrying about the maths though. You will probably get a good result if you calculate a normal vector from the bullet towards the target object, and apply an impulse to the target object in that direction, scaled by the dot product of the bullet's incoming velocity with this direction vector.
This will apply the maximum impulse when the bullet his the target squarely from below, with a sideways component if it doesn't hit it squarely, and the magnitude of the impulse will decay to zero as the bullet's impact gets more tangential.
Something like this:
var direction = (target.position - bullet.position).normalized;
var magnitude = MaxImpulse * Vector3.Dot(direction, bullet.rigidbody.velocity.normalized);
then apply an impulse of direction*magnitude.
$$anonymous$$y new code looks like this:
var direction = ((Vector2)transform.position - impactPoint).normalized;
var magnitude = 100.0f * Vector2.Dot(direction, Vector2.up);
rigidbody2D.AddForceAtPosition(direction * magnitude, impactPoint);
The effect is close to what I want now, except now I lost the torque!
Another side-effect is that with a rectangular object that is wider than it is tall then sometimes if I hit a far edge I get a downwards force?
Yes, I assumed your targets were circular.
Generally the direction should be the surface normal at the contact point, for a perfect bounce with no friction. This will also cause torques again, for non-circular objects, which it sounds like you do want.
The other thing that will cause torque is if you add a vertical frictional force to whatever you calculate, maybe just a constant one.
Generally the direction should be the surface normal at the contact point, for a perfect bounce with no friction. This will also cause torques again, for non-circular objects, which it sounds like you do want.
@gfoot I would like both angular and linear velocity imparted on the collided object. Not just one or the other.
The other thing that will cause torque is if you add a vertical frictional force to whatever you calculate, maybe just a constant one.
How do I implement this?
To begin with, for non-circular shapes use the surface normal vector from the RayCastHit2D object ins$$anonymous$$d of calculating a vector from the hit point towards the object's centre. That will fix the problem with the downward force, and might give the effect you're looking for.
Then on top of that experiment with adding an additional force upwards at the contact point - play with the magnitude of this force and see if it helps you achieve the result you want.
var direction = -rayCastHit.normal;
var magnitude = 100.0f * Vector2.Dot(direction, Vector2.up);
rigidbody2D.AddForceAtPosition(direction * magnitude + ConstantUpwardsForce * Vector2.up, impactPoint);
Start with ConstantUpwardsForce set to zero, get a feel for the behaviour, then start increasing it and see if you like the result better.
Your answer
Follow this Question
Related Questions
Continuously moving rigidbody 2 Answers
Rotating my character only while moving in a 2D plane 3 Answers
where to trigger which collision event? 1 Answer
How do I make this kind of follow script? 1 Answer
Spinning rigidbody platform in 2D 0 Answers