Maarten Baert's website

Game Maker / C++ projects

Home Model Creator ExtremePhysics Game Maker DLLs SimpleScreenRecorder AlterPCB Quadcopters   Recent comments Search

Last modified: Thu, 31 Jan 2013
Refresh

Collision detection


ExtremePhysics handles collisions automatically, so usually you don't have to do anything when two bodies collide. But sometimes you might want to do something special when two bodies collide, for example destroy one of the bodies. If you use the build-in GM collision events or functions, the results won't always be correct. This is because Game Maker calculates collisions based on the sprites, which is not very precise. If you use ExtremePhysics, it's usually better to use ExtremePhysics collision detection functions.

Collisions between existing bodies

Collisions between existing bodies can be detected with contacts. Whenever two bodies collide, ExtremePhysics will create a contact automatically when you call ep_world_update_contacts.

You can use this script to check whether two bodies are touching:

// bodies_touch(world,body1_id,body2_id)
// returns whether two bodies are touching
var s, c;
for(s = ep_body_first_shape(argument0, argument1); s!=0; s = ep_shape_next(argument0, argument1, s)) {
    for(c = ep_shape_get_first_contact(argument0, argument1, s); c!=0; c = ep_shape_get_next_contact(argument0, argument1, s, c)) {
        if ep_contact_get_body1(argument0, c)=argument2 or ep_contact_get_body2(argument0, c)=argument2 {
            return true;
        }
    }
}
return false;

This isn't very efficient though, especially if you call this for all possible collisions. There's a better way to do it. First, do this for all bodies in the game, right after creating them:

ep_body_set_uservar(global.world, body, 0, id);

This will store the id of the object that created the body in user variable 0. Now you can use this to check all collisions for one instance:

var s, c, b, object;
for(s = ep_body_first_shape(global.world, body); s!=0; s = ep_shape_next(global.world, body, s)) {
    for(c = ep_shape_get_first_contact(global.world, body, s); c!=0; c = ep_shape_get_next_contact(global.world, body, s, c)) {
        b = ep_contact_get_body1(global.world, c);
        if b=body {
            b = ep_contact_get_body2(global.world, c);
        }
        object = ep_body_get_user_var(global.world, b, 0);
        if object.object_index=obj_block {
            // this instance is touching a block
        }
    }
}

Or if you want to check all collisions at once (this is sometimes the most efficient solution):

var c, b1, b2, object1, object2;
for(c = ep_world_first_contact(global.world); c!=0; c = ep_contact_next(global.world, c)) {
    b1 = ep_contact_get_body1(global.world, c);
    b2 = ep_contact_get_body2(global.world, c);
    object1 = ep_body_get_uservar(global.world, b1, 0);
    object2 = ep_body_get_uservar(global.world, b2, 0);
    if object1.object_index=obj_block and object2.object_index=obj_player {
        collision_block_player(object1, object2);
    } else if object1.object_index=obj_player and object2.object_index=obj_block {
        collision_block_player(object2, object1);
    } else if object1.object_index=obj_player and object2.object_index=obj_ball {
        collision_player_ball(object1, object2);
    } else if object1.object_index=obj_ball and object2.object_index=obj_player {
        collision_player_ball(object2, object1);
    } /* ... */
}

collision_block_player and collision_player_ball are scripts you should write yourself. The two arguments hold the ids of the objects that are colliding. This way every collision is handled exactly once every step.

You can also use the GM function object_is_ancestor if you want to use parents. For example, if you have three types of blocks, and obj_block is the parent of all three types, you could do this:

if object_is_ancestor(object1.object_index, obj_block) and object2.object_index=obj_player {
    collision_block_player(object1, object2);
} else if object1.object_index=obj_player and object_is_ancestor(object2.object_index, obj_block) {
    collision_block_player(object2, object1);
}

Collisions with virtual shapes

Virtual shapes are shapes that don't actually exist, they are only used to check collisions. The collision functions that use virtual shapes will simply return whether a collision would have occurred if there was a shape at that position, but there is no real collision (i.e. the real body won't bounce back).

The following functions use one virtual shape and one real body/shape:

After using one of these functions, you can call ep_world_get_collision_body and ep_world_get_collision_shape to get the id of the bodies and shapes that caused the collision.

The following functions use two virtual shapes:


Comments

Huder

Comment #1: Thu, 2 Jun 2011, 17:19 (GMT+1, DST)

Quote


I'm making bullets and i wonder how get an instance's id which is hit by bullet.

I'm destroying this bullet if was hit scenery object or player, but here is problem. I want ignore collision with bullet owner. So every bullet have variable bulletOwnerId.

if ( ep_world_collision_test_line(world,x,y,x+lengthdir_x(speed,direction-180),y+lengthdir_y(speed,direction-180),1, co_bullet, co_scenery|co_player, 0) )
{
    if ( here i want put code: id of instance being hit != bulletOwnerId )
    instance_destroy();
}
Maarten Baert

Administrator

Comment #2: Thu, 16 Jun 2011, 21:36 (GMT+1, DST)

Quote


You can use ep_world_get_collision_body and ep_world_get_collision_shape. I've added this to the tutorial now.

B35a13

Comment #3: Fri, 24 Jun 2011, 21:12 (GMT+1, DST)

Quote


Is there a possibility that these codes don't work anymore?
When i try to use them, i get some errors.
I figured out that

ep_body_get_user_var

=

ep_body_get_uservar

.

Nevermind, i figured it out.

Last modified: Wed, 20 Jul 2011, 23:12 (GMT+1, DST)

Maarten Baert

Administrator

Comment #4: Tue, 2 Aug 2011, 2:38 (GMT+1, DST)

Quote


Quote: B35a13

Is there a possibility that these codes don't work anymore?
When i try to use them, i get some errors.
I figured out that ep_body_get_user_var = ep_body_get_uservar.

Nevermind, i figured it out.

Thanks for telling me, I've corrected the code now.

Brunoxzx

Comment #5: Fri, 19 Aug 2011, 8:10 (GMT+1, DST)

Quote


Hi Maarten. Do you think if i use a "switch" instead a "else if" in your code to get collisions the code will be quiker.

Example.

var c, b1, b2, object1, object2;
for(c = ep_world_first_contact(global.world); c!=0; c = ep_contact_next(global.world, c)) {
    b1 = ep_contact_get_body1(global.world, c);
    b2 = ep_contact_get_body2(global.world, c);
    object1 = ep_body_get_uservar(global.world, b1, 0);
    object2 = ep_body_get_uservar(global.world, b2, 0);
    switch(object1.object_index ^ object2.object_index){
        case (obj_player ^ obj_block): collision_block_player(object1,object2); break;
        case (obj_player ^ obj_ball): collision_player_ball(object1,object2); break;
    }
}

Thank you for your kind attention.

Sorry for my bad english.

Last modified: Sun, 21 Aug 2011, 3:53 (GMT+1, DST)

Maarten Baert

Administrator

Comment #6: Mon, 22 Aug 2011, 22:49 (GMT+1, DST)

Quote


@Brunoxzx: That won't always work:
1^4 = 001^100 = 101 = 5
3^6 = 011^110 = 101 = 5

Brunoxzx

Comment #7: Thu, 1 Sep 2011, 6:35 (GMT+1, DST)

Quote


O.O you have all the reason XD.

I have another question, I'm making a simple bullet, creating a new static body with 32 of speed and all goes good except that when the bullet collides with a crate the generated impulse force its huge.

what can i do to reduce the impulse force of my bullet.

Sorry for my bad inglish (again).

Maarten Baert

Administrator

Comment #8: Sun, 11 Sep 2011, 1:38 (GMT+1, DST)

Quote


Quote: Brunoxzx

O.O you have all the reason XD.

I have another question, I'm making a simple bullet, creating a new static body with 32 of speed and all goes good except that when the bullet collides with a crate the generated impulse force its huge.

what can i do to reduce the impulse force of my bullet.

Sorry for my bad inglish (again).

Reduce the mass of the bullet. Or if you are using ep_body_calculate_mass, reduce the density of the shape(s).

Brunoxzx

Comment #9: Sun, 11 Sep 2011, 10:28 (GMT+1, DST)

Quote


Oh thanks, you solve the problem!.

Hai273996803

Comment #10: Mon, 25 Jun 2012, 12:21 (GMT+1, DST)

Quote


excuse me,"ep_world_get_collision_body" and "ep_world_get_collision_shape" how to use?? They "index" means what?I do not understand?

Killpill

Comment #11: Wed, 4 Jul 2012, 2:50 (GMT+1, DST)

Quote


I'm having a bit of a problem with collisions.

One of your examples uses substeps to stop objects that move fast from going through walls and such. My game needs this.

However, when using substeps, the contacts from collisions are destroyed before the objects can check for collisions (most of the time, if the contacts are present on the last substep they'll detect the collision).

Is there a way around this without making a collision detection system that runs in the substep code and reports back to the objects?

Maarten Baert

Administrator

Comment #12: Fri, 6 Jul 2012, 19:49 (GMT+1, DST)

Quote


Quote: Hai273996803

excuse me,"ep_world_get_collision_body" and "ep_world_get_collision_shape" how to use?? They "index" means what?I do not understand?

index = 0 means the first collision found, index = 1 means the second collision, ...

The collision functions return the total number of collisions found.

Quote: Killpill

Is there a way around this without making a collision detection system that runs in the substep code and reports back to the objects?

No, unfortunately not. This is exactly what I did in The Machine.

You can speed it up a bit by only checking new contacts: use ep_world_last_contact to get the id of the newest contact, then use ep_contact_previous until you get a contact with an id that's less than or equal to the id of the newest contact in the previous substep (or 0 which means there are no more contacts). Now you won't be checking the same contact multiple times per step.

Last modified: Fri, 6 Jul 2012, 19:54 (GMT+1, DST)

Killpill

Comment #13: Sat, 7 Jul 2012, 1:18 (GMT+1, DST)

Quote


Woah, thank you. I can also use that to make sure "hit something" sounds don't play twice.

Is there a way to apply a circular impulse to the world that effects all bodies within a range? I'm trying to make an explosion that doesn't rely on multiple small bodies and only lasts one step. Here is what I'm using now:

dia = 100;
pow = 1000;

n = ep_world_collision_test_circle(global.world, dia/2, x, y, .02, TERRAIN_MASK, DEFAULT_COLLISION, 0);
b = 0;
s = 0;

for (i = 0; i < n; i+=1){
  b[i] = ep_world_get_collision_body(global.world, i);
}

for (i = 0; i < n; i+=1){
  _x = ep_body_get_x_center(global.world, b[i]);
  _y = ep_body_get_y_center(global.world, b[i]);
    
  _dist = ep_body_ray_cast(global.world, b[i], x, y, lengthdir_x(1, point_direction(x, y, _x, _y)), lengthdir_y(1, point_direction(x, y, _x, _y)), TERRAIN_MASK, DEFAULT_COLLISION, 0);
  
  _x = x + lengthdir_x(_dist, point_direction(x, y, _x, _y));
  _y = y + lengthdir_y(_dist, point_direction(x, y, _x, _y));
  
  if (_dist){
    _xx = ep_body_vect_world_to_local_x(global.world, b[i], _x, _y);
    _yy = ep_body_vect_world_to_local_y(global.world, b[i], _x, _y);
    _pow = (pow/(dia/2))*_dist;
    
    xpow = lengthdir_x(_pow, point_direction(x, y, _x, _y));
    ypow = lengthdir_y(_pow, point_direction(x, y, _x, _y));
    
    ep_body_apply_impulse(global.world, b[i], _xx, _yy, xpow, ypow, 0, false, false, true);
  }
}

instance_destroy();

I also don't know if there is a way to get the contact point of a virtual shape collision, so I used raycast to make a guesstimate. I have no idea if I did the force values correctly, something seems off sometimes. Using raycast in the first loop would reset the world collisions, so I had to use two.

Moving on.. I looked at the spiderball tutorial and it looked promising for making bodies "stick" to slopes instead of using them as ramps/falling down. I can't, however, get that to work unless I use a circle instead of a box shape. For my slopes, I am using a polygon triangle. Any advise you could offer for that?

I would upload the file, but the project is rather large and messy - as we are implementing Extreme Physics late in development.

Thanks for helping out - and for making this DLL. I hope we'll be able to release our game with your DLL powering the physics.

Last modified: Sat, 7 Jul 2012, 6:02 (GMT+1, DST)

Maarten Baert

Administrator

Comment #14: Thu, 12 Jul 2012, 1:41 (GMT+1, DST)

Quote


Quote: Killpill

I also don't know if there is a way to get the contact point of a virtual shape collision, so I used raycast to make a guesstimate.

You can't, in fact I'm skipping most of that code completely to save time.

Quote: Killpill

I have no idea if I did the force values correctly, something seems off sometimes. Using raycast in the first loop would reset the world collisions, so I had to use two.

I don't really understand why you are using raycasting in the first place. You're always raycasting directly towards the center of the body. Since the force is pointing in exactly the same direction, the result would be exactly the same if you had applied the force directly to the center of the body, which is a lot easier to do.

Quote: Killpill

Moving on.. I looked at the spiderball tutorial and it looked promising for making bodies "stick" to slopes instead of using them as ramps/falling down. I can't, however, get that to work unless I use a circle instead of a box shape. For my slopes, I am using a polygon triangle. Any advise you could offer for that?

It should work for any shape. Can you show me the code?

Killpill

Comment #15: Sun, 15 Jul 2012, 1:06 (GMT+1, DST)

Quote


I do things that way to make objects rotate. Although I am pointing to the center, the force is not applied to the center.

I deleted the old code for sticking to slopes but the reason it didn't work was that is the spiderball example, you used rotation to make the ball move. The rotation wasn't affected by the force that pushed the ball into the wall, so the ball still moved smoothly. I can't use rotation with a box, so I use forces. By pushing the box into the slope, I change the speed it climbs the slope.

Maarten Baert

Administrator

Comment #16: Sun, 12 Aug 2012, 20:32 (GMT+1, DST)

Quote


Quote: Killpill

I do things that way to make objects rotate. Although I am pointing to the center, the force is not applied to the center.

I deleted the old code for sticking to slopes but the reason it didn't work was that is the spiderball example, you used rotation to make the ball move. The rotation wasn't affected by the force that pushed the ball into the wall, so the ball still moved smoothly. I can't use rotation with a box, so I use forces. By pushing the box into the slope, I change the speed it climbs the slope.

You can also use 'tangentvelocity' (ep_shape_set_material) instead. It should work better (just as good as rotation works for circles).

Mattinator123

Comment #17: Wed, 5 Sep 2012, 5:56 (GMT+1, DST)

Quote


im new here and i think im missing something

for(s = ep_body_get_first_shape(global.world, body); s!=0; s = ep_shape_next(global.world, body, s)) {
ep_body_get_first_shape

no longer exists?

plz help i need to get my water game working!

Maarten Baert

Administrator

Comment #18: Fri, 7 Sep 2012, 23:51 (GMT+1, DST)

Quote


Quote: Mattinator123

im new here and i think im missing something

for(s = ep_body_get_first_shape(global.world, body); s!=0; s = ep_shape_next(global.world, body, s)) {
ep_body_get_first_shape

no longer exists?

plz help i need to get my water game working!

The right name is ep_body_first_shape. I will change it.

Claudiu_hash

Comment #19: Sun, 9 Sep 2012, 0:06 (GMT+1, DST)

Quote


hey

i have just a little programming concept problem over here and after a few days of searching for a solution i kind of reached the end of my patience and understanding.

so there are "n" number of instances of blue_block and "m" number of instances of pink_block

both block types have health and mass

when a blue_block collides with a pink block the health of the blue_block is lowered by:
d = m*sqr(v)/2
where
d is the damage done to blue_block
v is the velocity of the pink_block
m is the mass of the pink_block

when the damage is higher then health then the object is destroyed.

the problems are:
1. i need the damage to be done only on first collision. so that if block_blue stays in contact with block_pink no damage should be done anymore.
2. if a pink_block touches a blue_block it does its damage and they remain in contact and another pink_block touches the same blue_block it should do its damage to.
3. and of course if a blue_block touches another blue_block there should be no damage.
4. when a dynamic block (blue or pink) touches a static block ... strange things happen because the static block does not have mass and velocity.
5. a pink_block touches a blue_block; after that they bounce and get in contact another time, damage should be done twice to the blue_block.

and the same damage system should apply to the pink_blocks on collision with the blue_blocks

any ideea would be of great help.

Last modified: Sun, 9 Sep 2012, 0:31 (GMT+1, DST)

Maarten Baert

Administrator

Comment #20: Mon, 17 Sep 2012, 13:33 (GMT+1, DST)

Quote


Quote: Claudiu_hash

hey

i have just a little programming concept problem over here and after a few days of searching for a solution i kind of reached the end of my patience and understanding.

so there are "n" number of instances of blue_block and "m" number of instances of pink_block

both block types have health and mass

when a blue_block collides with a pink block the health of the blue_block is lowered by:
d = m*sqr(v)/2
where
d is the damage done to blue_block
v is the velocity of the pink_block
m is the mass of the pink_block

when the damage is higher then health then the object is destroyed.

the problems are:
1. i need the damage to be done only on first collision. so that if block_blue stays in contact with block_pink no damage should be done anymore.
2. if a pink_block touches a blue_block it does its damage and they remain in contact and another pink_block touches the same blue_block it should do its damage to.
3. and of course if a blue_block touches another blue_block there should be no damage.
4. when a dynamic block (blue or pink) touches a static block ... strange things happen because the static block does not have mass and velocity.
5. a pink_block touches a blue_block; after that they bounce and get in contact another time, damage should be done twice to the blue_block.

and the same damage system should apply to the pink_blocks on collision with the blue_blocks

any ideea would be of great help.

You can get the velocity difference with ep_contact_get_point1_normalveldelta/ep_contact_get_point2_normalveldelta. You probably want to add those two together. This should work for static bodies too. For the mass, try to use

mass = 1 / (1 / mass1 + 1 / mass2);

That's that I use inside ExtremePhysics. Static bodies essentially have infinite mass, and 1 / infinite is 0, so if the first body is static it becomes

mass = 1 / (0 + 1 / mass2) = mass2;

You can do this more easily if you save the inverted mass instead of the mass itself (i.e. 1 / mass1 instead of mass1) because that makes it possible to give bodies an infinite mass (just set the inverted mass to 0).

Normally the velocity should be almost zero after the first impact, but if you want to check that explicitly you can use the contact id for that. A few posts back (slightly different situation, but the idea is the same):

Quote

use ep_world_last_contact to get the id of the newest contact, then use ep_contact_previous until you get a contact with an id that's less than or equal to the id of the newest contact in the previous step (or 0 which means there are no more contacts). Now you won't be checking the same contact multiple times.

You can use user variables to store the id of the objects that the bodies represent, and once you have the ids you can use id.object_index to check whether it's a blue or pink block.

Kalspar

Comment #21: Sat, 6 Apr 2013, 2:35 (GMT+1, DST)

Quote


hi... yeah im kinda new to the game making thing... and i am making a game called "The Individual" and the main character is a square, the other character's in this game(AI's)are circle's, and your character is now tired of being the only square and goes off to find someone just like him...

My problem is ,is that i can't make him roll (with physics) and move left and right when ever i press left...or right. i know how to make him move and rotate, but he wont move.

here... i will try and make more sense. say if i hit the right arrow key, he stay's there and rotates. only rotates, there is no roll or movement to the right...he just sit's there and rotates, and if i hit space bar he jump's up and moves to the right, and when he hit's the ground. it start's all over again. all i want to know is how to give him tilting physics and rolling physics. kinda like dice movement. hope you under stand and that you can help me :/. thank you

Maarten Baert

Administrator

Comment #22: Sun, 7 Apr 2013, 15:04 (GMT+1, DST)

Quote


Quote: Kalspar

hi... yeah im kinda new to the game making thing... and i am making a game called "The Individual" and the main character is a square, the other character's in this game(AI's)are circle's, and your character is now tired of being the only square and goes off to find someone just like him...

My problem is ,is that i can't make him roll (with physics) and move left and right when ever i press left...or right. i know how to make him move and rotate, but he wont move.

here... i will try and make more sense. say if i hit the right arrow key, he stay's there and rotates. only rotates, there is no roll or movement to the right...he just sit's there and rotates, and if i hit space bar he jump's up and moves to the right, and when he hit's the ground. it start's all over again. all i want to know is how to give him tilting physics and rolling physics. kinda like dice movement. hope you under stand and that you can help me :/. thank you

You are probably trying to change the position and orientation directly, i.e. with ep_body_set_position. You should never do this, because to ExtremePhysics it will look like the body just teleported to the new location. This means collisions won't be simulated realistically, like you saw. Instead you should use ep_body_set_velocity_center, and let ExtremePhysics handle the movement.

Last modified: Sun, 7 Apr 2013, 15:05 (GMT+1, DST)

Melph93

Comment #23: Wed, 12 Jun 2013, 10:29 (GMT+1, DST)

Quote


Hello. I am using your engine for a racing game. Before I whine for help, I would like to thank you for creating such an efficient and accessible engine! It has been extremely helpful.

In my game, if a strong enough force is applied to an object (a barrel perhaps), I would like the barrel to break. How would I go about calculating the force being put onto an object? Is there anyway for me to check if a barrel has a certain amount of force, either while being rammed (let's say by a car), or crushed between a barrel and a wall? I cannot use the speed of the barrel because it might be getting crushed, but still not moving at all. I hope that made sense. Thanks!

Edit: I solved the problem, as explained in my following accidental double post.

Last modified: Wed, 12 Jun 2013, 12:34 (GMT+1, DST)

Melph93

Comment #24: Wed, 12 Jun 2013, 11:08 (GMT+1, DST)

Quote


I read in a comment above that I could use the ep_contact_get_point1_normalveldelta/ep_contact_get_point2_normalveldelta functions to get the difference in velocity between two objects (for example, my car and a barrel). I am unsure of how I would use them however. Where would I call them from, and what would I use as the contact_id argument? Thanks again!

Edit: sorry I did not just edit my previous post, it wasn't appearing before I made this comment.

Edit Again: I have figured out the answer to my own question, using posts you previously had made on other pages. Anyway, if anyone had the same question, this is how it worked for me.

After using ep_world_update_contacts() and ep_world_simulate_step() calls, I went through a for loop of all the contacts as demonstrated on this page...

http://www.maartenbaert.be/extremephysics/tutorials/collision-detection/

Then, using the contact in the for loop (variable c), you can call ep_contact_get_point1_normalveldelta/ep_contact_get_point2_normalveldelta functions to get the velocities (I added them together to get the difference in velocities). You can use the ep_body_get_mass() fuction to get the masses of the objects.

For my kinetic force function, I then did mass*velocity^2, but you can obviously use these variables to calculate whatever force you want.

Thanks a ton for the excellent scripts Maarten!

Last modified: Wed, 12 Jun 2013, 12:33 (GMT+1, DST)

Maarten Baert

Administrator

Comment #25: Fri, 14 Jun 2013, 23:25 (GMT+1, DST)

Quote


Quote: Melph93

Then, using the contact in the for loop (variable c), you can call ep_contact_get_point1_normalveldelta/ep_contact_get_point2_normalveldelta functions to get the velocities (I added them together to get the difference in velocities). You can use the ep_body_get_mass() fuction to get the masses of the objects.

That's almost correct - you shouldn't add the two together, you should take the maximum of the two. Otherwise edge-edge contacts will have a velocity that's twice as high. This doesn't make a difference when one of the two shapes is a circle, since circles can't have edge-edge contacts (there are no edges). You should also check that the velocity is positive, because if it's negative that means the two objects are moving away from each other (you won't see this very often though).

If you want to do it 100% right, you have to check which contact points are active and only check the active ones. In your case it won't make a difference though, because ep_contact_get_point1_normalveldelta/ep_contact_get_point2_normalveldelta will just return 0 when the contact point is not active.

Last modified: Fri, 14 Jun 2013, 23:28 (GMT+1, DST)

J_dotson

Comment #26: Tue, 18 Jun 2013, 23:54 (GMT+1, DST)

Quote


First of all, I have to say this is an excellent, easy-to-use engine, so thanks for making it! I am writing a sci-fi tank game that will eventually be 3D, but all the physics for the game will be from a top-down orientation using Extreme Physics. The tanks hover above the ground so I would like them to move as if they were on ice. When they shoot each other, I thought it might be interesting to have the bullets effect them realistically. But I seem to experience significant performance issues when I create a separate body for each bullet since 60 bullets are fired each second. So I decided to use some of the collision checking functions:

if(ep_world_collision_test_line(global.world,x,y,xx,yy,0.1,1,2,0))
{
    var hit, dist, shift;
    hit = ep_world_get_collision_body(global.world,0);
    dist = point_distance(x,y,xx,yy);
    shift = dist/2;
    dist -= shift;
    xx = x + lengthdir_x(dist,dir);
    yy = y + lengthdir_y(dist,dir);
    while(shift>0.1)
    {
        shift = shift/2;
        if(ep_world_collision_test_line(global.world,x,y,xx,yy,0.1,1,2,0))
            dist -= shift;
        else
            dist += shift;
        xx = x + lengthdir_x(dist,dir);
        yy = y + lengthdir_y(dist,dir);
    }
    xx = ep_body_coord_world_to_local_x(global.world,hit,xx,yy);
    yy = ep_body_coord_world_to_local_y(global.world,hit,xx,yy);
    ep_body_apply_impulse(global.world,hit,xx,yy,lengthdir_x(5,dir),lengthdir_y(5,dir),0,false,false,false);
    instance_destroy();
}
else
{
    x += lengthdir_x(vel,dir);
    y += lengthdir_y(vel,dir);
    xx = x + lengthdir_x(vel,dir);
    yy = y + lengthdir_y(vel,dir);
}

So basically I use a binary search process to approximate the point of collision and then apply an impulse. This doesn't seem to behave very realistically. Sometimes the other tank will rotate the wrong way or generally not as expected. The accuracy of the collision seems be dependent on the angle of the bullet as well, with certain angles presenting more realistic results than others.
Here the source if you want to play around with it and see what I mean:
https://www.dropbox.com/s/yh7bfy62dmhyeas/physics_test.gm81

J_dotson

Comment #27: Wed, 19 Jun 2013, 5:58 (GMT+1, DST)

Quote


Sorry for re-posting. There may still be something wrong with what I have done earlier, but I believe the tank does not react to the collision properly is because the force should be applied normal to the shape. Would there be a way using my current method to determine the normal of the edge that makes contact with the bullet?

Maarten Baert

Administrator

Comment #28: Wed, 19 Jun 2013, 15:36 (GMT+1, DST)

Quote


First of all, 60 bodies per second shouldn't be a problem if you also destroy them fast enough. EP can handle hunderds of bodies. So I think the performance problem is somewhere else (maybe you forgot to destroy the bodies, or maybe the way the bullets are drawn is slow).

What you're looking for is raycasting. Take a look at the platform example, you can shoot lasers with the mouse and they also apply a force to the target.

I think the problem you have is caused by this code:

    xx = ep_body_coord_world_to_local_x(global.world,hit,xx,yy);
    yy = ep_body_coord_world_to_local_y(global.world,hit,xx,yy);

The first line overwrites xx, but you still need it in the second line. This produces incorrect results.

Also, the last argument of ep_body_apply_impulse should be 'true' in this case.

You could make the force normal to the shape, but I don't think it's more realistic. It would make sense if the bullets bounce off the tank, but they probably won't do that in reality ;).

J_dotson

Comment #29: Wed, 19 Jun 2013, 21:15 (GMT+1, DST)

Quote


Thanks for the help! I fixed the problem with the coordinate conversions and it works great. I think I prefer this method to ray-casting because the effect isn't instant and is dependent on how far away the target body is.
As far as the normal issue, seeing it now, I agree that the bullets should not bounce perfectly off the tank, but I would like to calculate the normal for other purposes. Would you suggest just doing a line to line collision with each edge of the target polygon or is there a faster way?
As far as creating a new body for each bullet, I wasn't as much worried about the computation time needed to create the bodies as much as the large amount of potential contacts. For instance, in your explosion example, I had a significant fps decrease when the explosion occurred near several bodies. But if this is an option, do you think it would be faster or slower than the current method. I'm expecting significant graphical performance issues and I want to make sure this is as fast as possible. Thanks again! :)

Maarten Baert

Administrator

Comment #30: Tue, 23 Jul 2013, 19:59 (GMT+1, DST)

Quote


Quote: J_dotson

As far as the normal issue, seeing it now, I agree that the bullets should not bounce perfectly off the tank, but I would like to calculate the normal for other purposes. Would you suggest just doing a line to line collision with each edge of the target polygon or is there a faster way?

If there's an actual collision, you can get the normals from the contact with ep_contact_get_normal_x and ep_contact_get_normal_y. Otherwise it's not possible.

Quote: J_dotson

As far as creating a new body for each bullet, I wasn't as much worried about the computation time needed to create the bodies as much as the large amount of potential contacts. For instance, in your explosion example, I had a significant fps decrease when the explosion occurred near several bodies. But if this is an option, do you think it would be faster or slower than the current method. I'm expecting significant graphical performance issues and I want to make sure this is as fast as possible. Thanks again! :)

Raycasting is definitely faster than creating separate bodies, because it has to be done only once. Bodies exist for multiple steps, and each time collisions are calculated. It gets worse when there are actual collisions because that also creates contacts (which are constraints, so they slow down the solver phase, especially if the number of iterations is high).

A55h411

Comment #31: Mon, 14 Jul 2014, 14:52 (GMT+1, DST)

Quote


Hello. I used this code to make collision detecting for player's object in my game:

var s, c, b, object;
for(s = ep_body_first_shape(global.world, body); s!=0; s = ep_shape_next(global.world, body, s)) {
    for(c = ep_shape_get_first_contact(global.world, body, s); c!=0; c = ep_shape_get_next_contact(global.world, body, s, c)) {
        b = ep_contact_get_body1(global.world, c);
        if b=body {
            b = ep_contact_get_body2(global.world, c);
        }
        object = ep_body_get_user_var(global.world, b, 0);
        if object.object_index=obj_block {
            // this instance is touching a block
        }
    }
}

I have a question: how can i get the id of the shape that collides with player's object?

Maarten Baert

Administrator

Comment #32: Sat, 19 Jul 2014, 21:22 (GMT+1, DST)

Quote


Quote: A55h411

I have a question: how can i get the id of the shape that collides with player's object?

Like this:

var s, other_s, c, b, object;
for(s = ep_body_first_shape(global.world, body); s!=0; s = ep_shape_next(global.world, body, s)) {
    for(c = ep_shape_get_first_contact(global.world, body, s); c!=0; c = ep_shape_get_next_contact(global.world, body, s, c)) {
        b = ep_contact_get_body1(global.world, c);
        if b=body {
            b = ep_contact_get_body2(global.world, c);
        }
        other_s = ep_contact_get_shape1(global.world, c);
        if other_s=s {
            other_s = ep_contact_get_shape2(global.world, c);
        }
        object = ep_body_get_user_var(global.world, b, 0);
        if object.object_index=obj_block {
            // this instance is touching a block
        }
    }
}

Last modified: Sat, 19 Jul 2014, 21:22 (GMT+1, DST)

Sketchy_b

Comment #33: Wed, 9 Sep 2015, 13:34 (GMT+1, DST)

Quote


Hi Maarten, first off thanks for creating this wonderful physics engine! secondly I am using your script to check all collisions on each step (Three Substeps) and all works well when there is only one dynamic object in the scene but when I start adding more the collision detection doesn't pick up all collisions in that step it seems to only report the first one(I guess?). However i am using the collision as a damage model and so could do with checking all collisions that happen in the step. is there an easy way to do this?

Thanks Sketchy_B

Last modified: Wed, 9 Sep 2015, 20:13 (GMT+1, DST)

Sketchy_b

Comment #34: Mon, 14 Sep 2015, 14:13 (GMT+1, DST)

Quote


My bad, I was checking the wrong variable in my impact test. Awesome Engine Man!

Write a comment