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_get_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_get_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, shape, 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 body and shape that caused the collision.
The following functions use two virtual shapes:
Comments
Huder |
Comment #1: Thu, 2 Jun 2011, 17:19 (GMT+1, DST) 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 BaertAdministrator |
Comment #2: Thu, 16 Jun 2011, 21:36 (GMT+1, DST) 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) Is there a possibility that these codes don't work anymore? 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 BaertAdministrator |
Comment #4: Tue, 2 Aug 2011, 2:38 (GMT+1, DST) Quote: B35a13
Is there a possibility that these codes don't work anymore? 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) 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 BaertAdministrator |
Comment #6: Mon, 22 Aug 2011, 22:49 (GMT+1, DST) @Brunoxzx: That won't always work: |
Brunoxzx |
Comment #7: Thu, 1 Sep 2011, 6:35 (GMT+1, DST) 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 BaertAdministrator |
Comment #8: Sun, 11 Sep 2011, 1:38 (GMT+1, DST) 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) Oh thanks, you solve the problem!. |