[Solved] Applying an impulse at an impact point

From the Asset Store
Connect the dots in the correct order and draw happy animals!
  • Hello,

    I want to apply an impulse to "sprite A" when "sprite B" collides with it. Object A has the behavior "Physics" but not object B.

    Here, "Sprite A" is the hitbox of an enemy and "sprite B" is a bullet fired by the player.

    An obvious solution would be to apply the physics bevavior to the two sprites, but this is unfotunatly not an option in my current project for other reasons. Only the enemy hitbox can have physics properties (in order to interact with other enemy hitboxes).

    When I want to apply an impulse with the "Physics" events, the impulse can only be applied at an image point. I dont find how to apply it at a custom point on a sprite (the impact point with the bullet).

    And last but not least, the hitbox is not a simple circle, the shape is more like a square. The impact point is also important because it will determine precisely how the "sprite B" will react to the impulse (angle, rotation, etc.).

    Basicaly, I want to simulate an impact between two "Physics" objects at a specific point, but ony the object which is hit can have the physics bevavior.

  • An easy solution could be to have an invisible and tiny Physics 'bullet' sprite pinned to the bullet at all times? So it will be a realistic Physics collision.

    If not that, then you can do it with a Bullet (non-Physics) and hitbox (Physics) by measuring the perpendicular distance from it's pivot (and/or center of gravity that you define) multiplying with a factor of bullet speed, which will give you the amount of 'Torque' that should be applied to the Physics object combined with (inversely proportional to distance) an impulse. This will require a lot of trials and errors. To save time, you can set up a repeating algorithm where you simply adjust the Torque factor and Impulse and perhaps compare it with an identical clones of two Physics objects to see which values match best to the real impact.

    I would personally go with the first option and make life simple.

  • You didn't specify the size of B, but if it can be thought of as very small it will make things simpler. Does B bounce too, or is it just getting destroyed?

    The first is to find the point of collision and the normal. Since B is small you can just use B's position when it overlaps A. The normal is a bit trickier, but you can find it with something like this. It assumes that A is a rectangle. It just find the closest edge on A and uses it's normal

    variable best=1000
    variable normal=0
    variable d=0
    variable a=0
    
    set best to 1000
    repeat 4 times
    -- set a to A.angle+90*loopindex
    -- set d to (loopindex%2=0)?A.width/2:A.height/2
    -- subtract (B.x-A.x)*cos(a)+(B.y-A.y)*sin(a) from d
    -- compare: d < best
    ---- set best to d
    ---- set normal to a

    So the next part is to calculate the impulse. It's taken from here if you want the source of the math:

    en.wikipedia.org/wiki/Collision_response

    rx,ry is the offset from A to B

    relvel is the velocity between the two objects at that point, along the normal.

    cross is the cross product of r and the normal.

    j is the impulse magnitude

    vx, vy is the horizontal and vertical velocities

    w is the angular velocity

    variable rx = 0
    variable ry = 0
    variable relvel = 0
    variable cross = 0
    variable c = 0
    variable j = 0
    
    set rx to B.x-A.x
    set ry to B.y-A.y
    set relvel to (B.vx - (A.vx+A.w*PI/180*-ry))*cos(normal) + (B.vy - (A.vy+A.w*PI/180*rx))*sin(normal)
    set cross to rx*sin(normal)-ry*cos(normal)
    set j to -(1+e)*relvel/(1/A.mass+1/B.mass+1/A.inertia*(-ry*c*cos(normal) + rx*c*sin(normal)))

    Before we go further the units used by the physics behavior needs to be taken into account. Construct physics uses degrees per second for angular velocity. The equations above need radians per second.

    So above A.w is replaced with A.w*PI/180.

    Also the physics behavior I don't think gives you the inertia of an object. But for a rectangle you can calculate it with

    inertia = mass/12*(w^2+(1/w)^2)

    Also bear in mind when I use A.vx in the equations above I mean A.physics.velocityX. Similar to vy and w.

    Ok, cool so Now we have j, which is the magnitude of the impulse. Since we can't apply an impluse at as specific location can just set the velocities directly.

    set vx to A.vx-*1/A.mass*cos(normal)

    set vy to A.vx-*1/A.mass*sin(normal)

    set w to A.w-j*1/A.mass*cross*180/Math.PI;

    Barring any typos on my part that should work.

  • If you don't need the physics to be very accurate, you can do this:

    B on collision with A:
     A Apply Impulse 100 at angle angle(B.x, B.y, A.x, A.y)
    

    Use image point 0 or -1

    To apply rotation, you can get the difference between angle(B.x, B.y, A.x, A.y) and B.angle (or angle of motion). Let's say this difference is 20 degrees, so you apply an angular velocity in the opposite direction, -40 for example.

    Again, this will not be very accurate, but should probably look ok for most collisions.

  • Thank you very much for these annwsers !

    R0J0hound, your method looks amazing but my math level seems way too low and my brain melted somewhere in the process :(

    I'm trying to use a combination between El Constructor's and dop2000's methods. The "realisticness" of the result is not that mandatory for the gameplay, so this should do the job.

    First of all, Im trying to apply dop2000's method in order to retrieve the rotation direction. But I dont understand this point : "Let's say this difference is 20 degrees, so you apply an angular velocity in the opposite direction, -40 for example. "

    I use anglediff(angle(B.x, B.y, A.x, A.y), B.Angle), this will always gives me a result between 0 and 360. But angular velocity is either a positive or negative value(for clockwise or anticlockwise). Im probably a little stupid here, but I dont understand how a can apply an angluar velocity in the opposite direction of a number thats always positive (0 -> 360).

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • I use anglediff(angle(B.x, B.y, A.x, A.y), B.Angle), this will always gives me a result between 0 and 360. But angular velocity is either a positive or negative value(for clockwise or anticlockwise). Im probably a little stupid here, but I dont understand how a can apply an angluar velocity in the opposite direction of a number thats always positive (0 -> 360)

    anglediff will give you the smallest angle (the difference between the two angles) that should be from 0 to 180 degrees. However, in your case it will probably be within 0 and 90, which is even easier to work with.

    That value should help you find the 'impulse' amount (smaller anglediff means larger impulse) and also the amount of angular velocity (smaller anglediff means smaller torque).

    However, yes, you cannot find out the direction (plus/minus) angular velocity from that. You need to check if the Physics object 'is clockwise from' the bullet direction or anticlockwise.

    So, if [PhysicsObject] "A" is clockwise from [ angle(B.x, B.y, A.x, A.y) ]
    Then, angularVel = angularVel
    Else: angularVel = - angularVel

    All you're doing is checking if the Physics object's origin is towards left or right from the perspective (direction) of the bullet. That will define - or + angularVel.

  • A couple of other things to consider:

    1. If object B has Bullet behavior with "Bounce off solids=Yes", its angle of motion at the moment of collision with A may be different. You need to get the angle before the bullet has bounced, so in this case you should disable "Bounce off solids" and use "Bounce off object" action instead.

    2. To make it look more realistic, you need to decrease the impulse with the angle difference. So if the bullet head-on collided with the object A, the impulse is high, the rotation is low. If the bullet hit the corner of object A, the impulse is small, the rotation is high.

  • Thank you guys, its working perfectly !

    I however had to add a couple of conditions to test if the bullet hits either the "front" or the "rear" of B (which looks more or less like a ship). Otherwise, the rotation direction was only correct when I hit the rear. The rotation is now applying correctly everywhere on the object.

    I ill now try to find the good ratio between the impulse strenght and the rotation speed depending on the angle of the bullet, but this should be easier.

    Thank you for your help !

  • I achieved to get the ratio between the rotation speed and the impulse strength with unlerp(0 ,90, anglediff(angle(B.x, B.Y, A.X, A.Y))) . This gives me the multiplyer to apply to the rotation speed. Then, "1-unlerp(...)" give me the multiplyer for the impulse speed.

    As said by dop2000, its not 100% accurate, but its hard to notice the difference between ths and a "real" physical hit.

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)