You are currently viewing the GMLscripts.com static mirror. Forum access and script submissions are not available through this mirror.

Invert GMLscripts.com

collision_triangle

This script function works like the built-in collision_*() functions and is used to detect collisions with a triangular region. It uses a collision mask shaped like a right-angled triangle to detect collisions with pixel accuracy (unlike other simpler methods). Because any triangle can be split into two right-angled triangles, the function can manipulate this single collision mask to fit any type of triangle using only scaling and rotation.

collision_triangle

Click and drag triangle points. Press SPACE to toggle mask resolution.Download

The partner function collision_triangle_init() is required to initialize the main function collision_triangle() and must be called once before the main function can be used. The initialization function creates a collision mask with the desired resolution and prepares the __objCollisionTriangle helper object for use by the main function. See function header notes for more information.

NOTE: This script function requires some manual assistance before use. There needs to be a helper object named __objCollisionTriangle in your project before the function can be initialized. Once added, the object needs no further editing and does not need to be added to any rooms.

collision_triangle(x1, y1, x2, y2, x3, y3, object)
Returns an object instance id that collides with a given triangle.
COPY/// @func   collision_triangle(x1, y1, x2, y2, x3, y3, object)
///
/// @desc   Returns an object instance id that collides with a given triangle.
///         If there is no collision, keyword noone is returned.
///
///         IMPORTANT: Initialize with collision_triangle_init() before first use.
///
/// @param  {real}      x1          x-coordinate of 1st point of triangle
/// @param  {real}      y1          y-coordinate of 1st point of triangle
/// @param  {real}      x2          x-coordinate of 2nd point of triangle
/// @param  {real}      y2          y-coordinate of 2nd point of triangle
/// @param  {real}      x3          x-coordinate of 3rd point of triangle
/// @param  {real}      y3          y-coordinate of 3rd point of triangle
/// @param  {object}    object      object or instance to check, or all
///
/// @return {instance}  object instance id
///
/// GMLscripts.com/license

function collision_triangle(x1, y1, x2, y2, x3, y3, object)
{
   // Bounding box check (early out)
   var xmin = min(x1, x2, x3);
   var xmax = max(x1, x2, x3);
   var ymin = min(y1, y2, y3);
   var ymax = max(y1, y2, y3);
   var inst = collision_rectangle(xmin, ymin, xmax, ymax, object, false, false);
   if (inst == noone) return noone;

   // Triangle perimeter check (early out)
   inst = collision_line(x1, y1, x2, y2, object, true, false);
   if (inst != noone) return inst;
   inst = collision_line(x1, y1, x3, y3, object, true, false);
   if (inst != noone) return inst;
   inst = collision_line(x2, y2, x3, y3, object, true, false);
   if (inst != noone) return inst;

   // Find long side, make it (x1,y2) to (x2,y2)
   var d12 = point_distance(x1, y1, x2, y2);
   var d13 = point_distance(x1, y1, x3, y3);
   var d23 = point_distance(x2, y2, x3, y3);
   var t;
   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).
   var dx = x2 - x1;
   var dy = y2 - y1;
   var x4, y4;
   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.
   var d14 = point_distance(x1, y1, x4, y4);
   var d24 = d12 - d14;
   with (__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) ^^ (y3 < y4)) image_yscale *= -1;
       inst = instance_place(x4, y4, object);
       if (inst != noone) return inst;
       image_xscale = -d24 / size;
       inst = instance_place(x4, y4, object);
       if (inst != noone) return inst;
   }
   return noone;
}
collision_triangle_init(size)
Required to initialize collision_triangle() before first use.
COPY/// @func   collision_triangle_init(size)
///
/// @desc   Required to initialize collision_triangle() before first use.
///         Creates an instance of stub object __objCollisionTriangle and
///         prepares it for use including the creation of triangle collision
///         mask of the given size. A larger size can improves accuracy at
///         the expense of memory usage. The default size of 256 pixels is
///         probably sufficient for most purposes.
///
///         This function only needs to be called once and the collision
///         triangle instance persists between rooms. If it is called again,
///         any previous triangle collision instance will be destroyed along
///         with its collision mask sprite, and a new instance and collision
///         mask sprite will be created using the new size.
///
///         IMPORTANT: An object called __objCollisionTriangle must exist
///         in your project before use. It should be a blank stub and does
///         not require any additional settings or inclusion in any room.
///
/// @param  {real}      size        size of mask in pixels (default 256)
///
/// @return {bool}      true on success, false otherwise.
///
/// GMLscripts.com/license

function collision_triangle_init(size=256)
{
    with (__objCollisionTriangle) {
        if (sprite_exists(mask_index)) sprite_delete(mask_index);
        instance_destroy();
    }
    var color = draw_get_color();
    var surface = surface_create(size, size);
    if (!surface_exists(surface)) return false;
    surface_set_target(surface);
    draw_clear_alpha(c_black, 0);
    draw_set_color(c_white);
    draw_triangle(size, size, size, -1, -1, -1, false);
    surface_reset_target();
    var sprite = sprite_create_from_surface(surface, 0, 0, size, size, true, false, size, 0);
    surface_free(surface);
    draw_set_color(color);
    if (!sprite_exists(sprite)) return false;
    sprite_collision_mask(sprite, false, 2, 0, 0, size, size, bboxkind_precise, 0);
    with (instance_create_depth(0, 0, 0, __objCollisionTriangle)) {
        self.persistent = true;
        self.visible = false;
        self.mask_index = sprite;
        self.size = size;
    }
    return true;
}

Contributors: xot

GitHub: View · Commits · Blame · Raw