collision_triangle
This script works similarly to built-in collision_*() functions.
It uses a right-triangle-shaped sprite mask to detect collisions with pixel accuracy (unlike other simpler and faster methods).
Because any triangle can be split into two right triangles, the script can manipulate this single collision mask to fit any triangle using only scaling and rotation.
NOTE: This function will eventually be replaced with a version that works more like the built-in collision_*() functions of Game Maker.
It will return an instance id rather than the true or false value it returns now.
WARNING: This script will not work if 'Treat uninitialized variables as value 0' is enabled in the Game Maker Global Game Settings.
** Usage:
** collision_triangle(x1,y1,x2,y2,x3,y3,object)
**
** Arguments:
** x1,y1 first point of triangle
** x2,y2 second point of triangle
** x3,y3 third point of triangle
** object an object or instance to check for collision
**
** Returns:
** (true) if there is a collision between the given
** triangle and the given object, (false) otherwise
**
** Notes:
** Must be initialized with collision_triangle_init() before use.
**
** GMLscripts.com
*/
{
var x1,y1,x2,y2,x3,y3,object,xmin,xmax,ymin,ymax,d12,d13,d23,d14,d24,t,dx,dy,x4,y4;
x1 = argument0;
y1 = argument1;
x2 = argument2;
y2 = argument3;
x3 = argument4;
y3 = argument5;
object = argument6;
// Bounding box check
xmin = min(x1,x2,x3);
xmax = max(x1,x2,x3);
ymin = min(y1,y2,y3);
ymax = max(y1,y2,y3);
if (not collision_rectangle(xmin,ymin,xmax,ymax,object,false,false)) return false;
// Triangle perimeter check
if (collision_line(x1,y1,x2,y2,object,true,false)) return true;
if (collision_line(x1,y1,x3,y3,object,true,false)) return true;
if (collision_line(x2,y2,x3,y3,object,true,false)) return true;
// Find long side, make it (x1,y2) to (x2,y2)
d12 = point_distance(x1,y1,x2,y2);
d13 = point_distance(x1,y1,x3,y3);
d23 = point_distance(x2,y2,x3,y3);
switch (max(d12,d13,d23)) {
case d13:
t = x2; x2 = x3; x3 = t;
t = y2; y2 = y3; y3 = t;
d12 = d13;
break;
case d23:
t = x1; x1 = x3; x3 = t;
t = y1; y1 = y3; y3 = t;
d12 = d23;
break;
}
// From (x3,y3), find nearest point on long side (x4,y4).
dx = x2 - x1;
dy = y2 - y1;
if ((dx == 0) && (dy == 0)) {
x4 = x1;
y4 = y1;
}else{
t = ((x3 - x1) * dx + (y3 - y1) * dy) / (d12 * d12);
x4 = x1 + t * dx;
y4 = y1 + t * dy;
}
// A line constructed from (x3,y3) to (x4,y4) divides
// the original triangle into two right triangles.
// Fit the collision mask into these triangles.
d14 = point_distance(x1,y1,x4,y4);
d24 = d12 - d14;
with (global.objCollisionTriangle) {
image_angle = point_direction(x1,y1,x4,y4);
image_xscale = d14 / size;
image_yscale = point_distance(x3,y3,x4,y4) / size;
if ((x1 > x4) xor (y3 < y4)) image_yscale *= -1;
if (place_meeting(x4,y4,object)) return true;
image_xscale = -d24 / size;
if (place_meeting(x4,y4,object)) return true;
}
return false;
}
** Usage:
** collision_triangle_init(size)
**
** Arguments:
** size size of the test triangle in pixels
** increase size to increase accuracy
**
** Returns:
** nothing
**
** Notes:
** Creates an object, a sprite, and a global variable called objCollisionTriangle
**
** GMLscripts.com
*/
{
if (not variable_global_exists("objCollisionTriangle")) {
var color,object,size;
size = argument0;
object = object_add();
object_set_persistent(object,true);
object_event_add(object,ev_create,0,"size = "+string(size));
global.objCollisionTriangle = instance_create(0,0,object);
draw_clear_alpha(c_black,1);
color = draw_get_color();
draw_set_color(c_white);
draw_triangle(size,size,size,0,0,0,false);
draw_set_color(color);
global.objCollisionTriangle.sprite_index =
sprite_create_from_screen(0,0,size,size,true,true,false,true,size,0);
global.objCollisionTriangle.visible = false;
}
}
[Please Login]
Projects: 5
Contributors: Big J, xot
History:
Mar 17, 2007 - xot submits the original script
Jul 27, 2009 - Big J spots a typo
comments powered by Disqus

Related: