Last active
April 27, 2024 04:38
-
-
Save tinkerer-red/9020a3f1f5fd81d262f7da743eb58f7d to your computer and use it in GitHub Desktop.
more collision functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//feather ignore all | |
#region jsDoc | |
/// @func collision_circle_array() | |
/// @desc This function is the same as the collision_circle() function, only instead of just detecting one instance / tile map in collision at a time, it will detect multiple instances or tile maps. | |
/// @param {Real} x1 : The x coordinate of the center of the circle to check. | |
/// @param {Real} y1 : The y coordinate of the center of the circle to check. | |
/// @param {Real} rad : The radius (distance in pixels from its center to its edge). | |
/// @param {Id.TileMapElement | Asset.GMObject | Id.Instance | Constant.All | Constant.Other | Array} obj : Asset or Object Instance or Tile Map Element ID or Array An object, instance, tile map ID, keywords all/other, or array containing these items | |
/// @param {Bool} prec : Whether the check is based on precise collisions (true, which is slower) or its bounding box in general (false, faster). | |
/// @param {Bool} notme : Whether the calling instance, if relevant, should be excluded (true) or not (false). | |
/// @param {Array} array : The array to use to store the IDs of colliding instances. | |
/// @param {Bool} ordered : Whether the list should be ordered by distance (true) or not (false). | |
/// @returns {Array} | |
#endregion | |
function collision_circle_array(_x1, _y1, _radius, _obj, _prec=false, _notme=true, _arr=undefined, _ordered=false) { | |
static __list = ds_list_create(); | |
collision_circle_list(_x1, _y1, _radius, _obj, _prec, _notme, __list, _ordered); | |
_arr = __push_list_into_arr(_arr, __list); | |
ds_list_clear(__list); | |
return _arr; | |
} | |
#region jsDoc | |
/// @func collision_ellipse_array() | |
/// @desc This function is the same as the collision_ellipse() function, only instead of just detecting one instance / tile map in collision at a time, it will detect multiple instances or tile maps. | |
/// @param {Real} x1 : The x coordinate of the left side of the ellipse to check. | |
/// @param {Real} y1 : The y coordinate of the top side of the ellipse to check. | |
/// @param {Real} x2 : The x coordinate of the right side of the ellipse to check. | |
/// @param {Real} y2 : The y coordinate of the bottom side of the ellipse to check. | |
/// @param {Id.TileMapElement | Asset.GMObject | Id.Instance | Constant.All | Constant.Other | Array} obj : Asset or Object Instance or Tile Map Element ID or Array An object, instance, tile map ID, keywords all/other, or array containing these items | |
/// @param {Bool} prec : Whether the check is based on precise collisions (true, which is slower) or its bounding box in general (false, faster). | |
/// @param {Bool} notme : Whether the calling instance, if relevant, should be excluded (true) or not (false). | |
/// @param {Array} array : The array to use to store the IDs of colliding instances. | |
/// @param {Bool} ordered : Whether the list should be ordered by distance (true) or not (false). | |
/// @returns {Array} | |
#endregion | |
function collision_ellipse_array(_x1, _y1, _x2, _y2, _obj, _prec=false, _notme=true, _arr=undefined, _ordered=false) { | |
static __list = ds_list_create(); | |
collision_ellipse_list(_x1, _y1, _x2, _y2, _obj, _prec, _notme, __list, _ordered); | |
_arr = __push_list_into_arr(_arr, __list); | |
ds_list_clear(__list); | |
return _arr; | |
} | |
#region jsDoc | |
/// @func collision_line_array() | |
/// @desc This function is the same as the collision_line() function, only instead of just detecting one instance / tile map in collision at a time, it will detect multiple instances / tile maps. | |
/// @param {Real} x1 : The x coordinate of the start of the line. | |
/// @param {Real} y1 : The y coordinate of the start of the line. | |
/// @param {Real} x2 : The x coordinate of the end of the line. | |
/// @param {Real} y2 : The y coordinate of the end of the line. | |
/// @param {Id.TileMapElement | Asset.GMObject | Id.Instance | Constant.All | Constant.Other | Array} obj : Asset or Object Instance or Tile Map Element ID or Array An object, instance, tile map ID, keywords all/other, or array containing these items | |
/// @param {Bool} prec : Whether the check is based on precise collisions (true, which is slower) or its bounding box in general (false, faster). | |
/// @param {Bool} notme : Whether the calling instance, if relevant, should be excluded (true) or not (false). | |
/// @param {Array} array : The array to use to store the IDs of colliding instances. | |
/// @param {Bool} ordered : Whether the list should be ordered by distance (true) or not (false). | |
/// @returns {Array} | |
#endregion | |
function collision_line_array(_x1, _y1, _x2, _y2, _obj, _prec=false, _notme=true, _arr=undefined, _ordered=false) { | |
static __list = ds_list_create(); | |
collision_line_list(_x1, _y1, _x2, _y2, _obj, _prec, _notme, __list, _ordered); | |
_arr = __push_list_into_arr(_arr, __list); | |
ds_list_clear(__list); | |
return _arr; | |
} | |
#region jsDoc | |
/// @func collision_point_array() | |
/// @desc This function is the same as the collision_circle() function, only instead of just detecting one instance / tile map in collision at a time, it will detect multiple instances or tile maps. | |
/// @param {Real} x : The x coordinate of the point to check. | |
/// @param {Real} y : The y coordinate of the point to check. | |
/// @param {Id.TileMapElement | Asset.GMObject | Id.Instance | Constant.All | Constant.Other | Array} obj : Asset or Object Instance or Tile Map Element ID or Array An object, instance, tile map ID, keywords all/other, or array containing these items | |
/// @param {Bool} prec : Whether the check is based on precise collisions (true, which is slower) or its bounding box in general (false, faster). | |
/// @param {Bool} notme : Whether the calling instance, if relevant, should be excluded (true) or not (false). | |
/// @param {Array} array : The array to use to store the IDs of colliding instances. | |
/// @param {Bool} ordered : Whether the list should be ordered by distance (true) or not (false). | |
/// @returns {Array} | |
#endregion | |
function collision_point_array(_x, _y, _obj, _prec=false, _notme=true, _arr=undefined, _ordered=false) { | |
static __list = ds_list_create(); | |
collision_point_list(_x, _y, _obj, _prec, _notme, __list, _ordered); | |
_arr = __push_list_into_arr(_arr, __list); | |
ds_list_clear(__list); | |
return _arr; | |
} | |
#region jsDoc | |
/// @func collision_rectangle_array() | |
/// @desc This function is the same as the collision_circle() function, only instead of just detecting one instance / tile map in collision at a time, it will detect multiple instances or tile maps. | |
/// @param {Real} x1 : The x coordinate of the left side of the rectangle to check. | |
/// @param {Real} y1 : The y coordinate of the top side of the rectangle to check. | |
/// @param {Real} x2 : The x coordinate of the right side of the rectangle to check. | |
/// @param {Real} y2 : The y coordinate of the bottom side of the rectangle to check. | |
/// @param {Id.TileMapElement | Asset.GMObject | Id.Instance | Constant.All | Constant.Other | Array} obj : Asset or Object Instance or Tile Map Element ID or Array An object, instance, tile map ID, keywords all/other, or array containing these items | |
/// @param {Bool} prec : Whether the check is based on precise collisions (true, which is slower) or its bounding box in general (false, faster). | |
/// @param {Bool} notme : Whether the calling instance, if relevant, should be excluded (true) or not (false). | |
/// @param {Array} array : The array to use to store the IDs of colliding instances. | |
/// @param {Bool} ordered : Whether the list should be ordered by distance (true) or not (false). | |
/// @returns {Array} | |
#endregion | |
function collision_rectangle_array(_x1, _y1, _x2, _y2, _obj, _prec=false, _notme=true, _arr=undefined, _ordered=false) { | |
static __list = ds_list_create(); | |
collision_rectangle_list(_x1, _y1, _x2, _y2, _obj, _prec, _notme, __list, _ordered); | |
_arr = __push_list_into_arr(_arr, __list); | |
ds_list_clear(__list); | |
return _arr; | |
} | |
//Abstract Collisions (making use of circle collides) | |
#region jsDoc | |
/// @func collision_cone_array() | |
/// @desc This function is the same as the collision_circle() function, only instead of just detecting one instance / tile map in collision at a time, it will detect multiple instances or tile maps. | |
/// @param {Real} x : The x coordinate of the left side of the rectangle to check. | |
/// @param {Real} y : The y coordinate of the top side of the rectangle to check. | |
/// @param {Real} direction : The direction of the cone check. | |
/// @param {Real} length : The length of the cone's check distance. | |
/// @param {Real} fov : The field of view of the cone, a value between 0 and 360. | |
/// @param {Id.TileMapElement | Asset.GMObject | Id.Instance | Constant.All | Constant.Other | Array} obj : Asset or Object Instance or Tile Map Element ID or Array An object, instance, tile map ID, keywords all/other, or array containing these items | |
/// @param {Bool} prec : Whether the check is based on precise collisions (true, which is slower) or its bounding box in general (false, faster). | |
/// @param {Bool} notme : Whether the calling instance, if relevant, should be excluded (true) or not (false). | |
/// @param {Array} array : The array to use to store the IDs of colliding instances. | |
/// @param {Bool} ordered : Whether the list should be ordered by distance (true) or not (false). | |
/// @returns {Array} | |
#endregion | |
function collision_cone_array(_x, _y, _direction, _length, _fov, _obj, _prec=false, _notme=true, _arr=undefined, _ordered=false) { | |
static _circle_radius = 1_000_000; | |
if (_fov <= 0 || _length <= 0 || _fov <= 0) return _arr; | |
var _obj_arr = collision_circle_array(_x, _y, _length, _obj, _prec, _notme, undefined, _ordered); | |
if (_fov >= 360) return _arr; | |
var _half_fov = _fov/2; | |
if (_fov <= 180) { | |
//daisy chain checks as "and" check | |
//left | |
var _cx = _x + lengthdir_x(_circle_radius, _direction-_half_fov+90); | |
var _cy = _y + lengthdir_y(_circle_radius, _direction-_half_fov+90); | |
_obj_arr = collision_circle_array(_cx, _cy, _circle_radius, _obj_arr, _prec, _notme, undefined, _ordered); | |
//right | |
_cx = _x + lengthdir_x(_circle_radius, _direction+_half_fov-90); | |
_cy = _y + lengthdir_y(_circle_radius, _direction+_half_fov-90); | |
_obj_arr = collision_circle_array(_cx, _cy, _circle_radius, _obj_arr, _prec, _notme, undefined, _ordered); | |
return _obj_arr; | |
} | |
else { | |
//check as "or" checks | |
//left | |
var _cx = _x + lengthdir_x(_circle_radius, _direction-_half_fov+90); | |
var _cy = _y + lengthdir_y(_circle_radius, _direction-_half_fov+90); | |
var _col_arr = collision_circle_array(_cx, _cy, _circle_radius, _obj_arr, _prec, _notme, undefined, _ordered); | |
//right | |
_cx = _x + lengthdir_x(_circle_radius, _direction+_half_fov-90); | |
_cy = _y + lengthdir_y(_circle_radius, _direction+_half_fov-90); | |
_col_arr = collision_circle_array(_cx, _cy, _circle_radius, _obj_arr, _prec, _notme, _col_arr, _ordered); | |
array_unique_ext(_col_arr); | |
return _col_arr; | |
} | |
} | |
#region jsDoc | |
/// @func collision_triangle_array() | |
/// @desc This function will return all instances inside of a triangle, the point order requires the points to be in clockwise order. | |
/// @param {Real} x1 : The x coordinate of the first line of the triangle to check. | |
/// @param {Real} y1 : The y coordinate of the first line of the triangle to check. | |
/// @param {Real} x2 : The x coordinate of the second line of the triangle to check. | |
/// @param {Real} y2 : The y coordinate of the second line of the triangle to check. | |
/// @param {Real} x3 : The x coordinate of the third line of the triangle to check. | |
/// @param {Real} y3 : The y coordinate of the third line of the triangle to check. | |
/// @param {Id.TileMapElement | Asset.GMObject | Id.Instance | Constant.All | Constant.Other | Array} obj : Asset or Object Instance or Tile Map Element ID or Array An object, instance, tile map ID, keywords all/other, or array containing these items | |
/// @param {Bool} prec : Whether the check is based on precise collisions (true, which is slower) or its bounding box in general (false, faster). | |
/// @param {Bool} notme : Whether the calling instance, if relevant, should be excluded (true) or not (false). | |
/// @param {Array} array : The array to use to store the IDs of colliding instances. | |
/// @param {Bool} ordered : Whether the list should be ordered by distance (true) or not (false). | |
/// @returns {Array} | |
#endregion | |
function collision_triangle_array(_x1, _y1, _x2, _y2, _x3, _y3, _obj, _prec=false, _notme=true, _list=ds_list_create(), _ordered=false) { | |
static _circle_radius = 1_000_000; | |
//for each line | |
//Line AB | |
var _dist_a = point_distance(_x1, _y1, _x2, _y2); | |
var _dir_a = point_direction(_x1, _y1, _x2, _y2); | |
var _xa = _x1 + lengthdir_x(_dist_a/2, _dir_a); | |
var _ya = _y1 + lengthdir_y(_dist_a/2, _dir_a); | |
var _cdir_a = _dir_a-90; | |
//Line BC | |
var _dist_b = point_distance(_x2, _y2, _x3, _y3); | |
var _dir_b = point_direction(_x2, _y2, _x3, _y3); | |
var _xb = _x2 + lengthdir_x(_dist_b/2, _dir_b); | |
var _yb = _y2 + lengthdir_y(_dist_b/2, _dir_b); | |
var _cdir_b = _dir_b-90; | |
//Line CA | |
var _dist_c = point_distance(_x3, _y3, _x1, _y1); | |
var _dir_c = point_direction(_x3, _y3, _x1, _y1); | |
var _xc = _x3 + lengthdir_x(_dist_c/2, _dir_c); | |
var _yc = _y3 + lengthdir_y(_dist_c/2, _dir_c); | |
var _cdir_c = _dir_c-90; | |
_obj_arr = collision_circle_array(_xa+lengthdir_x(_circle_radius, _cdir_a), _ya+lengthdir_y(_circle_radius, _cdir_a), _circle_radius, _obj, _prec, _notme, undefined, _ordered); | |
_obj_arr = collision_circle_array(_xb+lengthdir_x(_circle_radius, _cdir_b), _yb+lengthdir_y(_circle_radius, _cdir_b), _circle_radius, _obj_arr, _prec, _notme, undefined, _ordered); | |
_obj_arr = collision_circle_array(_xc+lengthdir_x(_circle_radius, _cdir_c), _yc+lengthdir_y(_circle_radius, _cdir_c), _circle_radius, _obj_arr, _prec, _notme, undefined, _ordered); | |
return _obj_arr; | |
} | |
#region jsDoc | |
/// @func collision_polygon_array() | |
/// @desc This function is for use with convex polygons, (it can work with some concave polygons but not reliable) | |
/// @param {Array} point_arr : An array of points in a clockwise direction. Format: [x1, y1, x2, y2, x3, y3] | |
/// @param {Id.TileMapElement | Asset.GMObject | Id.Instance | Constant.All | Constant.Other | Array} obj : Asset or Object Instance or Tile Map Element ID or Array An object, instance, tile map ID, keywords all/other, or array containing these items | |
/// @param {Bool} prec : Whether the check is based on precise collisions (true, which is slower) or its bounding box in general (false, faster). | |
/// @param {Bool} notme : Whether the calling instance, if relevant, should be excluded (true) or not (false). | |
/// @param {Array} array : The array to use to store the IDs of colliding instances. | |
/// @param {Bool} ordered : Whether the list should be ordered by distance (true) or not (false). | |
/// @returns {Array} | |
#endregion | |
function collision_polygon_array(_point_arr, _obj, _prec=false, _notme=true, _arr=undefined, _ordered=false) { | |
static _circle_radius = 1_000_000; | |
var _obj_arr = _obj; | |
var _length = array_length(_point_arr); | |
//for each line | |
var _i=0; repeat(_length/2-1) { | |
var _x1 = _point_arr[_i+0]; | |
var _y1 = _point_arr[_i+1]; | |
var _x2 = _point_arr[_i+2]; | |
var _y2 = _point_arr[_i+3]; | |
var _dist = point_distance(_x1, _y1, _x2, _y2); | |
var _dir = point_direction(_x1, _y1, _x2, _y2); | |
var _x = _x1 + lengthdir_x(_dist/2, _dir); | |
var _y = _y1 + lengthdir_y(_dist/2, _dir); | |
var _col_dir = _dir-90; | |
//check the collision | |
_obj_arr = collision_circle_array(_x+lengthdir_x(_circle_radius, _col_dir), _y+lengthdir_y(_circle_radius, _col_dir), _circle_radius, _obj_arr, _prec, _notme, undefined, _ordered); | |
_i+=2;}//end repeat loop | |
//check from last point to first point | |
_x1 = _point_arr[_length-2]; | |
_y1 = _point_arr[_length-1]; | |
_x2 = _point_arr[0]; | |
_y2 = _point_arr[1]; | |
_dist = point_distance(_x1, _y1, _x2, _y2); | |
_dir = point_direction(_x1, _y1, _x2, _y2); | |
_x = _x1 + lengthdir_x(_dist/2, _dir); | |
_y = _y1 + lengthdir_y(_dist/2, _dir); | |
_col_dir = _dir-90; | |
//check the collision | |
_obj_arr = collision_circle_array(_x+lengthdir_x(_circle_radius, _col_dir), _y+lengthdir_y(_circle_radius, _col_dir), _circle_radius, _obj_arr, _prec, _notme, undefined, _ordered); | |
return _obj_arr; | |
} | |
//Intersect functions | |
#region jsDoc | |
/// @func line_intersect() | |
/// @desc Find the intersect of two lines, This function will return undefined if there was no intersect. | |
/// @param {Real} l1x1 : Line 1, x1. | |
/// @param {Real} l1y1 : Line 1, y1. | |
/// @param {Real} l1x2 : Line 1, x2. | |
/// @param {Real} l1y2 : Line 1, y2. | |
/// @param {Real} l2x1 : Line 2, x1. | |
/// @param {Real} l2y1 : Line 2, y1. | |
/// @param {Real} l2x2 : Line 2, x2. | |
/// @param {Real} l2y2 : Line 2, y2. | |
/// @returns {Struct.Point | undefined} | |
#endregion | |
function line_intersect(_l1x1, _l1y1, _l1x2, _l1y2, _l2x1, _l2y1, _l2x2, _l2y2) { | |
var _den = ((_l1x1 - _l1x2) * (_l2y1 - _l2y2)) - ((_l1y1 - _l1y2) * (_l2x1 - _l2x2)); | |
if (_den == 0) { | |
// Lines are parallel, no intersection | |
return undefined; | |
} | |
var t = ((_l1x1 - _l2x1) * (_l2y1 - _l2y2) - (_l1y1 - _l2y1) * (_l2x1 - _l2x2)) / _den; | |
var u = -((_l1x1 - _l1x2) * (_l1y1 - _l2y1) - (_l1y1 - _l1y2) * (_l1x1 - _l2x1)) / _den; | |
if (t >= 0 && t <= 1 && u >= 0 && u <= 1) { | |
var _xx = _l1x1 + t * (_l1x2 - _l1x1); | |
var _yy = _l1y1 + t * (_l1y2 - _l1y1); | |
return { x: _xx, y: _yy }; | |
} else { | |
// Lines don't intersect within the given segments | |
return undefined; | |
} | |
} | |
#region jsDoc | |
/// @func line_circle_intersect() | |
/// @desc Find the intersect of two lines, This function will return undefined if there was no intersect. | |
/// @param {Real} lx1 : Line x1. | |
/// @param {Real} ly1 : Line y1. | |
/// @param {Real} lx2 : Line x2. | |
/// @param {Real} ly2 : Line y2. | |
/// @param {Real} cx : Circle x. | |
/// @param {Real} cy : Circle y. | |
/// @param {Real} cr : Circle r. | |
/// @returns {Array.Struct.Point} | |
#endregion | |
function line_circle_intersect(_lx1, _ly1, _lx2, _ly2, _cx, _cy, _cr) { | |
var intersections = []; | |
var _dx = _lx2 - _lx1; | |
var _dy = _ly2 - _ly1; | |
var a = _dx * _dx + _dy * _dy; | |
var b = 2 * (_dx * (_lx1 - _cx) + _dy * (_ly1 - _cy)); | |
var c = (_lx1 - _cx) * (_lx1 - _cx) + (_ly1 - _cy) * (_ly1 - _cy) - _cr * _cr; | |
var discriminant = b * b - 4 * a * c; | |
if (discriminant >= 0) { | |
// Two possible intersection points | |
var t1 = (-b + sqrt(discriminant)) / (2 * a); | |
var t2 = (-b - sqrt(discriminant)) / (2 * a); | |
var _xx1 = _lx1 + t1 * _dx; | |
var _yy1 = _ly1 + t1 * _dy; | |
var _xx2 = _lx1 + t2 * _dx; | |
var _yy2 = _ly1 + t2 * _dy; | |
// Check if the intersection point(s) lie on the line segment | |
if (t1 >= 0 && t1 <= 1) { | |
array_push(intersections, { x: _xx1, y: _yy1 }); | |
} | |
if (t2 >= 0 && t2 <= 1) { | |
array_push(intersections, { x: _xx2, y: _yy2 }); | |
} | |
} | |
return (array_length(intersections)) ? intersections : undefined; | |
} | |
//helper function | |
#region jsDoc | |
/// @func line_intersect() | |
/// @desc Pushed elements from a ds_list into an array, typically used for conversion but can be used to push a list into an array. | |
/// @param {Array | undefined} arr : The array to write to. Leaving this argument undefined will generate a new array. | |
/// @param {Id.DsList} list : the ds_list to read from. | |
/// @returns {Array | undefined} | |
#endregion | |
function __push_list_into_arr(_arr=undefined, _list) { | |
gml_pragma("forceinline"); | |
if (_arr == undefined) { | |
_arr = array_create(ds_list_size(_list), undefined); | |
var _offset = 0; | |
} | |
else { | |
var _offset = array_length(_arr); | |
array_resize(_arr, _offset+ds_list_size(_list)) | |
} | |
var _i=0; repeat(ds_list_size(_list)) { | |
_arr[_offset+_i] = _list[| _i]; | |
_i+=1;}//end repeat loop | |
return _arr; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment