FoxyOfJungle / TurboGML

The largest collection of useful general GML functions (AI, Linear Algebra - Vectors, Arrays, Structs, Strings, File Search, Conversions etc)
MIT License
218 stars 12 forks source link

Script Submission `collision_cone_array` #7

Open tinkerer-red opened 2 weeks ago

tinkerer-red commented 2 weeks ago

Submitting a function, the code is all there to expand this into collision_cone the only note is that if angle is less then 180 both checks need to pass prior to returning the first instance it finds.

Additionally I removed the optional argument array which simulates how collision_*_list functions work, as I found it unneeded in practical use cases. one would simply push the array onto the end of their desired array, and including it only slowed down the function substantially with large object counts.

///   collision_cone_array(x, y, dir, length, angle, object, prec, notme, ordered) {
//  
//  Returns:  - Array
//  
//  x         - The x point of the cone
//  y         - The y point of the cone
//  direction - The direction from x,y the cone expands from
//  length    - The radius (distance in pixels from its center to its edge).
//  angle     - The angle width of the cone
//  obj       - An object, instance, tile map ID, keywords all/other, or array containing these items
//  prec      - Whether the check is based on pixel-perfect collisions (true = slow) or its bounding box in general (false = fast). 
//  notme     - Whether the calling instance, if relevant, should be excluded (true) or not (false). 
//  ordered   - Whether the list should be ordered by distance (true) or not (false).

function collision_cone_array(xx, yy, _dir, _length, _angle, object, prec, notme, ordered=false) {
    //helper function
    static __list_to_arr = function(_list){
        var _array = [];
        var _i = 0, _size = ds_list_size(_list);
        repeat(_size) {
            _array[_i] = _list[| _i ];
        ++_i;}
        return _array;
    };
    static _plane_radius = 1_000_000; // this is just used to make a circle so large it will cover any practical use case, with floating point erros should act as a "object on this side of line" check

    var _list = ds_list_create();
    collision_circle_list(xx, yy, _length, object, prec, notme, _list, ordered);
    var _arr = __list_to_arr(_list)
    ds_list_clear(_list);

    if (_angle == 360)
    || (array_length(_arr) == 0) {
        ds_list_destroy(_list);
        return _arr;
    }

    if (_angle <= 180){
        //  Plane Check 1
        var _ang = _dir + _angle/2 -90;
        var _plane_x = xx+lengthdir_x(_plane_radius, _ang);
        var _plane_y = yy+lengthdir_y(_plane_radius, _ang);
        collision_circle_list(_plane_x, _plane_y, _plane_radius, _arr, prec, notme, _list, ordered);
        var _arr = __list_to_arr(_list)
        ds_list_clear(_list);

        if (array_length(_arr) != 0) {
            //  Plane Check 2
            var _ang = _dir - _angle/2 +90;
            var _plane_x = xx+lengthdir_x(_plane_radius, _ang);
            var _plane_y = yy+lengthdir_y(_plane_radius, _ang);
            collision_circle_list(_plane_x, _plane_y, _plane_radius, _arr, prec, notme, _list, ordered);
            var _arr = __list_to_arr(_list)
        }
    }
    else{  //  if the angle is larger then 180
        //  Plane Check 1
        var _ang = _dir + _angle/2 -90;
        var _plane_x = xx+lengthdir_x(_plane_radius, _ang);
        var _plane_y = yy+lengthdir_y(_plane_radius, _ang);
        collision_circle_list(_plane_x, _plane_y, _plane_radius, _arr, prec, notme, _list, false);

        //  Plane Check 2
        var _ang = _dir - _angle/2 +90;
        var _plane_x = xx+lengthdir_x(_plane_radius, _ang);
        var _plane_y = yy+lengthdir_y(_plane_radius, _ang);
        collision_circle_list(_plane_x, _plane_y, _plane_radius, _arr, prec, notme, _list, false);

        var _arr = __list_to_arr(_list)
        ds_list_clear(_list);

        array_unique_ext(_arr);

        if (ordered) {
            //its faster to just re run a collision check to order these then it is to map an array based on distance
            collision_circle_list(xx, yy, _length, _arr, prec, notme, _list, ordered);
            var _arr = __list_to_arr(_list)
        }
    }

    ds_list_destroy(_list);
    return _arr;
}
tinkerer-red commented 2 weeks ago

example of it in use: https://gyazo.com/508091f2711c833ea9a2b37ebe60ccdf.mp4