GMLscripts.com

collision_triangle

MASK MASK MASK 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 triangle to detect collisions with pixel accuracy (unlike other simpler methods). Because any triangle can be split into two right triangles, the function can manipulate this single collision mask to fit any type of triangle using only scaling, rotation, and translation.

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.

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

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 x4, y4;
    if (d12 == 0) {
        x4 = x1;
        y4 = y1;
    }else{
        var dx = x2 - x1;
        var dy = y2 - y1;
        var px = x3 - x1;
        var py = y3 - y1;
        t = (px * dx + py * 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;
    var side = sign((x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1));
    with (__objCollisionTriangle) {
        image_angle  = point_direction(x1, y1, x2, y2);
        image_xscale = d14 / size;
        image_yscale = side * point_distance(x3, y3, x4, y4) / size;
        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