├── .gitignore ├── .gitattributes ├── datafiles ├── terrain.hm ├── meshes │ ├── merry.vbuff │ ├── tree.vbuff │ └── terrain.vbuff └── shapes │ ├── aabb.vbuff │ ├── grid.vbuff │ ├── obb.vbuff │ ├── plane.vbuff │ ├── point.vbuff │ ├── sphere.vbuff │ ├── sphere.000.vbuff │ ├── capsule_end.vbuff │ └── capsule_middle.vbuff ├── fonts └── fnt_demo │ ├── fnt_demo.png │ ├── fnt_test.old.png │ ├── fnt_test.old.yy │ └── fnt_demo.yy ├── sounds └── MP3_SND_Badlands │ ├── MP3_SND_Badlands.mp3 │ └── MP3_SND_Badlands.yy ├── shaders └── shd_demo │ ├── shd_demo.yy │ ├── shd_demo.vsh │ └── shd_demo.fsh ├── notes └── Col_Changelog │ ├── Col_Changelog.yy │ └── Col_Changelog.txt ├── scripts ├── Col_Tests │ └── Col_Tests.yy ├── Col_World │ ├── Col_World.yy │ └── Col_World.gml ├── Col_Config │ ├── Col_Config.yy │ └── Col_Config.gml ├── Col_Matrix │ ├── Col_Matrix.yy │ └── Col_Matrix.gml ├── Col_Vector │ ├── Col_Vector.yy │ └── Col_Vector.gml ├── Col_Shape_OBB │ └── Col_Shape_OBB.yy ├── Col_Shape_Ray │ ├── Col_Shape_Ray.yy │ └── Col_Shape_Ray.gml ├── screen_to_world │ ├── screen_to_world.yy │ └── screen_to_world.gml ├── Col_Heightmap │ ├── Col_Heightmap.yy │ └── Col_Heightmap.gml ├── Col_SAT_Stuff │ ├── Col_SAT_Stuff.yy │ └── Col_SAT_Stuff.gml ├── Col_Shape_AABB │ ├── Col_Shape_AABB.yy │ └── Col_Shape_AABB.gml ├── Col_Shape_Line │ ├── Col_Shape_Line.yy │ └── Col_Shape_Line.gml ├── Col_Shape_Mesh │ ├── Col_Shape_Mesh.yy │ └── Col_Shape_Mesh.gml ├── Col_Shape_Plane │ ├── Col_Shape_Plane.yy │ └── Col_Shape_Plane.gml ├── Col_Shape_Point │ ├── Col_Shape_Point.yy │ └── Col_Shape_Point.gml ├── Col_Shape_Capsule │ ├── Col_Shape_Capsule.yy │ └── Col_Shape_Capsule.gml ├── Col_Shape_Sphere │ ├── Col_Shape_Sphere.yy │ └── Col_Shape_Sphere.gml ├── Col_Spatial_Hash │ ├── Col_Spatial_Hash.yy │ └── Col_Spatial_Hash.gml ├── Col_Shape_Triangle │ └── Col_Shape_Triangle.yy ├── Col_Camera_Frustum │ ├── Col_Camera_Frustum.yy │ └── Col_Camera_Frustum.gml ├── Col_Helper_Functions │ ├── Col_Helper_Functions.yy │ └── Col_Helper_Functions.gml └── Col_Transformed_Model │ ├── Col_Transformed_Model.yy │ └── Col_Transformed_Model.gml ├── README.md ├── options ├── linux │ └── options_linux.yy ├── main │ └── options_main.yy ├── operagx │ └── options_operagx.yy ├── html5 │ └── options_html5.yy ├── mac │ └── options_mac.yy ├── tvos │ └── options_tvos.yy ├── windows │ └── options_windows.yy ├── ios │ └── options_ios.yy ├── windowsuap │ └── options_windowsuap.yy └── android │ └── options_android.yy ├── objects └── obj_demo │ ├── obj_demo.yy │ ├── Step_0.gml │ ├── Draw_0.gml │ ├── Draw_64.gml │ └── Create_0.gml ├── 3DCollisions.resource_order ├── rooms └── Room1 │ └── Room1.yy ├── 3DCollisions.yyp └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | Build/ -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.yy linguist-language=GML -------------------------------------------------------------------------------- /datafiles/terrain.hm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DragoniteSpam-GameMaker-Tutorials/3DCollisions/HEAD/datafiles/terrain.hm -------------------------------------------------------------------------------- /datafiles/meshes/merry.vbuff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DragoniteSpam-GameMaker-Tutorials/3DCollisions/HEAD/datafiles/meshes/merry.vbuff -------------------------------------------------------------------------------- /datafiles/meshes/tree.vbuff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DragoniteSpam-GameMaker-Tutorials/3DCollisions/HEAD/datafiles/meshes/tree.vbuff -------------------------------------------------------------------------------- /datafiles/shapes/aabb.vbuff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DragoniteSpam-GameMaker-Tutorials/3DCollisions/HEAD/datafiles/shapes/aabb.vbuff -------------------------------------------------------------------------------- /datafiles/shapes/grid.vbuff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DragoniteSpam-GameMaker-Tutorials/3DCollisions/HEAD/datafiles/shapes/grid.vbuff -------------------------------------------------------------------------------- /datafiles/shapes/obb.vbuff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DragoniteSpam-GameMaker-Tutorials/3DCollisions/HEAD/datafiles/shapes/obb.vbuff -------------------------------------------------------------------------------- /datafiles/shapes/plane.vbuff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DragoniteSpam-GameMaker-Tutorials/3DCollisions/HEAD/datafiles/shapes/plane.vbuff -------------------------------------------------------------------------------- /datafiles/shapes/point.vbuff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DragoniteSpam-GameMaker-Tutorials/3DCollisions/HEAD/datafiles/shapes/point.vbuff -------------------------------------------------------------------------------- /fonts/fnt_demo/fnt_demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DragoniteSpam-GameMaker-Tutorials/3DCollisions/HEAD/fonts/fnt_demo/fnt_demo.png -------------------------------------------------------------------------------- /datafiles/meshes/terrain.vbuff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DragoniteSpam-GameMaker-Tutorials/3DCollisions/HEAD/datafiles/meshes/terrain.vbuff -------------------------------------------------------------------------------- /datafiles/shapes/sphere.vbuff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DragoniteSpam-GameMaker-Tutorials/3DCollisions/HEAD/datafiles/shapes/sphere.vbuff -------------------------------------------------------------------------------- /datafiles/shapes/sphere.000.vbuff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DragoniteSpam-GameMaker-Tutorials/3DCollisions/HEAD/datafiles/shapes/sphere.000.vbuff -------------------------------------------------------------------------------- /fonts/fnt_demo/fnt_test.old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DragoniteSpam-GameMaker-Tutorials/3DCollisions/HEAD/fonts/fnt_demo/fnt_test.old.png -------------------------------------------------------------------------------- /datafiles/shapes/capsule_end.vbuff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DragoniteSpam-GameMaker-Tutorials/3DCollisions/HEAD/datafiles/shapes/capsule_end.vbuff -------------------------------------------------------------------------------- /datafiles/shapes/capsule_middle.vbuff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DragoniteSpam-GameMaker-Tutorials/3DCollisions/HEAD/datafiles/shapes/capsule_middle.vbuff -------------------------------------------------------------------------------- /sounds/MP3_SND_Badlands/MP3_SND_Badlands.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DragoniteSpam-GameMaker-Tutorials/3DCollisions/HEAD/sounds/MP3_SND_Badlands/MP3_SND_Badlands.mp3 -------------------------------------------------------------------------------- /shaders/shd_demo/shd_demo.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMShader":"", 3 | "%Name":"shd_demo", 4 | "name":"shd_demo", 5 | "parent":{ 6 | "name":"Test stuff", 7 | "path":"folders/Test stuff.yy", 8 | }, 9 | "resourceType":"GMShader", 10 | "resourceVersion":"2.0", 11 | "type":1, 12 | } -------------------------------------------------------------------------------- /notes/Col_Changelog/Col_Changelog.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMNotes":"v1", 3 | "%Name":"Col_Changelog", 4 | "name":"Col_Changelog", 5 | "parent":{ 6 | "name":"Collision Stuff", 7 | "path":"folders/Collision Stuff.yy", 8 | }, 9 | "resourceType":"GMNotes", 10 | "resourceVersion":"2.0", 11 | } -------------------------------------------------------------------------------- /scripts/Col_Tests/Col_Tests.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Tests", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Tests", 7 | "parent":{ 8 | "name":"Test stuff", 9 | "path":"folders/Test stuff.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_World/Col_World.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_World", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_World", 7 | "parent":{ 8 | "name":"Collision Stuff", 9 | "path":"folders/Collision Stuff.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 3D Collisions in GameMaker 2 | 3 | Ever wanted to implement 3D collisions in native GML, without the need for fancy DLL extensions? Here's how you can do just that! 4 | 5 | Video tutorial: 6 | 7 | [![YouTube](https://i.ytimg.com/vi/o7kjtTEMpeU/hqdefault.jpg)](https://www.youtube.com/playlist?list=PL_hT--4HOvrf_VYo26LNl3zN5uwfuC3CC) 8 | -------------------------------------------------------------------------------- /scripts/Col_Config/Col_Config.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Config", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Config", 7 | "parent":{ 8 | "name":"Collision Stuff", 9 | "path":"folders/Collision Stuff.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_Matrix/Col_Matrix.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Matrix", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Matrix", 7 | "parent":{ 8 | "name":"Collision Stuff", 9 | "path":"folders/Collision Stuff.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_Vector/Col_Vector.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Vector", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Vector", 7 | "parent":{ 8 | "name":"Collision Stuff", 9 | "path":"folders/Collision Stuff.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_Shape_OBB/Col_Shape_OBB.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Shape_OBB", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Shape_OBB", 7 | "parent":{ 8 | "name":"Shapes", 9 | "path":"folders/Collision Stuff/Shapes.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_Shape_Ray/Col_Shape_Ray.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Shape_Ray", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Shape_Ray", 7 | "parent":{ 8 | "name":"Shapes", 9 | "path":"folders/Collision Stuff/Shapes.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/screen_to_world/screen_to_world.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"screen_to_world", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"screen_to_world", 7 | "parent":{ 8 | "name":"3DCollisions", 9 | "path":"3DCollisions.yyp", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_Heightmap/Col_Heightmap.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Heightmap", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Heightmap", 7 | "parent":{ 8 | "name":"Collision Stuff", 9 | "path":"folders/Collision Stuff.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_SAT_Stuff/Col_SAT_Stuff.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_SAT_Stuff", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_SAT_Stuff", 7 | "parent":{ 8 | "name":"Collision Stuff", 9 | "path":"folders/Collision Stuff.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_Shape_AABB/Col_Shape_AABB.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Shape_AABB", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Shape_AABB", 7 | "parent":{ 8 | "name":"Shapes", 9 | "path":"folders/Collision Stuff/Shapes.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_Shape_Line/Col_Shape_Line.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Shape_Line", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Shape_Line", 7 | "parent":{ 8 | "name":"Shapes", 9 | "path":"folders/Collision Stuff/Shapes.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_Shape_Mesh/Col_Shape_Mesh.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Shape_Mesh", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Shape_Mesh", 7 | "parent":{ 8 | "name":"Shapes", 9 | "path":"folders/Collision Stuff/Shapes.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_Shape_Plane/Col_Shape_Plane.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Shape_Plane", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Shape_Plane", 7 | "parent":{ 8 | "name":"Shapes", 9 | "path":"folders/Collision Stuff/Shapes.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_Shape_Point/Col_Shape_Point.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Shape_Point", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Shape_Point", 7 | "parent":{ 8 | "name":"Shapes", 9 | "path":"folders/Collision Stuff/Shapes.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_Shape_Capsule/Col_Shape_Capsule.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Shape_Capsule", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Shape_Capsule", 7 | "parent":{ 8 | "name":"Shapes", 9 | "path":"folders/Collision Stuff/Shapes.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_Shape_Sphere/Col_Shape_Sphere.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Shape_Sphere", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Shape_Sphere", 7 | "parent":{ 8 | "name":"Shapes", 9 | "path":"folders/Collision Stuff/Shapes.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_Spatial_Hash/Col_Spatial_Hash.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Spatial_Hash", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Spatial_Hash", 7 | "parent":{ 8 | "name":"Collision Stuff", 9 | "path":"folders/Collision Stuff.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_Shape_Triangle/Col_Shape_Triangle.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Shape_Triangle", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Shape_Triangle", 7 | "parent":{ 8 | "name":"Shapes", 9 | "path":"folders/Collision Stuff/Shapes.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_Camera_Frustum/Col_Camera_Frustum.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Camera_Frustum", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Camera_Frustum", 7 | "parent":{ 8 | "name":"Collision Stuff", 9 | "path":"folders/Collision Stuff.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_Helper_Functions/Col_Helper_Functions.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Helper_Functions", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Helper_Functions", 7 | "parent":{ 8 | "name":"Collision Stuff", 9 | "path":"folders/Collision Stuff.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /scripts/Col_SAT_Stuff/Col_SAT_Stuff.gml: -------------------------------------------------------------------------------- 1 | function ColInterval(val_min, val_max) constructor { 2 | self.val_min = val_min; 3 | self.val_max = val_max; 4 | } 5 | 6 | function col_overlap_axis(shape1, shape2, axis) { 7 | var a = shape1.GetInterval(axis); 8 | var b = shape2.GetInterval(axis); 9 | return (b.val_min <= a.val_max) && (a.val_min <= b.val_max); 10 | } -------------------------------------------------------------------------------- /scripts/Col_Transformed_Model/Col_Transformed_Model.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMScript":"v1", 3 | "%Name":"Col_Transformed_Model", 4 | "isCompatibility":false, 5 | "isDnD":false, 6 | "name":"Col_Transformed_Model", 7 | "parent":{ 8 | "name":"Shapes", 9 | "path":"folders/Collision Stuff/Shapes.yy", 10 | }, 11 | "resourceType":"GMScript", 12 | "resourceVersion":"2.0", 13 | } -------------------------------------------------------------------------------- /shaders/shd_demo/shd_demo.vsh: -------------------------------------------------------------------------------- 1 | attribute vec3 in_Position; 2 | attribute vec3 in_Normal; 3 | attribute vec4 in_Colour; 4 | 5 | varying vec4 v_vColour; 6 | varying vec3 v_vWorldNormal; 7 | 8 | void main() { 9 | gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * vec4(in_Position, 1); 10 | v_vWorldNormal = (gm_Matrices[MATRIX_WORLD] * vec4(in_Normal, 0)).xyz; 11 | v_vColour = in_Colour; 12 | } -------------------------------------------------------------------------------- /shaders/shd_demo/shd_demo.fsh: -------------------------------------------------------------------------------- 1 | varying vec4 v_vColour; 2 | varying vec3 v_vWorldNormal; 3 | 4 | //uniform vec3 lightDirection; 5 | //uniform vec3 lightColor; 6 | 7 | void main() { 8 | vec3 lightDirection = vec3(-1, -0.9, -0.8); 9 | vec3 lightColor = vec3(1, 1, 1); 10 | vec4 color = vec4(lightColor, 1); 11 | gl_FragColor = v_vColour * max(0.25, -dot(normalize(v_vWorldNormal), normalize(lightDirection))) * color; 12 | gl_FragColor.a = 1.; 13 | } -------------------------------------------------------------------------------- /scripts/Col_Config/Col_Config.gml: -------------------------------------------------------------------------------- 1 | #macro COL_MIN_TREE_DENSITY 50 // tree structures won't subdivide unless they have more than this number of items inside them 2 | #macro COL_MESH_MAX_SPLITS 3 // trimesh octrees will use the above setting before splitting, but won't go more than this many levels deep 3 | #macro COL_DEFAULT_SPHERE_DISPLACEMENT_ATTEMPTS 5 // the default maximum number of attempts the system will make to displace a sphere from collision in a world -------------------------------------------------------------------------------- /sounds/MP3_SND_Badlands/MP3_SND_Badlands.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMSound":"", 3 | "%Name":"MP3_SND_Badlands", 4 | "audioGroupId":{ 5 | "name":"audiogroup_default", 6 | "path":"audiogroups/audiogroup_default", 7 | }, 8 | "bitDepth":1, 9 | "bitRate":128, 10 | "compression":0, 11 | "conversionMode":0, 12 | "duration":75.0498, 13 | "name":"MP3_SND_Badlands", 14 | "parent":{ 15 | "name":"Soundscapes", 16 | "path":"folders/Sounds/Soundscapes.yy", 17 | }, 18 | "preload":false, 19 | "resourceType":"GMSound", 20 | "resourceVersion":"2.0", 21 | "sampleRate":44100, 22 | "soundFile":"MP3_SND_Badlands.mp3", 23 | "type":0, 24 | "volume":1.0, 25 | } -------------------------------------------------------------------------------- /options/linux/options_linux.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMLinuxOptions":"", 3 | "%Name":"Linux", 4 | "name":"Linux", 5 | "option_linux_allow_fullscreen":false, 6 | "option_linux_disable_sandbox":false, 7 | "option_linux_display_cursor":true, 8 | "option_linux_display_name":"Created with GameMaker Studio 2", 9 | "option_linux_display_splash":false, 10 | "option_linux_enable_steam":false, 11 | "option_linux_homepage":"http://www.yoyogames.com", 12 | "option_linux_icon":"${base_options_dir}/linux/icons/64.png", 13 | "option_linux_interpolate_pixels":true, 14 | "option_linux_long_desc":"", 15 | "option_linux_maintainer_email":"", 16 | "option_linux_resize_window":false, 17 | "option_linux_scale":0, 18 | "option_linux_short_desc":"", 19 | "option_linux_splash_screen":"${base_options_dir}/linux/splash/splash.png", 20 | "option_linux_start_fullscreen":false, 21 | "option_linux_sync":false, 22 | "option_linux_texture_page":"2048x2048", 23 | "option_linux_version":"1.0.0.0", 24 | "resourceType":"GMLinuxOptions", 25 | "resourceVersion":"2.0", 26 | } -------------------------------------------------------------------------------- /options/main/options_main.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMMainOptions":"v5", 3 | "%Name":"Main", 4 | "name":"Main", 5 | "option_allow_instance_change":true, 6 | "option_audio_error_behaviour":true, 7 | "option_author":"", 8 | "option_collision_compatibility":true, 9 | "option_copy_on_write_enabled":false, 10 | "option_draw_colour":4294967295, 11 | "option_gameguid":"064c675f-0ef6-46c3-9bcb-fc2e08da9198", 12 | "option_gameid":"0", 13 | "option_game_speed":60, 14 | "option_legacy_json_parsing":true, 15 | "option_legacy_number_conversion":true, 16 | "option_legacy_other_behaviour":true, 17 | "option_legacy_primitive_drawing":true, 18 | "option_mips_for_3d_textures":false, 19 | "option_remove_unused_assets":false, 20 | "option_sci_usesci":false, 21 | "option_spine_licence":false, 22 | "option_steam_app_id":"0", 23 | "option_template_description":null, 24 | "option_template_icon":"${base_options_dir}/main/template_icon.png", 25 | "option_template_image":"${base_options_dir}/main/template_image.png", 26 | "option_window_colour":255, 27 | "resourceType":"GMMainOptions", 28 | "resourceVersion":"2.0", 29 | } -------------------------------------------------------------------------------- /scripts/screen_to_world/screen_to_world.gml: -------------------------------------------------------------------------------- 1 | function screen_to_world(x, y, v, p) { 2 | /* 3 | Transforms a 2D coordinate (in window space) to a 3D vector. 4 | Returns an array of the following format: 5 | [dx, dy, dz, ox, oy, oz] 6 | where [dx, dy, dz] is the direction vector and [ox, oy, oz] is the origin of the ray. 7 | Works for both orthographic and perspective projections. 8 | Script created by TheSnidr 9 | (slightly modified by @dragonitespam) 10 | */ 11 | 12 | var mx = 2 * (x / window_get_width() - .5) / p[0]; 13 | var my = 2 * (y / window_get_height() - .5) / p[5]; 14 | var camX = - (v[12] * v[0] + v[13] * v[1] + v[14] * v[2]); 15 | var camY = - (v[12] * v[4] + v[13] * v[5] + v[14] * v[6]); 16 | var camZ = - (v[12] * v[8] + v[13] * v[9] + v[14] * v[10]); 17 | 18 | if (p[15] == 0) { //This is a perspective projection 19 | return new Vector3(v[2] + mx * v[0] + my * v[1], v[6] + mx * v[4] + my * v[5], v[10] + mx * v[8] + my * v[9]); 20 | } else { //This is an ortho projection 21 | return new Vector3(v[2], v[6], v[10]); 22 | } 23 | } -------------------------------------------------------------------------------- /options/operagx/options_operagx.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMOperaGXOptions":"v1", 3 | "%Name":"operagx", 4 | "name":"operagx", 5 | "option_operagx_display_cursor":true, 6 | "option_operagx_editUrl":"", 7 | "option_operagx_game_name":"${project_name}", 8 | "option_operagx_guid":"", 9 | "option_operagx_internalShareUrl":"", 10 | "option_operagx_interpolate_pixels":true, 11 | "option_operagx_mod_editUrl":"", 12 | "option_operagx_mod_game_name":"${project_name}", 13 | "option_operagx_mod_guid":"", 14 | "option_operagx_mod_internalShareUrl":"", 15 | "option_operagx_mod_next_version":"1.0.0.0", 16 | "option_operagx_mod_publicShareUrl":"", 17 | "option_operagx_mod_team_id":"", 18 | "option_operagx_mod_team_name":"", 19 | "option_operagx_mod_version":"1.0.0.0", 20 | "option_operagx_next_version":"1.0.0.0", 21 | "option_operagx_publicShareUrl":"", 22 | "option_operagx_scale":0, 23 | "option_operagx_team_id":"", 24 | "option_operagx_team_name":"", 25 | "option_operagx_texture_page":"2048x2048", 26 | "option_operagx_transparent_background":false, 27 | "option_operagx_version":"1.0.0.0", 28 | "resourceType":"GMOperaGXOptions", 29 | "resourceVersion":"2.0", 30 | } -------------------------------------------------------------------------------- /options/html5/options_html5.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMHtml5Options":"", 3 | "%Name":"HTML5", 4 | "name":"HTML5", 5 | "option_html5_allow_fullscreen":true, 6 | "option_html5_browser_title":"Created with GameMaker Studio 2", 7 | "option_html5_centregame":false, 8 | "option_html5_display_cursor":true, 9 | "option_html5_facebook_app_display_name":"", 10 | "option_html5_facebook_id":"", 11 | "option_html5_flurry_enable":false, 12 | "option_html5_flurry_id":"", 13 | "option_html5_foldername":"html5game", 14 | "option_html5_google_analytics_enable":false, 15 | "option_html5_google_tracking_id":"", 16 | "option_html5_icon":"${base_options_dir}/html5/fav.ico", 17 | "option_html5_index":"", 18 | "option_html5_interpolate_pixels":true, 19 | "option_html5_jsprepend":"", 20 | "option_html5_loadingbar":"", 21 | "option_html5_localrunalert":true, 22 | "option_html5_outputdebugtoconsole":true, 23 | "option_html5_outputname":"index.html", 24 | "option_html5_scale":0, 25 | "option_html5_splash_png":"${base_options_dir}/html5/splash.png", 26 | "option_html5_texture_page":"2048x2048", 27 | "option_html5_usebuiltinfont":true, 28 | "option_html5_usebuiltinparticles":true, 29 | "option_html5_usesplash":false, 30 | "option_html5_use_facebook":false, 31 | "option_html5_version":"1.0.0.0", 32 | "option_html5_webgl":2, 33 | "resourceType":"GMHtml5Options", 34 | "resourceVersion":"2.0", 35 | } -------------------------------------------------------------------------------- /scripts/Col_Matrix/Col_Matrix.gml: -------------------------------------------------------------------------------- 1 | function mat4_determinant(mat) { 2 | var r1 = mat[ 5] * mat[10] * mat[15] - mat[ 5] * mat[11] * mat[14] - mat[ 9] * mat[ 6] * mat[15] + mat[ 9] * mat[ 7] * mat[14] + mat[13] * mat[ 6] * mat[11] - mat[13] * mat[ 7] * mat[10]; 3 | var r2 = -mat[ 4] * mat[10] * mat[15] + mat[ 4] * mat[11] * mat[14] + mat[ 8] * mat[ 6] * mat[15] - mat[ 8] * mat[ 7] * mat[14] - mat[12] * mat[ 6] * mat[11] + mat[12] * mat[ 7] * mat[10]; 4 | var r3 = mat[ 4] * mat[ 9] * mat[15] - mat[ 4] * mat[11] * mat[13] - mat[ 8] * mat[ 5] * mat[15] + mat[ 8] * mat[ 7] * mat[13] + mat[12] * mat[ 5] * mat[11] - mat[12] * mat[ 7] * mat[ 9]; 5 | var r4 = -mat[ 4] * mat[ 9] * mat[14] + mat[ 4] * mat[10] * mat[13] + mat[ 8] * mat[ 5] * mat[14] - mat[ 8] * mat[ 6] * mat[13] - mat[12] * mat[ 5] * mat[10] + mat[12] * mat[ 6] * mat[ 9]; 6 | 7 | return mat[0] * r1 + mat[1] * r2 + mat[2] * r3 + mat[3] * r4; 8 | } 9 | 10 | function mat4_mul_point(mat, point) { 11 | static transformed_point = [0, 0, 0, 0]; 12 | matrix_transform_vertex(mat, point.x, point.y, point.z, 1, transformed_point); 13 | return new Vector3(transformed_point[0], transformed_point[1], transformed_point[2]); 14 | } 15 | 16 | function mat4_mul_vector(mat, vec) { 17 | static transformed_point = [0, 0, 0, 0]; 18 | matrix_transform_vertex(mat, vec.x, vec.y, vec.z, 0, transformed_point); 19 | return new Vector3(transformed_point[0], transformed_point[1], transformed_point[2]); 20 | } -------------------------------------------------------------------------------- /scripts/Col_Heightmap/Col_Heightmap.gml: -------------------------------------------------------------------------------- 1 | function ColHeightmap(buffer, w, h, scale) constructor { 2 | self.buffer = buffer; 3 | self.w = w; 4 | self.h = h; 5 | self.scale = scale; 6 | 7 | static GetHeight = function(x, y) { 8 | x /= self.scale; 9 | y /= self.scale; 10 | 11 | x = clamp(x, 0, self.w - 1); 12 | y = clamp(y, 0, self.h - 1); 13 | 14 | var data_type_size = buffer_sizeof(buffer_f32); 15 | 16 | var x0 = floor(x); 17 | var y0 = floor(y); 18 | var x1 = ceil(x); 19 | var y1 = ceil(y); 20 | 21 | var index00 = x0 * self.h + y0; 22 | var index01 = x0 * self.h + y1; 23 | var index10 = x1 * self.h + y0; 24 | var index11 = x1 * self.h + y1; 25 | 26 | var z00 = buffer_peek(self.buffer, index00 * data_type_size, buffer_f32); 27 | var z01 = buffer_peek(self.buffer, index01 * data_type_size, buffer_f32); 28 | var z10 = buffer_peek(self.buffer, index10 * data_type_size, buffer_f32); 29 | var z11 = buffer_peek(self.buffer, index11 * data_type_size, buffer_f32); 30 | 31 | var z_top = lerp(z00, z10, frac(x)); 32 | var z_bottom = lerp(z01, z11, frac(x)); 33 | var z_final = lerp(z_top, z_bottom, frac(y)); 34 | 35 | return z_final * self.scale; 36 | }; 37 | 38 | static Delete = function() { 39 | buffer_delete(self.buffer); 40 | }; 41 | } -------------------------------------------------------------------------------- /objects/obj_demo/obj_demo.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMObject":"", 3 | "%Name":"obj_demo", 4 | "eventList":[ 5 | {"$GMEvent":"v1","%Name":"","collisionObjectId":null,"eventNum":0,"eventType":0,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, 6 | {"$GMEvent":"v1","%Name":"","collisionObjectId":null,"eventNum":0,"eventType":8,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, 7 | {"$GMEvent":"v1","%Name":"","collisionObjectId":null,"eventNum":0,"eventType":3,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, 8 | {"$GMEvent":"v1","%Name":"","collisionObjectId":null,"eventNum":64,"eventType":8,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, 9 | ], 10 | "managed":true, 11 | "name":"obj_demo", 12 | "overriddenProperties":[], 13 | "parent":{ 14 | "name":"Test stuff", 15 | "path":"folders/Test stuff.yy", 16 | }, 17 | "parentObjectId":null, 18 | "persistent":false, 19 | "physicsAngularDamping":0.1, 20 | "physicsDensity":0.5, 21 | "physicsFriction":0.2, 22 | "physicsGroup":1, 23 | "physicsKinematic":false, 24 | "physicsLinearDamping":0.1, 25 | "physicsObject":false, 26 | "physicsRestitution":0.1, 27 | "physicsSensor":false, 28 | "physicsShape":1, 29 | "physicsShapePoints":[], 30 | "physicsStartAwake":true, 31 | "properties":[], 32 | "resourceType":"GMObject", 33 | "resourceVersion":"2.0", 34 | "solid":false, 35 | "spriteId":null, 36 | "spriteMaskId":null, 37 | "visible":true, 38 | } -------------------------------------------------------------------------------- /options/mac/options_mac.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMMacOptions":"", 3 | "%Name":"macOS", 4 | "name":"macOS", 5 | "option_mac_allow_fullscreen":false, 6 | "option_mac_allow_incoming_network":false, 7 | "option_mac_allow_outgoing_network":false, 8 | "option_mac_apple_sign_in":false, 9 | "option_mac_app_category":"Games", 10 | "option_mac_app_id":"com.company.game", 11 | "option_mac_arm64":true, 12 | "option_mac_build_app_store":false, 13 | "option_mac_build_number":0, 14 | "option_mac_copyright":"", 15 | "option_mac_disable_sandbox":false, 16 | "option_mac_display_cursor":true, 17 | "option_mac_display_name":"Created with GameMaker Studio 2", 18 | "option_mac_enable_retina":false, 19 | "option_mac_enable_steam":false, 20 | "option_mac_icon_png":"${base_options_dir}/mac/icons/1024.png", 21 | "option_mac_installer_background_png":"${base_options_dir}/mac/splash/installer_background.png", 22 | "option_mac_interpolate_pixels":true, 23 | "option_mac_menu_dock":false, 24 | "option_mac_min_version":"10.10", 25 | "option_mac_output_dir":"~/gamemakerstudio2", 26 | "option_mac_resize_window":false, 27 | "option_mac_scale":0, 28 | "option_mac_signing_identity":"Developer ID Application:", 29 | "option_mac_splash_png":"${base_options_dir}/mac/splash/splash.png", 30 | "option_mac_start_fullscreen":false, 31 | "option_mac_team_id":"", 32 | "option_mac_texture_page":"2048x2048", 33 | "option_mac_version":"1.0.0.0", 34 | "option_mac_vsync":false, 35 | "option_mac_x86_64":true, 36 | "resourceType":"GMMacOptions", 37 | "resourceVersion":"2.0", 38 | } -------------------------------------------------------------------------------- /options/tvos/options_tvos.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMtvOSOptions":"v1", 3 | "%Name":"tvOS", 4 | "name":"tvOS", 5 | "option_tvos_build_number":0, 6 | "option_tvos_bundle_name":"com.company.game", 7 | "option_tvos_display_cursor":false, 8 | "option_tvos_display_name":"Made in GameMaker Studio 2", 9 | "option_tvos_enable_broadcast":false, 10 | "option_tvos_icon_1280":"${base_options_dir}/tvos/icons/1280.png", 11 | "option_tvos_icon_400":"${base_options_dir}/tvos/icons/400.png", 12 | "option_tvos_icon_400_2x":"${base_options_dir}/tvos/icons/400_2x.png", 13 | "option_tvos_interpolate_pixels":true, 14 | "option_tvos_min_version":"10.0", 15 | "option_tvos_output_dir":"~/GameMakerStudio2/tvOS", 16 | "option_tvos_podfile_lock_path":"${options_dir}\\tvos\\Podfile.lock", 17 | "option_tvos_podfile_path":"${options_dir}\\tvos\\Podfile", 18 | "option_tvos_scale":0, 19 | "option_tvos_splashscreen":"${base_options_dir}/tvos/splash/splash.png", 20 | "option_tvos_splashscreen_2x":"${base_options_dir}/tvos/splash/splash_2x.png", 21 | "option_tvos_splash_time":0, 22 | "option_tvos_team_id":"", 23 | "option_tvos_texture_page":"2048x2048", 24 | "option_tvos_topshelf":"${base_options_dir}/tvos/topshelf/topshelf.png", 25 | "option_tvos_topshelf_2x":"${base_options_dir}/tvos/topshelf/topshelf_2x.png", 26 | "option_tvos_topshelf_wide":"${base_options_dir}/tvos/topshelf/topshelf_wide.png", 27 | "option_tvos_topshelf_wide_2x":"${base_options_dir}/tvos/topshelf/topshelf_wide_2x.png", 28 | "option_tvos_version":"1.0.0.0", 29 | "resourceType":"GMtvOSOptions", 30 | "resourceVersion":"2.0", 31 | } -------------------------------------------------------------------------------- /options/windows/options_windows.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMWindowsOptions":"v1", 3 | "%Name":"Windows", 4 | "name":"Windows", 5 | "option_windows_allow_fullscreen_switching":false, 6 | "option_windows_borderless":false, 7 | "option_windows_company_info":"YoYo Games Ltd", 8 | "option_windows_copyright_info":"", 9 | "option_windows_copy_exe_to_dest":false, 10 | "option_windows_d3dswapeffectdiscard":false, 11 | "option_windows_description_info":"A GameMaker Studio 2 Game", 12 | "option_windows_disable_sandbox":false, 13 | "option_windows_display_cursor":true, 14 | "option_windows_display_name":"Created with GameMaker Studio 2", 15 | "option_windows_enable_steam":false, 16 | "option_windows_executable_name":"${project_name}.exe", 17 | "option_windows_icon":"${base_options_dir}/windows/icons/icon.ico", 18 | "option_windows_installer_finished":"${base_options_dir}/windows/installer/finished.bmp", 19 | "option_windows_installer_header":"${base_options_dir}/windows/installer/header.bmp", 20 | "option_windows_interpolate_pixels":false, 21 | "option_windows_license":"${base_options_dir}/windows/installer/license.txt", 22 | "option_windows_nsis_file":"${base_options_dir}/windows/installer/nsis_script.nsi", 23 | "option_windows_product_info":"Created with GameMaker Studio 2", 24 | "option_windows_resize_window":false, 25 | "option_windows_save_location":0, 26 | "option_windows_scale":0, 27 | "option_windows_sleep_margin":10, 28 | "option_windows_splash_screen":"${base_options_dir}/windows/splash/splash.png", 29 | "option_windows_start_fullscreen":false, 30 | "option_windows_steam_use_alternative_launcher":false, 31 | "option_windows_texture_page":"2048x2048", 32 | "option_windows_use_splash":false, 33 | "option_windows_version":"1.2.1.0", 34 | "option_windows_vsync":false, 35 | "resourceType":"GMWindowsOptions", 36 | "resourceVersion":"2.0", 37 | } -------------------------------------------------------------------------------- /scripts/Col_Helper_Functions/Col_Helper_Functions.gml: -------------------------------------------------------------------------------- 1 | function NewColAABBFromMinMax(point_min, point_max) { 2 | return new ColAABB(new Vector3( 3 | mean(point_min.x, point_max.x), 4 | mean(point_min.y, point_max.y), 5 | mean(point_min.z, point_max.z) 6 | ), new Vector3( 7 | abs((point_max.x - point_min.x) / 2), 8 | abs((point_max.y - point_min.y) / 2), 9 | abs((point_max.z - point_min.z) / 2) 10 | )); 11 | } 12 | 13 | function NewColRayFromPoints(start, finish) { 14 | return new ColRay(start, new Vector3(finish.x - start.x, finish.y - start.y, finish.z - start.z)); 15 | } 16 | 17 | function RaycastHitInformation() constructor { 18 | self.shape = undefined; 19 | self.point = undefined; 20 | self.distance = infinity; 21 | self.normal = undefined; 22 | 23 | static Update = function(distance, shape, point, normal) { 24 | if (distance < self.distance) { 25 | self.distance = distance; 26 | self.shape = shape; 27 | self.point = point; 28 | self.normal = normal; 29 | } 30 | }; 31 | 32 | static Clear = function() { 33 | self.shape = undefined; 34 | self.point = undefined; 35 | self.distance = infinity; 36 | self.normal = undefined; 37 | }; 38 | } 39 | 40 | function col_project_onto_plane(vertex, origin, norm, e1, e2) { 41 | var dx = vertex.x - origin.x, dy = vertex.y - origin.y, dz = vertex.z - origin.z; 42 | return new Vector3( 43 | dot_product_3d(dx, dy, dz, e1.x, e1.y, e1.z), 44 | dot_product_3d(dx, dy, dz, e2.x, e2.y, e2.z), 45 | 0 46 | ); 47 | } 48 | 49 | function col_lines_intersect(a, b, c, d) { 50 | return (col_points_are_counterclockwise(a, c, d) != col_points_are_counterclockwise(b, c, d)) && 51 | (col_points_are_counterclockwise(a, b, c) != col_points_are_counterclockwise(a, b, d)); 52 | } 53 | 54 | function col_points_are_counterclockwise(a, b, c) { 55 | return ((c.y - a.y) * (b.x - a.x)) < ((b.y - a.y) * (c.x - a.x)); 56 | } -------------------------------------------------------------------------------- /notes/Col_Changelog/Col_Changelog.txt: -------------------------------------------------------------------------------- 1 | Version 1.3 2 | 3 | - Optimized AABB/OBB by like 40% 4 | - This also means good things for OBB/trimesh 5 | - Optimized trimesh/everything by "it depends"% 6 | - You still shouldn't use these if you don't have to 7 | - Dropped support for anything older than 2024.14, so that we can take full advantage of a variety of new optimizations that were added then 8 | - Native matrix_inverse without a fallback solution 9 | - Native sphere visiblity checks are much faster than the ones we did ourselves 10 | - A bunch of the matrix functions can now take an output array so we don't have to re-allocate a bunch of other arrays 11 | 12 | Version 1.2 13 | 14 | - Added an bonus GetObjectsInFrustumFast() method which uses the native sphere_is_visible() function added in 2024.1400 betas 15 | - In my testing it runs in about half the time as the original 16 | - This might become the default version eventually, unless I find something wrong with it 17 | 18 | Version 1.1 19 | 20 | - A bunch of optimizations 21 | - A whole bunch of new `Vector` functions (including a Vector2 class), just for fun 22 | - Removed the Matrix classes in favor of just using the GameMaker 16-element array matrices, because those were confusing and using them added more overhead that I really like 23 | - If you construct a ColTransformedModel (or call the Set() method that goes with them) with an array of ColTriangles instead of a ColMesh, a ColMesh will be created for you 24 | - This will create a new ColMesh from scratch, so only do this if each Transformed Model is to be associated with a unique Mesh 25 | - ColWorld now takes an Octree, **Quadtree**, or _Spatial Hash_ as its preferred acceleration structure instead of creating one for you 26 | - ColWorld::CheckRay can now take a maximum distance, discarding any hits that are farther away 27 | - Added `COL_MIN_TREE_DENSITY` to set the object threshold for when a tree structure is subdivided, which can speed them up by a fair amount 28 | - Shapes attached to objects also have an .object reference that they can refer back to 29 | 30 | [click here for the answer to life, the universe, and everything](https://www.youtube.com/watch?v=dQw4w9WgXcQ) 31 | 32 | Version 1.0 33 | 34 | - Initial release -------------------------------------------------------------------------------- /objects/obj_demo/Step_0.gml: -------------------------------------------------------------------------------- 1 | if (keyboard_check(ord("A"))) { 2 | dir++; 3 | } 4 | if (keyboard_check(ord("D"))) { 5 | dir--; 6 | } 7 | if (keyboard_check(ord("W"))) { 8 | pitch = max(--pitch, -80); 9 | } 10 | if (keyboard_check(ord("S"))) { 11 | pitch = min(++pitch, 80); 12 | } 13 | if (keyboard_check(ord("Q"))) { 14 | dist = max(--dist, 20); 15 | } 16 | if (keyboard_check(ord("E"))) { 17 | dist = min(++dist, 400); 18 | } 19 | 20 | if (keyboard_check(vk_numpad0)) { 21 | shape_1 = new ColTestPoint(point); 22 | } 23 | if (keyboard_check(vk_numpad1)) { 24 | shape_1 = new ColTestSphere(sphere); 25 | } 26 | if (keyboard_check(vk_numpad2)) { 27 | shape_1 = new ColTestAABB(aabb); 28 | } 29 | if (keyboard_check(vk_numpad3)) { 30 | shape_1 = new ColTestTriangle(); 31 | } 32 | if (keyboard_check(vk_numpad4)) { 33 | shape_1 = new ColTestPlane(plane); 34 | } 35 | if (keyboard_check(vk_numpad5)) { 36 | shape_1 = new ColTestLine(undefined); 37 | } 38 | if (keyboard_check(vk_numpad6)) { 39 | shape_1 = new ColTestMesh(tree); 40 | } 41 | if (keyboard_check(vk_numpad7)) { 42 | shape_1 = new ColTestOBB(obb); 43 | } 44 | if (keyboard_check(vk_numpad8)) { 45 | shape_1 = new ColTestCapsule(capsule_end, capsule_middle); 46 | } 47 | if (keyboard_check(vk_numpad9)) { 48 | shape_1 = new ColTestModel(tree, tree_vertices); 49 | } 50 | if (keyboard_check(vk_tab)) { 51 | shape_1 = new ColTestHeightmap(terrain, terrain_heightmap); 52 | } 53 | 54 | if (keyboard_check(ord("1"))) { 55 | shape_2 = new ColTestPoint(point); 56 | } 57 | if (keyboard_check(ord("2"))) { 58 | shape_2 = new ColTestSphere(sphere); 59 | } 60 | if (keyboard_check(ord("3"))) { 61 | shape_2 = new ColTestAABB(aabb); 62 | } 63 | if (keyboard_check(ord("4"))) { 64 | shape_2 = new ColTestTriangle(); 65 | } 66 | if (keyboard_check(ord("5"))) { 67 | shape_2 = new ColTestPlane(plane); 68 | } 69 | if (keyboard_check(ord("6"))) { 70 | shape_2 = new ColTestLine(undefined); 71 | } 72 | if (keyboard_check(ord("7"))) { 73 | shape_2 = new ColTestMesh(tree); 74 | } 75 | if (keyboard_check(ord("8"))) { 76 | shape_2 = new ColTestOBB(obb); 77 | } 78 | if (keyboard_check(ord("9"))) { 79 | shape_2 = new ColTestCapsule(capsule_end, capsule_middle); 80 | } 81 | if (keyboard_check(ord("0"))) { 82 | shape_2 = new ColTestModel(tree, tree_vertices); 83 | } 84 | 85 | shape_1.update(); -------------------------------------------------------------------------------- /scripts/Col_Camera_Frustum/Col_Camera_Frustum.gml: -------------------------------------------------------------------------------- 1 | /// these two matrices are going to be Matrix4 instances 2 | function ColCameraFrustum(view_mat, proj_mat) constructor { 3 | static vp = matrix_build_identity(); 4 | matrix_multiply(view_mat, proj_mat, vp); 5 | 6 | var c1 = new Vector3(vp[ 0], vp[ 4], vp[ 8]); 7 | var c2 = new Vector3(vp[ 1], vp[ 5], vp[ 9]); 8 | var c3 = new Vector3(vp[ 2], vp[ 6], vp[10]); 9 | var c4 = new Vector3(vp[ 3], vp[ 7], vp[11]); 10 | 11 | var ww = vp[15]; 12 | 13 | self.left = new ColPlane(c4.Add(c1), ww + vp[12]).Normalize(); 14 | self.right = new ColPlane(c4.Sub(c1), ww - vp[12]).Normalize(); 15 | self.bottom = new ColPlane(c4.Add(c2), ww + vp[13]).Normalize(); 16 | self.top = new ColPlane(c4.Sub(c2), ww - vp[13]).Normalize(); 17 | self.near = new ColPlane(c4.Add(c3), ww + vp[14]).Normalize(); 18 | self.far = new ColPlane(c4.Sub(c3), ww - vp[14]).Normalize(); 19 | 20 | self.as_array = [self.left, self.right, self.bottom, self.top, self.near, self.far]; 21 | 22 | static AsArray = function() { 23 | return self.as_array; 24 | }; 25 | 26 | static GetCorners = function() { 27 | return [ 28 | col_three_plane_intersection(self.near, self.top, self.left), 29 | col_three_plane_intersection(self.near, self.top, self.right), 30 | col_three_plane_intersection(self.near, self.bottom, self.left), 31 | col_three_plane_intersection(self.near, self.bottom, self.right), 32 | col_three_plane_intersection(self.far, self.top, self.left), 33 | col_three_plane_intersection(self.far, self.top, self.right), 34 | col_three_plane_intersection(self.far, self.bottom, self.left), 35 | col_three_plane_intersection(self.far, self.bottom, self.right) 36 | ]; 37 | }; 38 | } 39 | 40 | function col_three_plane_intersection(p1, p2, p3) { 41 | var n = p1.normal; 42 | var p2xp3 = p2.normal.Cross(p3.normal); 43 | var p3xp1 = p3.normal.Cross(n); 44 | var p1xp2 = n.Cross(p2.normal); 45 | 46 | var cross_product_sum = p2xp3.Mul(-p1.distance) 47 | .Add(p3xp1.Mul(-p2.distance)) 48 | .Add(p1xp2.Mul(-p3.distance)); 49 | 50 | return cross_product_sum.Div(dot_product_3d(n.x, n.y, n.z, p2xp3.x, p2xp3.y, p2xp3.z)); 51 | } 52 | 53 | enum EFrustumResults { 54 | OUTSIDE, 55 | INTERSECTING, 56 | INSIDE 57 | } -------------------------------------------------------------------------------- /scripts/Col_Shape_Ray/Col_Shape_Ray.gml: -------------------------------------------------------------------------------- 1 | function ColRay(origin, direction) constructor { 2 | self.origin = origin; // Vec3 3 | var mag = point_distance_3d(0, 0, 0, direction.x, direction.y, direction.z); 4 | self.direction = new Vector3( 5 | direction.x / mag, 6 | direction.y / mag, 7 | direction.z / mag 8 | ); // vec3 9 | 10 | static CheckPoint = function(point, hit_info) { 11 | return point.CheckRay(self, hit_info); 12 | }; 13 | 14 | static CheckSphere = function(sphere, hit_info) { 15 | return sphere.CheckRay(self, hit_info); 16 | }; 17 | 18 | static CheckAABB = function(aabb, hit_info) { 19 | return aabb.CheckRay(self, hit_info); 20 | }; 21 | 22 | static CheckPlane = function(plane, hit_info) { 23 | return plane.CheckRay(self, hit_info); 24 | }; 25 | 26 | static CheckOBB = function(obb, hit_info) { 27 | return obb.CheckRay(self, hit_info); 28 | }; 29 | 30 | static CheckCapsule = function(capsule, hit_info) { 31 | return capsule.CheckRay(self, hit_info); 32 | }; 33 | 34 | static CheckTriangle = function(triangle, hit_info) { 35 | return triangle.CheckRay(self, hit_info); 36 | }; 37 | 38 | static CheckMesh = function(mesh, hit_info) { 39 | return mesh.CheckRay(self, hit_info); 40 | }; 41 | 42 | static CheckModel = function(model, hit_info) { 43 | return model.CheckRay(self, hit_info); 44 | }; 45 | 46 | static CheckRay = function(ray, hit_info = undefined) { 47 | return false; 48 | }; 49 | 50 | static CheckLine = function(line, hit_info) { 51 | return false; 52 | }; 53 | 54 | static DisplaceSphere = function(sphere) { 55 | return undefined; 56 | }; 57 | 58 | static NearestPoint = function(vec3) { 59 | var origin = self.origin; 60 | var vx = vec3.x - origin.x; 61 | var vy = vec3.y - origin.y; 62 | var vz = vec3.z - origin.z; 63 | var d = self.direction; 64 | var t = max(dot_product_3d(vx, vy, vz, d.x, d.y, d.z), 0); 65 | return new Vector3( 66 | origin.x + d.x * t, 67 | origin.y + d.y * t, 68 | origin.z + d.z * t 69 | ); 70 | }; 71 | 72 | static GetMin = function() { 73 | return undefined; 74 | }; 75 | 76 | static GetMax = function() { 77 | return undefined; 78 | }; 79 | } -------------------------------------------------------------------------------- /3DCollisions.resource_order: -------------------------------------------------------------------------------- 1 | { 2 | "FolderOrderSettings":[ 3 | {"name":"Collision Stuff","order":25,"path":"folders/Collision Stuff.yy",}, 4 | {"name":"Shapes","order":1,"path":"folders/Collision Stuff/Shapes.yy",}, 5 | ], 6 | "ResourceOrderSettings":[ 7 | {"name":"Col_Changelog","order":3,"path":"notes/Col_Changelog/Col_Changelog.yy",}, 8 | {"name":"obj_demo","order":1,"path":"objects/obj_demo/obj_demo.yy",}, 9 | {"name":"Room1","order":14,"path":"rooms/Room1/Room1.yy",}, 10 | {"name":"Col_Camera_Frustum","order":2,"path":"scripts/Col_Camera_Frustum/Col_Camera_Frustum.yy",}, 11 | {"name":"Col_Config","order":4,"path":"scripts/Col_Config/Col_Config.yy",}, 12 | {"name":"Col_Heightmap","order":5,"path":"scripts/Col_Heightmap/Col_Heightmap.yy",}, 13 | {"name":"Col_Helper_Functions","order":6,"path":"scripts/Col_Helper_Functions/Col_Helper_Functions.yy",}, 14 | {"name":"Col_Matrix","order":7,"path":"scripts/Col_Matrix/Col_Matrix.yy",}, 15 | {"name":"Col_SAT_Stuff","order":8,"path":"scripts/Col_SAT_Stuff/Col_SAT_Stuff.yy",}, 16 | {"name":"Col_Shape_Capsule","order":1,"path":"scripts/Col_Shape_Capsule/Col_Shape_Capsule.yy",}, 17 | {"name":"Col_Shape_Line","order":2,"path":"scripts/Col_Shape_Line/Col_Shape_Line.yy",}, 18 | {"name":"Col_Shape_Mesh","order":3,"path":"scripts/Col_Shape_Mesh/Col_Shape_Mesh.yy",}, 19 | {"name":"Col_Shape_OBB","order":4,"path":"scripts/Col_Shape_OBB/Col_Shape_OBB.yy",}, 20 | {"name":"Col_Shape_Plane","order":5,"path":"scripts/Col_Shape_Plane/Col_Shape_Plane.yy",}, 21 | {"name":"Col_Shape_Point","order":6,"path":"scripts/Col_Shape_Point/Col_Shape_Point.yy",}, 22 | {"name":"Col_Shape_Ray","order":7,"path":"scripts/Col_Shape_Ray/Col_Shape_Ray.yy",}, 23 | {"name":"Col_Shape_Sphere","order":8,"path":"scripts/Col_Shape_Sphere/Col_Shape_Sphere.yy",}, 24 | {"name":"Col_Shape_Triangle","order":9,"path":"scripts/Col_Shape_Triangle/Col_Shape_Triangle.yy",}, 25 | {"name":"Col_Spatial_Hash","order":9,"path":"scripts/Col_Spatial_Hash/Col_Spatial_Hash.yy",}, 26 | {"name":"Col_Tests","order":3,"path":"scripts/Col_Tests/Col_Tests.yy",}, 27 | {"name":"Col_Transformed_Model","order":10,"path":"scripts/Col_Transformed_Model/Col_Transformed_Model.yy",}, 28 | {"name":"Col_Vector","order":10,"path":"scripts/Col_Vector/Col_Vector.yy",}, 29 | {"name":"Col_World","order":11,"path":"scripts/Col_World/Col_World.yy",}, 30 | {"name":"screen_to_world","order":24,"path":"scripts/screen_to_world/screen_to_world.yy",}, 31 | {"name":"shd_demo","order":2,"path":"shaders/shd_demo/shd_demo.yy",}, 32 | ], 33 | } -------------------------------------------------------------------------------- /objects/obj_demo/Draw_0.gml: -------------------------------------------------------------------------------- 1 | draw_clear(c_black); 2 | shader_set(shd_demo); 3 | 4 | gpu_set_zwriteenable(true); 5 | gpu_set_ztestenable(true); 6 | gpu_set_cullmode(cull_counterclockwise); 7 | 8 | var camera = camera_get_active(); 9 | var xto = 0; 10 | var yto = 0; 11 | var zto = 0; 12 | var xfrom = xto + dist * dcos(dir) * dcos(pitch); 13 | var yfrom = yto - dist * dsin(dir) * dcos(pitch); 14 | var zfrom = zto - dist * dsin(pitch); 15 | 16 | var view_mat = matrix_build_lookat(xfrom, yfrom, zfrom, xto, yto, zto, 0, 0, 1); 17 | var proj_mat = matrix_build_projection_perspective_fov(-60, -window_get_width() / window_get_height(), 1, 32000); 18 | camera_set_view_mat(camera, view_mat); 19 | camera_set_proj_mat(camera, proj_mat); 20 | camera_apply(camera); 21 | 22 | vertex_submit(grid, pr_linelist, -1); 23 | 24 | if (!keyboard_check(vk_shift)) { 25 | shape_1.draw(); 26 | } 27 | shape_2.draw(); 28 | 29 | if (is_instanceof(shape_1, ColTestSphere)) { 30 | var displacement = shape_2.data.DisplaceSphere(shape_1.data); 31 | if (displacement != undefined) { 32 | var r = shape_1.data.radius; 33 | matrix_set(matrix_world, matrix_build(displacement.x, displacement.y, displacement.z, 0, 0, 0, r, r, r)); 34 | vertex_submit(self.point, pr_trianglelist, -1); 35 | matrix_set(matrix_world, matrix_build_identity()); 36 | } 37 | } 38 | 39 | var mouse_vector = screen_to_world(window_mouse_get_x(), window_mouse_get_y(), view_mat, proj_mat); 40 | var ray = new ColRay(new Vector3(xfrom, yfrom, zfrom), new Vector3(mouse_vector.x, mouse_vector.y, mouse_vector.z)); 41 | var hit_info = new RaycastHitInformation(); 42 | var ray_hit = shape_1.data && shape_1.data.CheckRay(ray, hit_info); 43 | if (shape_1.data && shape_1.data.CheckRay(ray, hit_info)) { 44 | matrix_set(matrix_world, matrix_build(hit_info.point.x, hit_info.point.y, hit_info.point.z, 0, 0, 0, 1, 1, 1)); 45 | vertex_submit(point, pr_trianglelist, -1); 46 | matrix_set(matrix_world, matrix_build(hit_info.point.x + hit_info.normal.x, hit_info.point.y + hit_info.normal.y, hit_info.point.z + hit_info.normal.z, 0, 0, 0, 1, 1, 1)); 47 | vertex_submit(point, pr_trianglelist, -1); 48 | matrix_set(matrix_world, matrix_build_identity()); 49 | } 50 | 51 | hit_info.Clear(); 52 | if (shape_2.data && shape_2.data.CheckRay(ray, hit_info)) { 53 | /*repeat (99) { 54 | shape_2.data.CheckRay(ray, hit_info) 55 | }*/ 56 | matrix_set(matrix_world, matrix_build(hit_info.point.x, hit_info.point.y, hit_info.point.z, 0, 0, 0, 1, 1, 1)); 57 | vertex_submit(point, pr_trianglelist, -1); 58 | matrix_set(matrix_world, matrix_build(hit_info.point.x + hit_info.normal.x, hit_info.point.y + hit_info.normal.y, hit_info.point.z + hit_info.normal.z, 0, 0, 0, 1, 1, 1)); 59 | vertex_submit(point, pr_trianglelist, -1); 60 | matrix_set(matrix_world, matrix_build_identity()); 61 | } 62 | 63 | shader_reset(); 64 | gpu_set_zwriteenable(false); 65 | gpu_set_ztestenable(false); 66 | gpu_set_cullmode(cull_noculling); -------------------------------------------------------------------------------- /options/ios/options_ios.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMiOSOptions":"v1", 3 | "%Name":"iOS", 4 | "name":"iOS", 5 | "option_ios_build_number":0, 6 | "option_ios_bundle_name":"com.company.game", 7 | "option_ios_defer_home_indicator":false, 8 | "option_ios_devices":2, 9 | "option_ios_display_name":"Created with GameMaker Studio 2", 10 | "option_ios_enable_broadcast":false, 11 | "option_ios_half_ipad1_textures":false, 12 | "option_ios_icon_ipad_app_152":"${base_options_dir}/ios/icons/app/ipad_152.png", 13 | "option_ios_icon_ipad_app_76":"${base_options_dir}/ios/icons/app/ipad_76.png", 14 | "option_ios_icon_ipad_notification_20":"${base_options_dir}/ios/icons/notification/ipad_20.png", 15 | "option_ios_icon_ipad_notification_40":"${base_options_dir}/ios/icons/notification/ipad_40.png", 16 | "option_ios_icon_ipad_pro_app_167":"${base_options_dir}/ios/icons/app/ipad_pro_167.png", 17 | "option_ios_icon_ipad_settings_29":"${base_options_dir}/ios/icons/settings/ipad_29.png", 18 | "option_ios_icon_ipad_settings_58":"${base_options_dir}/ios/icons/settings/ipad_58.png", 19 | "option_ios_icon_ipad_spotlight_40":"${base_options_dir}/ios/icons/spotlight/ipad_40.png", 20 | "option_ios_icon_ipad_spotlight_80":"${base_options_dir}/ios/icons/spotlight/ipad_80.png", 21 | "option_ios_icon_iphone_app_120":"${base_options_dir}/ios/icons/app/iphone_120.png", 22 | "option_ios_icon_iphone_app_180":"${base_options_dir}/ios/icons/app/iphone_180.png", 23 | "option_ios_icon_iphone_notification_40":"${base_options_dir}/ios/icons/notification/iphone_40.png", 24 | "option_ios_icon_iphone_notification_60":"${base_options_dir}/ios/icons/notification/iphone_60.png", 25 | "option_ios_icon_iphone_settings_58":"${base_options_dir}/ios/icons/settings/iphone_58.png", 26 | "option_ios_icon_iphone_settings_87":"${base_options_dir}/ios/icons/settings/iphone_87.png", 27 | "option_ios_icon_iphone_spotlight_120":"${base_options_dir}/ios/icons/spotlight/iphone_120.png", 28 | "option_ios_icon_iphone_spotlight_80":"${base_options_dir}/ios/icons/spotlight/iphone_80.png", 29 | "option_ios_icon_itunes_artwork_1024":"${base_options_dir}/ios/icons/itunes/itunes_1024.png", 30 | "option_ios_interpolate_pixels":false, 31 | "option_ios_launchscreen_fill":0, 32 | "option_ios_launchscreen_image":"${base_options_dir}/ios/splash/launchscreen.png", 33 | "option_ios_launchscreen_image_landscape":"${base_options_dir}/ios/splash/launchscreen-landscape.png", 34 | "option_ios_min_version":"10.0", 35 | "option_ios_orientation_landscape":true, 36 | "option_ios_orientation_landscape_flipped":true, 37 | "option_ios_orientation_portrait":true, 38 | "option_ios_orientation_portrait_flipped":true, 39 | "option_ios_output_dir":"~/gamemakerstudio2", 40 | "option_ios_podfile_lock_path":"${options_dir}/ios/Podfile.lock", 41 | "option_ios_podfile_path":"${options_dir}/ios/Podfile", 42 | "option_ios_scale":0, 43 | "option_ios_splashscreen_background_colour":255, 44 | "option_ios_team_id":"", 45 | "option_ios_texture_page":"2048x2048", 46 | "option_ios_version":"1.0.0.0", 47 | "resourceType":"GMiOSOptions", 48 | "resourceVersion":"2.0", 49 | } -------------------------------------------------------------------------------- /objects/obj_demo/Draw_64.gml: -------------------------------------------------------------------------------- 1 | draw_set_font(fnt_demo); 2 | draw_text_colour(32, 20, "FPS: " + string(fps) + "/" + string(fps_real), 0x00ccff, 0x00ccff, 0x00ccff, 0x00ccff, 1); 3 | draw_text_colour(32, 40, "Q: zoom in", c_white, c_white, c_white, c_white, 1); 4 | draw_text_colour(32, 60, "E: zoom out", c_white, c_white, c_white, c_white, 1); 5 | draw_text_colour(192, 40, "W: rotate camera up", c_white, c_white, c_white, c_white, 1); 6 | draw_text_colour(192, 60, "S: rotate camera down", c_white, c_white, c_white, c_white, 1); 7 | draw_text_colour(480, 40, "A: rotate camera left", c_white, c_white, c_white, c_white, 1); 8 | draw_text_colour(480, 60, "D: rotate camera right", c_white, c_white, c_white, c_white, 1); 9 | 10 | var n = 1; 11 | draw_text_colour(720, n++ * 20, "Numpad 0: Shape 1 Point", c_white, c_white, c_white, c_white, 1); 12 | draw_text_colour(720, n++ * 20, "Numpad 1: Shape 1 Sphere", c_white, c_white, c_white, c_white, 1); 13 | draw_text_colour(720, n++ * 20, "Numpad 2: Shape 1 AABB", c_white, c_white, c_white, c_white, 1); 14 | draw_text_colour(720, n++ * 20, "Numpad 3: Shape 1 Triangle", c_white, c_white, c_white, c_white, 1); 15 | draw_text_colour(720, n++ * 20, "Numpad 4: Shape 1 Plane", c_white, c_white, c_white, c_white, 1); 16 | draw_text_colour(720, n++ * 20, "Numpad 5: Shape 1 Line", c_white, c_white, c_white, c_white, 1); 17 | draw_text_colour(720, n++ * 20, "Numpad 6: Shape 1 Mesh", c_white, c_white, c_white, c_white, 1); 18 | draw_text_colour(720, n++ * 20, "Numpad 7: Shape 1 OBB", c_white, c_white, c_white, c_white, 1); 19 | draw_text_colour(720, n++ * 20, "Numpad 8: Shape 1 Capsule", c_white, c_white, c_white, c_white, 1); 20 | draw_text_colour(720, n++ * 20, "Numpad 9: Shape 1 Model", c_white, c_white, c_white, c_white, 1); 21 | 22 | draw_text_colour(720, n++ * 20, "Tab: Terrain heightmap", c_white, c_white, c_white, c_white, 1); 23 | 24 | n = 1; 25 | draw_text_colour(1080, n++ * 20, "1: Shape 2 Point", c_white, c_white, c_white, c_white, 1); 26 | draw_text_colour(1080, n++ * 20, "2: Shape 2 Sphere", c_white, c_white, c_white, c_white, 1); 27 | draw_text_colour(1080, n++ * 20, "3: Shape 2 AABB", c_white, c_white, c_white, c_white, 1); 28 | draw_text_colour(1080, n++ * 20, "4: Shape 2 Triangle", c_white, c_white, c_white, c_white, 1); 29 | draw_text_colour(1080, n++ * 20, "5: Shape 2 Plane", c_white, c_white, c_white, c_white, 1); 30 | draw_text_colour(1080, n++ * 20, "6: Shape 2 Line", c_white, c_white, c_white, c_white, 1); 31 | draw_text_colour(1080, n++ * 20, "7: Shape 2 Mesh", c_white, c_white, c_white, c_white, 1); 32 | draw_text_colour(1080, n++ * 20, "8: Shape 2 OBB", c_white, c_white, c_white, c_white, 1); 33 | draw_text_colour(1080, n++ * 20, "9: Shape 2 Capsule", c_white, c_white, c_white, c_white, 1); 34 | draw_text_colour(1080, n++ * 20, "0: Shape 2 Model", c_white, c_white, c_white, c_white, 1); 35 | 36 | var t0 = get_timer(); 37 | var overlap = shape_2.test(shape_1); 38 | var t1 = get_timer(); 39 | draw_text_colour(32, 100, $"Test time: {t1 - t0} microseconds", c_white, c_white, c_white, c_white, 1); 40 | if (overlap) { 41 | draw_text_colour(32, 120, "Shapes overlap!", c_red, c_red, c_red, c_red, 1); 42 | } -------------------------------------------------------------------------------- /options/windowsuap/options_windowsuap.yy: -------------------------------------------------------------------------------- 1 | { 2 | "option_windowsuap_display_name": "Created with GameMaker Studio 2", 3 | "option_windowsuap_package_name": "YourPackageName", 4 | "option_windowsuap_publisher_display_name": "YourPublisherName", 5 | "option_windowsuap_package_display_name": "YourPackageDisplayName", 6 | "option_windowsuap_description": "Your Description", 7 | "option_windowsuap_version": "1.0.0.0", 8 | "option_windowsuap_orient_portrait": true, 9 | "option_windowsuap_orient_portrait_flipped": true, 10 | "option_windowsuap_orient_landscape": true, 11 | "option_windowsuap_orient_landscape_flipped": true, 12 | "option_windowsuap_small_logo": "${base_options_dir}/windowsuap/logos/SmallLogo.scale-100.png", 13 | "option_windowsuap_smallish_logo": "${base_options_dir}/windowsuap/logos/SmallishLogo.scale-100.png", 14 | "option_windowsuap_store_logo": "${base_options_dir}/windowsuap/logos/StoreLogo.scale-100.png", 15 | "option_windowsuap_logo": "${base_options_dir}/windowsuap/logos/Logo.scale-100.png", 16 | "option_windowsuap_logo_background_colour": 4278190080, 17 | "option_windowsuap_logo_foreground_text": 0, 18 | "option_windowsuap_wide_logo": "${base_options_dir}/windowsuap/logos/WideLogo.scale-100.png", 19 | "option_windowsuap_large_logo": "${base_options_dir}/windowsuap/logos/LargeLogo.scale-100.png", 20 | "option_windowsuap_splash_png": "${base_options_dir}/windowsuap/splash/SplashScreen.scale-100.png", 21 | "option_windowsuap_splash_background_colour": 4278190080, 22 | "option_windowsuap_interpolate_pixels": false, 23 | "option_windowsuap_display_cursor": true, 24 | "option_windowsuap_start_fullscreen": false, 25 | "option_windowsuap_allow_fullscreen_switching": false, 26 | "option_windowsuap_use_synchronization": true, 27 | "option_windowsuap_scale": 0, 28 | "option_windowsuap_texture_page": "2048x2048", 29 | "option_windowsuap_certificate_location": "${base_options_dir}\\windowsuap\\keys\\WinUWPRunner_TemporaryKey.pfx", 30 | "option_windowsuap_certificate_publishername": "CN=Sandbox", 31 | "option_windowsuap_native_cpu": 0, 32 | "option_windowsuap_internet_capable": false, 33 | "option_windowsuap_microphone_capable": false, 34 | "option_windowsuap_iap_sandbox": false, 35 | "option_windowsuap_targetdevicefamily_universal": true, 36 | "option_windowsuap_target_platform_version": "10.0.14393.0", 37 | "option_windowsuap_target_platform_min_version": "10.0.14393.0", 38 | "option_windowsuap_targetdevicefamily_desktop": false, 39 | "option_windowsuap_desktop_family_platform_version": "10.0.14393.0", 40 | "option_windowsuap_desktop_family_platform_min_version": "10.0.14393.0", 41 | "option_windowsuap_targetdevicefamily_xbox": false, 42 | "option_windowsuap_xbox_family_platform_version": "10.0.14393.0", 43 | "option_windowsuap_xbox_family_platform_min_version": "10.0.14393.0", 44 | "option_windowsuap_targetdevicefamily_mobile": false, 45 | "option_windowsuap_mobile_family_platform_version": "10.0.14393.0", 46 | "option_windowsuap_mobile_family_platform_min_version": "10.0.14393.0", 47 | "option_windowsuap_targetdevicefamily_holographic": false, 48 | "option_windowsuap_holographic_family_platform_version": "10.0.14393.0", 49 | "option_windowsuap_holographic_family_platform_min_version": "10.0.14393.0", 50 | "option_windowsuap_targetdevicefamily_team": false, 51 | "option_windowsuap_team_family_platform_version": "10.0.14393.0", 52 | "option_windowsuap_team_family_platform_min_version": "10.0.14393.0", 53 | "option_windowsuap_xbox_live": false, 54 | "option_windowsuap_xbox_live_creators_program": false, 55 | "option_windowsuap_xbox_live_title_id": "0", 56 | "option_windowsuap_xbox_live_scid": "00000000-0000-0000-0000-000000000000", 57 | "resourceVersion": "1.0", 58 | "name": "Windows UWP", 59 | "tags": [], 60 | "resourceType": "GMWindowsUAPOptions", 61 | } -------------------------------------------------------------------------------- /rooms/Room1/Room1.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMRoom":"v1", 3 | "%Name":"Room1", 4 | "creationCodeFile":"", 5 | "inheritCode":false, 6 | "inheritCreationOrder":false, 7 | "inheritLayers":false, 8 | "instanceCreationOrder":[ 9 | {"name":"inst_71B877AB","path":"rooms/Room1/Room1.yy",}, 10 | ], 11 | "isDnd":false, 12 | "layers":[ 13 | {"$GMRInstanceLayer":"","%Name":"Instances","depth":0,"effectEnabled":true,"effectType":null,"gridX":32,"gridY":32,"hierarchyFrozen":false,"inheritLayerDepth":false,"inheritLayerSettings":false,"inheritSubLayers":true,"inheritVisibility":true,"instances":[ 14 | {"$GMRInstance":"v4","%Name":"inst_71B877AB","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_71B877AB","objectId":{"name":"obj_demo","path":"objects/obj_demo/obj_demo.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":1.0,"scaleY":1.0,"x":64.0,"y":32.0,}, 15 | ],"layers":[],"name":"Instances","properties":[],"resourceType":"GMRInstanceLayer","resourceVersion":"2.0","userdefinedDepth":false,"visible":true,}, 16 | {"$GMRBackgroundLayer":"","%Name":"Background","animationFPS":15.0,"animationSpeedType":0,"colour":4278190080,"depth":100,"effectEnabled":true,"effectType":null,"gridX":32,"gridY":32,"hierarchyFrozen":false,"hspeed":0.0,"htiled":false,"inheritLayerDepth":false,"inheritLayerSettings":false,"inheritSubLayers":true,"inheritVisibility":true,"layers":[],"name":"Background","properties":[],"resourceType":"GMRBackgroundLayer","resourceVersion":"2.0","spriteId":null,"stretch":false,"userdefinedAnimFPS":false,"userdefinedDepth":false,"visible":true,"vspeed":0.0,"vtiled":false,"x":0,"y":0,}, 17 | ], 18 | "name":"Room1", 19 | "parent":{ 20 | "name":"3DCollisions", 21 | "path":"3DCollisions.yyp", 22 | }, 23 | "parentRoom":null, 24 | "physicsSettings":{ 25 | "inheritPhysicsSettings":false, 26 | "PhysicsWorld":false, 27 | "PhysicsWorldGravityX":0.0, 28 | "PhysicsWorldGravityY":10.0, 29 | "PhysicsWorldPixToMetres":0.1, 30 | }, 31 | "resourceType":"GMRoom", 32 | "resourceVersion":"2.0", 33 | "roomSettings":{ 34 | "Height":768, 35 | "inheritRoomSettings":false, 36 | "persistent":false, 37 | "Width":1366, 38 | }, 39 | "sequenceId":null, 40 | "views":[ 41 | {"hborder":32,"hport":768,"hspeed":-1,"hview":768,"inherit":false,"objectId":null,"vborder":32,"visible":false,"vspeed":-1,"wport":1366,"wview":1366,"xport":0,"xview":0,"yport":0,"yview":0,}, 42 | {"hborder":32,"hport":768,"hspeed":-1,"hview":768,"inherit":false,"objectId":null,"vborder":32,"visible":false,"vspeed":-1,"wport":1366,"wview":1366,"xport":0,"xview":0,"yport":0,"yview":0,}, 43 | {"hborder":32,"hport":768,"hspeed":-1,"hview":768,"inherit":false,"objectId":null,"vborder":32,"visible":false,"vspeed":-1,"wport":1366,"wview":1366,"xport":0,"xview":0,"yport":0,"yview":0,}, 44 | {"hborder":32,"hport":768,"hspeed":-1,"hview":768,"inherit":false,"objectId":null,"vborder":32,"visible":false,"vspeed":-1,"wport":1366,"wview":1366,"xport":0,"xview":0,"yport":0,"yview":0,}, 45 | {"hborder":32,"hport":768,"hspeed":-1,"hview":768,"inherit":false,"objectId":null,"vborder":32,"visible":false,"vspeed":-1,"wport":1366,"wview":1366,"xport":0,"xview":0,"yport":0,"yview":0,}, 46 | {"hborder":32,"hport":768,"hspeed":-1,"hview":768,"inherit":false,"objectId":null,"vborder":32,"visible":false,"vspeed":-1,"wport":1366,"wview":1366,"xport":0,"xview":0,"yport":0,"yview":0,}, 47 | {"hborder":32,"hport":768,"hspeed":-1,"hview":768,"inherit":false,"objectId":null,"vborder":32,"visible":false,"vspeed":-1,"wport":1366,"wview":1366,"xport":0,"xview":0,"yport":0,"yview":0,}, 48 | {"hborder":32,"hport":768,"hspeed":-1,"hview":768,"inherit":false,"objectId":null,"vborder":32,"visible":false,"vspeed":-1,"wport":1366,"wview":1366,"xport":0,"xview":0,"yport":0,"yview":0,}, 49 | ], 50 | "viewSettings":{ 51 | "clearDisplayBuffer":true, 52 | "clearViewBackground":false, 53 | "enableViews":false, 54 | "inheritViewSettings":false, 55 | }, 56 | "volume":1.0, 57 | } -------------------------------------------------------------------------------- /objects/obj_demo/Create_0.gml: -------------------------------------------------------------------------------- 1 | vertex_format_begin(); 2 | vertex_format_add_position_3d(); 3 | vertex_format_add_normal(); 4 | vertex_format_add_colour(); 5 | vertex_format = vertex_format_end(); 6 | 7 | show_debug_overlay(true); 8 | 9 | dir = 315; 10 | pitch = -20; 11 | dist = 200; 12 | 13 | var buffer = buffer_load("shapes/grid.vbuff"); 14 | grid = vertex_create_buffer_from_buffer(buffer, vertex_format); 15 | buffer_delete(buffer); 16 | 17 | buffer = buffer_load("shapes/aabb.vbuff"); 18 | aabb = vertex_create_buffer_from_buffer(buffer, vertex_format); 19 | buffer_delete(buffer); 20 | 21 | buffer = buffer_load("shapes/plane.vbuff"); 22 | plane = vertex_create_buffer_from_buffer(buffer, vertex_format); 23 | buffer_delete(buffer); 24 | 25 | buffer = buffer_load("shapes/point.vbuff"); 26 | point = vertex_create_buffer_from_buffer(buffer, vertex_format); 27 | buffer_delete(buffer); 28 | 29 | buffer = buffer_load("shapes/sphere.vbuff"); 30 | sphere = vertex_create_buffer_from_buffer(buffer, vertex_format); 31 | buffer_delete(buffer); 32 | 33 | buffer = buffer_load("shapes/obb.vbuff"); 34 | obb = vertex_create_buffer_from_buffer(buffer, vertex_format); 35 | buffer_delete(buffer); 36 | 37 | buffer = buffer_load("shapes/capsule_middle.vbuff"); 38 | capsule_middle = vertex_create_buffer_from_buffer(buffer, vertex_format); 39 | buffer_delete(buffer); 40 | 41 | buffer = buffer_load("shapes/capsule_end.vbuff"); 42 | capsule_end = vertex_create_buffer_from_buffer(buffer, vertex_format); 43 | buffer_delete(buffer); 44 | 45 | buffer = buffer_load("meshes/tree.vbuff"); 46 | var vertex_size = 28; 47 | tree_vertices = []; 48 | for (var i = 0, n = buffer_get_size(buffer); i < n; i += vertex_size * 3) { 49 | array_push(tree_vertices, new ColTriangle( 50 | new Vector3( 51 | buffer_peek(buffer, i + 0 * vertex_size + 0, buffer_f32), 52 | buffer_peek(buffer, i + 0 * vertex_size + 4, buffer_f32), 53 | buffer_peek(buffer, i + 0 * vertex_size + 8, buffer_f32) 54 | ), 55 | new Vector3( 56 | buffer_peek(buffer, i + 1 * vertex_size + 0, buffer_f32), 57 | buffer_peek(buffer, i + 1 * vertex_size + 4, buffer_f32), 58 | buffer_peek(buffer, i + 1 * vertex_size + 8, buffer_f32) 59 | ), 60 | new Vector3( 61 | buffer_peek(buffer, i + 2 * vertex_size + 0, buffer_f32), 62 | buffer_peek(buffer, i + 2 * vertex_size + 4, buffer_f32), 63 | buffer_peek(buffer, i + 2 * vertex_size + 8, buffer_f32) 64 | ) 65 | )); 66 | } 67 | tree = vertex_create_buffer_from_buffer(buffer, vertex_format); 68 | buffer_delete(buffer); 69 | 70 | buffer = buffer_load("meshes/terrain.vbuff"); 71 | terrain = vertex_create_buffer_from_buffer(buffer, vertex_format); 72 | buffer_delete(buffer); 73 | 74 | terrain_heightmap = buffer_load("terrain.hm"); 75 | 76 | shape_1 = new ColTestPoint(point); 77 | shape_2 = new ColTestPoint(point); 78 | 79 | var test_combo = function(shape1, shape2) { 80 | var t0 = get_timer(); 81 | repeat (10_000) { 82 | shape1.test(shape2); 83 | } 84 | var t1 = get_timer(); 85 | show_debug_message($"{instanceof(shape1)} vs {instanceof(shape2)}, time: {(t1 - t0) / 1000} ms"); 86 | }; 87 | 88 | var p1 = new Vector3(random_range(-20, 0), random_range(-20, 0), random_range(-20, 20)); 89 | var p2 = new Vector3(random_range(-20, 20), random_range(-20, 20), random_range(-20, 20)); 90 | var p3 = new Vector3(random_range(0, 20), random_range(0, 20), random_range(-20, 20)); 91 | 92 | random_set_seed(0); 93 | 94 | var sphere1 = new ColTestSphere(undefined); 95 | var sphere2 = new ColTestSphere(undefined); 96 | var aabb1 = new ColTestAABB(undefined); 97 | var aabb2 = new ColTestAABB(undefined); 98 | var obb1 = new ColTestOBB(undefined); 99 | var obb2 = new ColTestOBB(undefined); 100 | var triangle1 = new ColTestTriangle(); 101 | var triangle2 = new ColTestTriangle(); 102 | var trimesh = new ColTestMesh(self.tree); 103 | var capsule1 = new ColTestCapsule(undefined, undefined); 104 | var capsule2 = new ColTestCapsule(undefined, undefined); 105 | 106 | test_combo(sphere1, sphere2); 107 | test_combo(aabb1, aabb2); 108 | test_combo(sphere1, aabb2); 109 | test_combo(sphere1, obb2); 110 | test_combo(capsule1, sphere2); 111 | test_combo(triangle1, triangle2); 112 | 113 | test_combo(triangle1, sphere2); 114 | test_combo(capsule1, triangle2); 115 | test_combo(obb1, obb2); 116 | test_combo(aabb1, obb2); 117 | test_combo(triangle1, trimesh); -------------------------------------------------------------------------------- /scripts/Col_Shape_Point/Col_Shape_Point.gml: -------------------------------------------------------------------------------- 1 | function ColPoint(position) constructor { 2 | self.Set(position); 3 | 4 | static Set = function(position) { 5 | self.position = position; 6 | self.property_min = position; 7 | self.property_max = position; 8 | }; 9 | 10 | static CheckObject = function(object) { 11 | return object.shape.CheckPoint(self); 12 | }; 13 | 14 | static CheckPoint = function(point) { 15 | var p1 = self.position; 16 | var p2 = point.position; 17 | return p1.x == p2.x && p1.y == p2.y && p1.z == p2.z; 18 | }; 19 | 20 | static CheckSphere = function(sphere) { 21 | var pp = self.position; 22 | var ps = sphere.position; 23 | return point_distance_3d(pp.x, pp.y, pp.z, ps.x, ps.y, ps.z) < sphere.radius; 24 | }; 25 | 26 | static CheckAABB = function(aabb) { 27 | var box_min = aabb.property_min; 28 | var box_max = aabb.property_max; 29 | var p = self.position; 30 | if (p.x < box_min.x || p.y < box_min.y || p.z < box_min.z) return false; 31 | if (p.x > box_max.x || p.y > box_max.y || p.z > box_max.z) return false; 32 | return true; 33 | }; 34 | 35 | static CheckPlane = function(plane) { 36 | var p = self.position; 37 | var n = plane.normal; 38 | return (dot_product_3d(p.x, p.y, p.z, n.x, n.y, n.z) == plane.distance); 39 | }; 40 | 41 | static CheckOBB = function(obb) { 42 | return obb.CheckPoint(self); 43 | }; 44 | 45 | static CheckCapsule = function(capsule) { 46 | return capsule.CheckPoint(self); 47 | }; 48 | 49 | static CheckTriangle = function(triangle) { 50 | var pa = triangle.a.Sub(self.position); 51 | var pb = triangle.b.Sub(self.position); 52 | var pc = triangle.c.Sub(self.position); 53 | 54 | var normPBC = pb.Cross(pc).Normalize(); 55 | var normPCA = pc.Cross(pa).Normalize(); 56 | var normPAB = pa.Cross(pb).Normalize(); 57 | 58 | if (dot_product_3d(normPBC.x, normPBC.y, normPBC.z, normPCA.x, normPCA.y, normPCA.z) < 1) { 59 | return false; 60 | } 61 | 62 | if (dot_product_3d(normPBC.x, normPBC.y, normPBC.z, normPAB.x, normPAB.y, normPAB.z) < 1) { 63 | return false; 64 | } 65 | 66 | return true; 67 | }; 68 | 69 | static CheckMesh = function(mesh) { 70 | return mesh.CheckPoint(self); 71 | }; 72 | 73 | static CheckModel = function(model) { 74 | return model.CheckPoint(self); 75 | }; 76 | 77 | static CheckRay = function(ray, hit_info = undefined) { 78 | var p = self.position; 79 | var nearest = ray.NearestPoint(p); 80 | if (point_distance_3d(nearest.x, nearest.y, nearest.z, p.x, p.y, p.z) > 0) return false; 81 | 82 | if (hit_info) { 83 | var ro = ray.origin; 84 | hit_info.Update(point_distance_3d(p.x, p.y, p.z, ro.x, ro.x, ro.z), self, p, undefined); 85 | } 86 | 87 | return true; 88 | }; 89 | 90 | static CheckLine = function(line) { 91 | var p = self.position; 92 | var nearest = line.NearestPoint(p); 93 | return nearest.x == p.x && nearest.y == p.y && nearest.z == p.z; 94 | }; 95 | 96 | static DisplaceSphere = function(sphere) { 97 | var pp = self.position; 98 | var ps = sphere.position; 99 | var d = point_distance_3d(pp.x, pp.y, pp.z, ps.x, ps.y, ps.z); 100 | if (d == 0 || d > sphere.radius) return undefined; 101 | 102 | return pp.Add(ps.Sub(pp).Normalize().Mul(sphere.radius)); 103 | }; 104 | 105 | static GetMin = function() { 106 | return self.position.Clone(); 107 | }; 108 | 109 | static GetMax = function() { 110 | return self.position.Clone(); 111 | }; 112 | 113 | static CheckFrustum = function(frustum) { 114 | var planes = frustum.as_array; 115 | var p = self.position; 116 | var px = p.x, py = p.y, pz = p.z; 117 | var i = 0; 118 | repeat (6) { 119 | var plane = planes[i++]; 120 | var n = plane.normal; 121 | if (dot_product_3d(n.x, n.y, n.z, px, py, pz) + plane.distance < 0) 122 | return EFrustumResults.OUTSIDE; 123 | } 124 | return EFrustumResults.INSIDE; 125 | }; 126 | 127 | static CheckFrustumFast = function() { 128 | var p = self.position; 129 | return sphere_is_visible(p.x, p.y, p.z, 0.0001) ? EFrustumResults.INSIDE : EFrustumResults.OUTSIDE; 130 | }; 131 | } -------------------------------------------------------------------------------- /options/android/options_android.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMAndroidOptions":"v1", 3 | "%Name":"Android", 4 | "name":"Android", 5 | "option_android_application_tag_inject":"", 6 | "option_android_arch_arm64":true, 7 | "option_android_arch_armv7":false, 8 | "option_android_arch_x86_64":false, 9 | "option_android_attribute_allow_backup":false, 10 | "option_android_build_tools":"", 11 | "option_android_compile_sdk":"", 12 | "option_android_device_support":0, 13 | "option_android_display_layout":"LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT", 14 | "option_android_display_name":"Created with GameMaker Studio 2", 15 | "option_android_edge_to_edge_display":false, 16 | "option_android_facebook_app_display_name":"", 17 | "option_android_facebook_id":"", 18 | "option_android_gamepad_support":true, 19 | "option_android_google_apk_expansion":false, 20 | "option_android_google_cloud_saving":false, 21 | "option_android_google_dynamic_asset_delivery":false, 22 | "option_android_google_licensing_public_key":"", 23 | "option_android_google_services_app_id":"", 24 | "option_android_gradle_plugin_version":"8.7.0", 25 | "option_android_gradle_version":"8.9", 26 | "option_android_icon_adaptivebg_hdpi":"${base_options_dir}/android/icons_adaptivebg/hdpi.png", 27 | "option_android_icon_adaptivebg_ldpi":"${base_options_dir}/android/icons_adaptivebg/ldpi.png", 28 | "option_android_icon_adaptivebg_mdpi":"${base_options_dir}/android/icons_adaptivebg/mdpi.png", 29 | "option_android_icon_adaptivebg_xhdpi":"${base_options_dir}/android/icons_adaptivebg/xhdpi.png", 30 | "option_android_icon_adaptivebg_xxhdpi":"${base_options_dir}/android/icons_adaptivebg/xxhdpi.png", 31 | "option_android_icon_adaptivebg_xxxhdpi":"${base_options_dir}/android/icons_adaptivebg/xxxhdpi.png", 32 | "option_android_icon_adaptive_generate":false, 33 | "option_android_icon_adaptive_hdpi":"${base_options_dir}/android/icons_adaptive/hdpi.png", 34 | "option_android_icon_adaptive_ldpi":"${base_options_dir}/android/icons_adaptive/ldpi.png", 35 | "option_android_icon_adaptive_mdpi":"${base_options_dir}/android/icons_adaptive/mdpi.png", 36 | "option_android_icon_adaptive_xhdpi":"${base_options_dir}/android/icons_adaptive/xhdpi.png", 37 | "option_android_icon_adaptive_xxhdpi":"${base_options_dir}/android/icons_adaptive/xxhdpi.png", 38 | "option_android_icon_adaptive_xxxhdpi":"${base_options_dir}/android/icons_adaptive/xxxhdpi.png", 39 | "option_android_icon_hdpi":"${base_options_dir}/android/icons/hdpi.png", 40 | "option_android_icon_ldpi":"${base_options_dir}/android/icons/ldpi.png", 41 | "option_android_icon_mdpi":"${base_options_dir}/android/icons/mdpi.png", 42 | "option_android_icon_xhdpi":"${base_options_dir}/android/icons/xhdpi.png", 43 | "option_android_icon_xxhdpi":"${base_options_dir}/android/icons/xxhdpi.png", 44 | "option_android_icon_xxxhdpi":"${base_options_dir}/android/icons/xxxhdpi.png", 45 | "option_android_install_location":0, 46 | "option_android_interpolate_pixels":false, 47 | "option_android_launchscreen_fill":0, 48 | "option_android_lint":false, 49 | "option_android_logcat":"yoyo:V DEBUG:V AndroidRuntime:V", 50 | "option_android_minimum_sdk":"", 51 | "option_android_orient_landscape":true, 52 | "option_android_orient_landscape_flipped":true, 53 | "option_android_orient_portrait":true, 54 | "option_android_orient_portrait_flipped":true, 55 | "option_android_package_company":"company", 56 | "option_android_package_domain":"com", 57 | "option_android_package_product":"game", 58 | "option_android_permission_bluetooth":true, 59 | "option_android_permission_internet":true, 60 | "option_android_permission_network_state":false, 61 | "option_android_permission_read_phone_state":false, 62 | "option_android_permission_record_audio":false, 63 | "option_android_permission_write_external_storage":false, 64 | "option_android_proguard_minifying":false, 65 | "option_android_proguard_shrinking":false, 66 | "option_android_scale":0, 67 | "option_android_screen_depth":0, 68 | "option_android_sleep_margin":4, 69 | "option_android_splashscreen_background_colour":255, 70 | "option_android_splash_screens_landscape":"${base_options_dir}/android/splash/landscape.png", 71 | "option_android_splash_screens_portrait":"${base_options_dir}/android/splash/portrait.png", 72 | "option_android_splash_time":0, 73 | "option_android_support_lib":"", 74 | "option_android_sync_amazon":false, 75 | "option_android_target_sdk":"", 76 | "option_android_texture_page":"2048x2048", 77 | "option_android_tools_from_version":false, 78 | "option_android_tv_banner":"${base_options_dir}/android/tv_banner.png", 79 | "option_android_tv_isgame":true, 80 | "option_android_tv_supports_leanback":true, 81 | "option_android_use_facebook":false, 82 | "option_android_version":"1.0.0.0", 83 | "resourceType":"GMAndroidOptions", 84 | "resourceVersion":"2.0", 85 | } -------------------------------------------------------------------------------- /scripts/Col_Shape_Plane/Col_Shape_Plane.gml: -------------------------------------------------------------------------------- 1 | function ColPlane(normal, distance) constructor { 2 | self.normal = normal; // Vec3 3 | self.distance = distance; // number 4 | 5 | self.property_min = undefined; 6 | self.property_max = undefined; 7 | 8 | static CheckObject = function(object) { 9 | return object.shape.CheckPlane(self); 10 | }; 11 | 12 | static CheckPoint = function(point) { 13 | return point.CheckPlane(self); 14 | }; 15 | 16 | static CheckSphere = function(sphere) { 17 | return sphere.CheckPlane(self); 18 | }; 19 | 20 | static CheckAABB = function(aabb) { 21 | return aabb.CheckPlane(self); 22 | }; 23 | 24 | static CheckPlane = function(plane) { 25 | if (self.distance == plane.distance) return true; 26 | var n1 = self.normal; 27 | var n2 = plane.normal; 28 | return point_distance_3d(0, 0, 0, n1.y * n2.z - n2.y * n1.z, n1.z * n2.x - n2.z * n1.x, n1.x * n2.y - n2.x * n1.y) > 0; 29 | }; 30 | 31 | static CheckOBB = function(obb) { 32 | return obb.CheckPlane(self); 33 | }; 34 | 35 | static CheckCapsule = function(capsule) { 36 | return capsule.CheckPlane(self); 37 | }; 38 | 39 | static CheckTriangle = function(triangle) { 40 | var nx = self.normal.x, ny = self.normal.y, nz = self.normal.z; 41 | var d = self.distance; 42 | var side_a = dot_product_3d(nx, ny, nz, triangle.a.x, triangle.a.y, triangle.a.z) - d; 43 | var side_b = dot_product_3d(nx, ny, nz, triangle.b.x, triangle.b.y, triangle.b.z) - d; 44 | var side_c = dot_product_3d(nx, ny, nz, triangle.c.x, triangle.c.y, triangle.c.z) - d; 45 | 46 | if (side_a == 0 && side_b == 0 && side_c == 0) { 47 | return true; 48 | } 49 | 50 | if (sign(side_a) == sign(side_b) && sign(side_a) == sign(side_c)) { 51 | return false; 52 | } 53 | 54 | return true; 55 | }; 56 | 57 | static CheckMesh = function(mesh) { 58 | return mesh.CheckPlane(self); 59 | }; 60 | 61 | static CheckModel = function(model) { 62 | return model.CheckPlane(self); 63 | }; 64 | 65 | static CheckRay = function(ray, hit_info = undefined) { 66 | var rd = ray.direction; 67 | var n = self.normal; 68 | var DdotN = dot_product_3d(rd.x, rd.y, rd.z, n.x, n.y, n.z); 69 | if (DdotN >= 0) return false; 70 | 71 | var ro = ray.origin; 72 | var OdotN = dot_product_3d(ro.x, ro.y, ro.z, n.x, n.y, n.z); 73 | var t = (self.distance - OdotN) / DdotN; 74 | if (t < 0) return false; 75 | 76 | if (hit_info) { 77 | hit_info.Update(t, self, ro.Add(rd.Mul(t)), n); 78 | } 79 | 80 | return true; 81 | }; 82 | 83 | static CheckLine = function(line) { 84 | var n = self.normal; 85 | var start = line.start; 86 | var dir = line.property_ray.direction; 87 | var NdotS = dot_product_3d(n.x, n.y, n.z, start.x, start.y, start.z); 88 | var NdotD = dot_product_3d(n.x, n.y, n.z, dir.x, dir.y, dir.z); 89 | 90 | if (NdotD == 0) return false; 91 | var t = (self.distance - NdotS) / NdotD; 92 | return (t >= 0) && (t <= 1); 93 | }; 94 | 95 | static DisplaceSphere = function(sphere) { 96 | if (!self.CheckSphere(sphere)) return undefined; 97 | 98 | var nearest = self.NearestPoint(sphere.position); 99 | var offset = self.normal.Mul(sphere.radius); 100 | 101 | return nearest.Add(offset); 102 | }; 103 | 104 | static NearestPoint = function(vec3) { 105 | var nx = self.normal.x, ny = self.normal.y, nz = self.normal.z; 106 | var dist = dot_product_3d(nx, ny, nz, vec3.x, vec3.y, vec3.z) - self.distance; 107 | return new Vector3(vec3.x - nx * dist, vec3.y - ny * dist, vec3.z - nz * dist); 108 | }; 109 | 110 | static PlaneEquation = function(vec3) { 111 | // much like the dot product, this function will return: 112 | // - +1ish if the value is in front of the plane 113 | // - 0 if the value is on the plane 114 | // - -1ish is the value is behind the plane 115 | var n = self.normal; 116 | return dot_product_3d(n.x, n.y, n.z, vec3.x, vec3.y, vec3.z) - self.distance; 117 | }; 118 | 119 | static GetMin = function() { 120 | return undefined; 121 | }; 122 | 123 | static GetMax = function() { 124 | return undefined; 125 | }; 126 | 127 | static Normalize = function() { 128 | var n = self.normal; 129 | var mag = point_distance_3d(0, 0, 0, n.x, n.y, n.z); 130 | return new ColPlane(n.Div(mag), self.distance / mag); 131 | }; 132 | } -------------------------------------------------------------------------------- /scripts/Col_Transformed_Model/Col_Transformed_Model.gml: -------------------------------------------------------------------------------- 1 | // feather disable GM2023 2 | // feather disable GM1041 3 | function ColTransformedModel(mesh, position = new Vector3(0, 0, 0), rotation = matrix_build_identity()) constructor { 4 | self.mesh = undefined; 5 | self.position = undefined; 6 | self.rotation = undefined; 7 | self.property_inverse = matrix_build_identity(); 8 | self.property_transform = matrix_build_identity(); 9 | self.Set(mesh, position, rotation); 10 | 11 | static Set = function(mesh = self.mesh, position = self.position, rotation = self.rotation) { 12 | static position_mat = matrix_build_identity(); 13 | 14 | if (is_array(mesh)) mesh = new ColMesh(mesh); 15 | self.mesh = mesh; 16 | self.position = position; 17 | self.rotation = rotation; 18 | 19 | matrix_build(position.x, position.y, position.z, 0, 0, 0, 1, 1, 1, position_mat); 20 | matrix_multiply(rotation, position_mat, self.property_transform); 21 | matrix_inverse(self.property_transform, self.property_inverse); 22 | 23 | self.property_obb = new ColOBB(mat4_mul_point(self.property_transform, mesh.bounds.position), mesh.bounds.half_extents, self.property_transform); 24 | self.property_min = self.property_obb.property_min; 25 | self.property_max = self.property_obb.property_max; 26 | }; 27 | 28 | static GetTransformMatrix = function() { 29 | return variable_clone(self.property_transform); 30 | }; 31 | 32 | static CheckPoint = function(point) { 33 | if (!self.property_obb.CheckPoint(point)) return false; 34 | 35 | var untransformed = new ColPoint(mat4_mul_point(self.property_inverse, point.position)); 36 | return self.mesh.CheckPoint(untransformed); 37 | }; 38 | 39 | static CheckSphere = function(sphere) { 40 | if (!self.property_obb.CheckSphere(sphere)) return false; 41 | 42 | var untransformed = new ColSphere(mat4_mul_point(self.property_inverse, sphere.position), sphere.radius); 43 | return self.mesh.CheckSphere(untransformed); 44 | }; 45 | 46 | static CheckAABB = function(aabb) { 47 | if (!self.property_obb.CheckAABB(aabb)) return false; 48 | 49 | var untransformed = new ColOBB(mat4_mul_point(self.property_inverse, aabb.position), aabb.half_extents, self.property_inverse); 50 | return self.mesh.CheckOBB(untransformed); 51 | }; 52 | 53 | static CheckOBB = function(obb) { 54 | if (!self.property_obb.CheckOBB(obb)) return false; 55 | 56 | static untransformed_inverse = matrix_build_identity(); 57 | 58 | matrix_multiply(obb.orientation, self.property_inverse, untransformed_inverse); 59 | 60 | var untransformed = new ColOBB(mat4_mul_point(self.property_inverse, obb.position), obb.size, untransformed_inverse); 61 | return self.mesh.CheckOBB(untransformed); 62 | }; 63 | 64 | static CheckPlane = function(plane) { 65 | if (!self.property_obb.CheckPlane(plane)) return false; 66 | 67 | var point = plane.normal.Mul(plane.distance); 68 | point = mat4_mul_point(self.property_inverse, point); 69 | 70 | var normal = mat4_mul_vector(self.property_inverse, plane.normal); 71 | var distance = point.Dot(normal); 72 | 73 | var untransformed = new ColPlane(normal, distance); 74 | return self.mesh.CheckPlane(untransformed); 75 | }; 76 | 77 | static CheckCapsule = function(capsule) { 78 | if (!capsule.CheckOBB(self.property_obb)) return false; 79 | 80 | var untransformed = new ColCapsule(mat4_mul_point(self.property_inverse, capsule.line.start), mat4_mul_point(self.property_inverse, capsule.line.finish), capsule.radius); 81 | return self.mesh.CheckCapsule(untransformed); 82 | }; 83 | 84 | static CheckTriangle = function(triangle) { 85 | if (!self.property_obb.CheckTriangle(triangle)) return false; 86 | 87 | var inverse = self.property_inverse; 88 | // "homework" 89 | }; 90 | 91 | static CheckMesh = function(mesh) { 92 | if (!mesh.CheckOBB(self.property_obb)) return false; 93 | 94 | return false; 95 | }; 96 | 97 | static CheckModel = function(model) { 98 | if (!model.CheckOBB(self.property_obb)) return false; 99 | 100 | return false; 101 | }; 102 | 103 | static CheckLine = function(line) { 104 | if (!self.property_obb.CheckLine(line)) return false; 105 | 106 | var inverse = self.property_inverse; 107 | // "homework" 108 | }; 109 | 110 | static CheckRay = function(ray, hit_info = undefined) { 111 | if (!self.property_obb.CheckRay(ray)) return false; 112 | 113 | static untransformed_hit_info = new RaycastHitInformation(); 114 | untransformed_hit_info.distance = infinity; 115 | 116 | var untransformed = new ColRay(mat4_mul_point(self.property_inverse, ray.origin), mat4_mul_vector(self.property_inverse, ray.direction)); 117 | 118 | if (self.mesh.CheckRay(untransformed, untransformed_hit_info)) { 119 | if (hit_info) { 120 | var point = mat4_mul_point(self.property_transform, untransformed_hit_info.point); 121 | var normal = mat4_mul_vector(self.property_transform, untransformed_hit_info.normal); 122 | var distance = point_distance_3d(ray.origin.x, ray.origin.y, ray.origin.z, point.x, point.y, point.z); 123 | hit_info.Update(distance, self, point, normal); 124 | } 125 | return true; 126 | } 127 | 128 | return false; 129 | }; 130 | 131 | static DisplaceSphere = function(sphere) { 132 | return undefined; 133 | }; 134 | 135 | static GetMin = function() { 136 | return self.property_min.Clone(); 137 | }; 138 | 139 | static GetMax = function() { 140 | return self.property_max.Clone(); 141 | }; 142 | } -------------------------------------------------------------------------------- /3DCollisions.yyp: -------------------------------------------------------------------------------- 1 | { 2 | "$GMProject":"v1", 3 | "%Name":"3DCollisions", 4 | "AudioGroups":[ 5 | {"$GMAudioGroup":"v1","%Name":"audiogroup_default","exportDir":"","name":"audiogroup_default","resourceType":"GMAudioGroup","resourceVersion":"2.0","targets":-1,}, 6 | ], 7 | "configs":{ 8 | "children":[], 9 | "name":"Default", 10 | }, 11 | "defaultScriptType":1, 12 | "Folders":[ 13 | {"$GMFolder":"","%Name":"Collision Stuff","folderPath":"folders/Collision Stuff.yy","name":"Collision Stuff","resourceType":"GMFolder","resourceVersion":"2.0",}, 14 | {"$GMFolder":"","%Name":"Shapes","folderPath":"folders/Collision Stuff/Shapes.yy","name":"Shapes","resourceType":"GMFolder","resourceVersion":"2.0",}, 15 | {"$GMFolder":"","%Name":"Test stuff","folderPath":"folders/Test stuff.yy","name":"Test stuff","resourceType":"GMFolder","resourceVersion":"2.0",}, 16 | ], 17 | "ForcedPrefabProjectReferences":[], 18 | "IncludedFiles":[ 19 | {"$GMIncludedFile":"","%Name":"merry.vbuff","CopyToMask":-1,"filePath":"datafiles/meshes","name":"merry.vbuff","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, 20 | {"$GMIncludedFile":"","%Name":"terrain.vbuff","CopyToMask":-1,"filePath":"datafiles/meshes","name":"terrain.vbuff","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, 21 | {"$GMIncludedFile":"","%Name":"tree.vbuff","CopyToMask":-1,"filePath":"datafiles/meshes","name":"tree.vbuff","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, 22 | {"$GMIncludedFile":"","%Name":"aabb.vbuff","CopyToMask":-1,"filePath":"datafiles/shapes","name":"aabb.vbuff","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, 23 | {"$GMIncludedFile":"","%Name":"capsule_end.vbuff","CopyToMask":-1,"filePath":"datafiles/shapes","name":"capsule_end.vbuff","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, 24 | {"$GMIncludedFile":"","%Name":"capsule_middle.vbuff","CopyToMask":-1,"filePath":"datafiles/shapes","name":"capsule_middle.vbuff","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, 25 | {"$GMIncludedFile":"","%Name":"grid.vbuff","CopyToMask":-1,"filePath":"datafiles/shapes","name":"grid.vbuff","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, 26 | {"$GMIncludedFile":"","%Name":"obb.vbuff","CopyToMask":-1,"filePath":"datafiles/shapes","name":"obb.vbuff","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, 27 | {"$GMIncludedFile":"","%Name":"plane.vbuff","CopyToMask":-1,"filePath":"datafiles/shapes","name":"plane.vbuff","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, 28 | {"$GMIncludedFile":"","%Name":"point.vbuff","CopyToMask":-1,"filePath":"datafiles/shapes","name":"point.vbuff","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, 29 | {"$GMIncludedFile":"","%Name":"sphere.000.vbuff","CopyToMask":-1,"filePath":"datafiles/shapes","name":"sphere.000.vbuff","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, 30 | {"$GMIncludedFile":"","%Name":"sphere.vbuff","CopyToMask":-1,"filePath":"datafiles/shapes","name":"sphere.vbuff","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, 31 | {"$GMIncludedFile":"","%Name":"terrain.hm","CopyToMask":-1,"filePath":"datafiles","name":"terrain.hm","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, 32 | ], 33 | "isEcma":false, 34 | "LibraryEmitters":[], 35 | "MetaData":{ 36 | "IDEVersion":"2024.1400.1.926", 37 | }, 38 | "name":"3DCollisions", 39 | "resources":[ 40 | {"id":{"name":"fnt_demo","path":"fonts/fnt_demo/fnt_demo.yy",},}, 41 | {"id":{"name":"Col_Changelog","path":"notes/Col_Changelog/Col_Changelog.yy",},}, 42 | {"id":{"name":"obj_demo","path":"objects/obj_demo/obj_demo.yy",},}, 43 | {"id":{"name":"Room1","path":"rooms/Room1/Room1.yy",},}, 44 | {"id":{"name":"Col_Camera_Frustum","path":"scripts/Col_Camera_Frustum/Col_Camera_Frustum.yy",},}, 45 | {"id":{"name":"Col_Config","path":"scripts/Col_Config/Col_Config.yy",},}, 46 | {"id":{"name":"Col_Heightmap","path":"scripts/Col_Heightmap/Col_Heightmap.yy",},}, 47 | {"id":{"name":"Col_Helper_Functions","path":"scripts/Col_Helper_Functions/Col_Helper_Functions.yy",},}, 48 | {"id":{"name":"Col_Matrix","path":"scripts/Col_Matrix/Col_Matrix.yy",},}, 49 | {"id":{"name":"Col_SAT_Stuff","path":"scripts/Col_SAT_Stuff/Col_SAT_Stuff.yy",},}, 50 | {"id":{"name":"Col_Shape_AABB","path":"scripts/Col_Shape_AABB/Col_Shape_AABB.yy",},}, 51 | {"id":{"name":"Col_Shape_Capsule","path":"scripts/Col_Shape_Capsule/Col_Shape_Capsule.yy",},}, 52 | {"id":{"name":"Col_Shape_Line","path":"scripts/Col_Shape_Line/Col_Shape_Line.yy",},}, 53 | {"id":{"name":"Col_Shape_Mesh","path":"scripts/Col_Shape_Mesh/Col_Shape_Mesh.yy",},}, 54 | {"id":{"name":"Col_Shape_OBB","path":"scripts/Col_Shape_OBB/Col_Shape_OBB.yy",},}, 55 | {"id":{"name":"Col_Shape_Plane","path":"scripts/Col_Shape_Plane/Col_Shape_Plane.yy",},}, 56 | {"id":{"name":"Col_Shape_Point","path":"scripts/Col_Shape_Point/Col_Shape_Point.yy",},}, 57 | {"id":{"name":"Col_Shape_Ray","path":"scripts/Col_Shape_Ray/Col_Shape_Ray.yy",},}, 58 | {"id":{"name":"Col_Shape_Sphere","path":"scripts/Col_Shape_Sphere/Col_Shape_Sphere.yy",},}, 59 | {"id":{"name":"Col_Shape_Triangle","path":"scripts/Col_Shape_Triangle/Col_Shape_Triangle.yy",},}, 60 | {"id":{"name":"Col_Spatial_Hash","path":"scripts/Col_Spatial_Hash/Col_Spatial_Hash.yy",},}, 61 | {"id":{"name":"Col_Tests","path":"scripts/Col_Tests/Col_Tests.yy",},}, 62 | {"id":{"name":"Col_Transformed_Model","path":"scripts/Col_Transformed_Model/Col_Transformed_Model.yy",},}, 63 | {"id":{"name":"Col_Vector","path":"scripts/Col_Vector/Col_Vector.yy",},}, 64 | {"id":{"name":"Col_World","path":"scripts/Col_World/Col_World.yy",},}, 65 | {"id":{"name":"screen_to_world","path":"scripts/screen_to_world/screen_to_world.yy",},}, 66 | {"id":{"name":"shd_demo","path":"shaders/shd_demo/shd_demo.yy",},}, 67 | ], 68 | "resourceType":"GMProject", 69 | "resourceVersion":"2.0", 70 | "RoomOrderNodes":[ 71 | {"roomId":{"name":"Room1","path":"rooms/Room1/Room1.yy",},}, 72 | ], 73 | "templateType":null, 74 | "TextureGroups":[ 75 | {"$GMTextureGroup":"","%Name":"Default","autocrop":true,"border":2,"compressFormat":"bz2","customOptions":"","directory":"","groupParent":null,"isScaled":true,"loadType":"default","mipsToGenerate":0,"name":"Default","resourceType":"GMTextureGroup","resourceVersion":"2.0","targets":-1,}, 76 | ], 77 | } -------------------------------------------------------------------------------- /scripts/Col_Shape_Sphere/Col_Shape_Sphere.gml: -------------------------------------------------------------------------------- 1 | function ColSphere(position, radius) constructor { 2 | self.position = position; // Vec3 3 | self.radius = radius; // Vec3 4 | 5 | self.property_min = position.Sub(radius); 6 | self.property_max = position.Add(radius); 7 | 8 | static Set = function(position = self.position, radius = self.radius) { 9 | self.position = position; 10 | self.radius = radius; 11 | self.property_min.x = position.x - radius; 12 | self.property_min.y = position.y - radius; 13 | self.property_min.z = position.z - radius; 14 | self.property_max.x = position.x + radius; 15 | self.property_max.y = position.y + radius; 16 | self.property_max.z = position.z + radius; 17 | }; 18 | 19 | static CheckObject = function(object) { 20 | return object.shape.CheckSphere(self); 21 | }; 22 | 23 | static CheckPoint = function(point) { 24 | return point.CheckSphere(self); 25 | }; 26 | 27 | static CheckSphere = function(sphere) { 28 | var p1 = self.position; 29 | var p2 = sphere.position; 30 | return point_distance_3d(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z) < (self.radius + sphere.radius); 31 | }; 32 | 33 | static CheckAABB = function(aabb) { 34 | var pa = aabb.position; 35 | var ps = self.position; 36 | if (point_distance_3d(pa.x, pa.y, pa.z, ps.x, ps.y, ps.z) > aabb.property_radius + self.radius) return false; 37 | 38 | var box_min = aabb.property_min; 39 | var box_max = aabb.property_max; 40 | var nx = clamp(ps.x, box_min.x, box_max.x); 41 | var ny = clamp(ps.y, box_min.y, box_max.y); 42 | var nz = clamp(ps.z, box_min.z, box_max.z); 43 | 44 | return point_distance_3d(nx, ny, nz, ps.x, ps.y, ps.z) < self.radius; 45 | }; 46 | 47 | static CheckPlane = function(plane) { 48 | var ps = self.position; 49 | var pn = plane.normal; 50 | var dist = dot_product_3d(pn.x, pn.y, pn.z, ps.x, ps.y, ps.z) - plane.distance; 51 | return point_distance_3d( 52 | ps.x - pn.x * dist, 53 | ps.y - pn.y * dist, 54 | ps.z - pn.z * dist, ps.x, ps.y, ps.z) < self.radius; 55 | }; 56 | 57 | static CheckOBB = function(obb) { 58 | return obb.CheckSphere(self); 59 | }; 60 | 61 | static CheckCapsule = function(capsule) { 62 | return capsule.CheckSphere(self); 63 | }; 64 | 65 | static CheckTriangle = function(triangle) { 66 | var ps = self.position; 67 | var nearest = triangle.NearestPoint(ps); 68 | return point_distance_3d(nearest.x, nearest.y, nearest.z, ps.x, ps.y, ps.z) < self.radius; 69 | }; 70 | 71 | static CheckMesh = function(mesh) { 72 | return mesh.CheckSphere(self); 73 | }; 74 | 75 | static CheckModel = function(model) { 76 | return model.CheckSphere(self); 77 | }; 78 | 79 | static CheckRay = function(ray, hit_info = undefined) { 80 | var dir = ray.direction; 81 | var o = ray.origin; 82 | var p = self.position; 83 | var ex = p.x - o.x; 84 | var ey = p.y - o.y; 85 | var ez = p.z - o.z; 86 | var mag_squared = dot_product_3d(ex, ey, ez, ex, ey, ez); 87 | var r_squared = sqr(self.radius); 88 | var EdotD = dot_product_3d(ex, ey, ez, dir.x, dir.y, dir.z); 89 | var offset = r_squared - (mag_squared - (EdotD * EdotD)); 90 | if (offset < 0) return false; 91 | 92 | if (hit_info) { 93 | var f = sqrt(abs(offset)); 94 | var t = EdotD - f; 95 | if (mag_squared < r_squared) { 96 | t = EdotD + f; 97 | } 98 | static contact_point = new Vector3(0, 0, 0); 99 | contact_point.x = o.x + dir.x * t; 100 | contact_point.y = o.y + dir.y * t; 101 | contact_point.z = o.z + dir.z * t; 102 | 103 | //hit_info.Update(t, self, contact_point, contact_point.Sub(p).Normalize()); 104 | hit_info.Update(contact_point.DistanceTo(ray.origin), self, contact_point, contact_point.Sub(p).Normalize()); 105 | } 106 | 107 | return true; 108 | }; 109 | 110 | static CheckLine = function(line) { 111 | var p = self.position; 112 | var nearest = line.NearestPoint(p); 113 | return point_distance_3d(nearest.x, nearest.y, nearest.z, p.x, p.y, p.z) < self.radius; 114 | }; 115 | 116 | static DisplaceSphere = function(sphere) { 117 | if (!self.CheckSphere(sphere)) return undefined; 118 | 119 | var p1 = self.position; 120 | var p2 = sphere.position; 121 | if (p1.x == p2.x && p1.y == p2.y && p1.z == p2.z) return undefined; 122 | 123 | var dir = sphere.position.Sub(p1).Normalize(); 124 | var offset = dir.Mul(sphere.radius + self.radius); 125 | 126 | return p1.Add(offset); 127 | }; 128 | 129 | static NearestPoint = function(vec3) { 130 | var dist = vec3.Sub(self.position).Normalize(); 131 | var scaled_dist = dist.Mul(self.radius); 132 | return scaled_dist.Add(self.position); 133 | }; 134 | 135 | static GetMin = function() { 136 | return self.property_min.Clone(); 137 | }; 138 | 139 | static GetMax = function() { 140 | return self.property_max.Clone(); 141 | }; 142 | 143 | static CheckFrustum = function(frustum) { 144 | var planes = frustum.as_array; 145 | var is_intersecting_anything = false; 146 | var r = self.radius; 147 | var p = self.position; 148 | var px = p.x, py = p.y, pz = p.z; 149 | var i = 0; 150 | repeat (6) { 151 | var plane = planes[i++]; 152 | var n = plane.normal; 153 | var dist = dot_product_3d(n.x, n.y, n.z, px, py, pz) + plane.distance; 154 | 155 | if (dist < -r) 156 | return EFrustumResults.OUTSIDE; 157 | 158 | if (abs(dist) < r) 159 | is_intersecting_anything = true; 160 | } 161 | return is_intersecting_anything ? EFrustumResults.INTERSECTING : EFrustumResults.INSIDE; 162 | }; 163 | 164 | static CheckFrustumFast = function() { 165 | var p = self.position; 166 | return sphere_is_visible(p.x, p.y, p.z, self.radius) ? EFrustumResults.INSIDE : EFrustumResults.OUTSIDE; 167 | }; 168 | } -------------------------------------------------------------------------------- /scripts/Col_Shape_Line/Col_Shape_Line.gml: -------------------------------------------------------------------------------- 1 | function ColLine(start, finish) constructor { 2 | self.start = start; // Vec3 3 | self.finish = finish; // Vec3 4 | 5 | var sx = start.x, sy = start.y, sz = start.z; 6 | var fx = finish.x, fy = finish.y, fz = finish.z; 7 | self.property_min = new Vector3(min(sx, fx), min(sy, fy), min(sz, fz)); 8 | self.property_max = new Vector3(max(sx, fx), max(sy, fy), max(sz, fz)); 9 | self.property_ray = new ColRay(start, new Vector3(fx - sx, fy - sy, fz - sz)); 10 | self.property_length = point_distance_3d(sx, sy, sz, fx, fy, fz); 11 | self.property_center = new Vector3(mean(sx, fx), mean(sy, fy), mean(sz, fz)); 12 | 13 | static Set = function(start, finish) { 14 | self.start = start; 15 | self.finish = finish; 16 | var sx = start.x, sy = start.y, sz = start.z; 17 | var fx = finish.x, fy = finish.y, fz = finish.z; 18 | self.property_min.x = min(sx, fx); 19 | self.property_min.y = min(sy, fy); 20 | self.property_min.z = min(sz, fz); 21 | self.property_max.x = max(sx, fx); 22 | self.property_max.y = max(sy, fy); 23 | self.property_max.z = max(sz, fz); 24 | self.property_ray.origin = start; 25 | self.property_length = point_distance_3d(sx, sy, sz, fx, fy, fz); 26 | var mag = self.property_length; 27 | self.property_ray.direction.x = (fx - sx) / mag; 28 | self.property_ray.direction.y = (fy - sy) / mag; 29 | self.property_ray.direction.z = (fz - sz) / mag; 30 | self.property_center.x = mean(sx, fx); 31 | self.property_center.y = mean(sy, fy); 32 | self.property_center.z = mean(sz, fz); 33 | }; 34 | 35 | static CheckObject = function(object) { 36 | return object.shape.CheckLine(self); 37 | }; 38 | 39 | static CheckPoint = function(point) { 40 | return point.CheckLine(self); 41 | }; 42 | 43 | static CheckSphere = function(sphere) { 44 | return sphere.CheckLine(self); 45 | }; 46 | 47 | static CheckAABB = function(aabb) { 48 | return aabb.CheckLine(self); 49 | }; 50 | 51 | static CheckPlane = function(plane) { 52 | return plane.CheckLine(self); 53 | }; 54 | 55 | static CheckOBB = function(obb) { 56 | return obb.CheckLine(self); 57 | }; 58 | 59 | static CheckCapsule = function(capsule) { 60 | return capsule.CheckLine(self); 61 | }; 62 | 63 | static CheckTriangle = function(triangle) { 64 | return triangle.CheckLine(self); 65 | }; 66 | 67 | static CheckMesh = function(mesh) { 68 | return mesh.CheckLine(self); 69 | }; 70 | 71 | static CheckModel = function(model) { 72 | return model.CheckLine(self); 73 | }; 74 | 75 | static CheckRay = function(ray, hit_info = undefined) { 76 | return false; 77 | }; 78 | 79 | static CheckLine = function(line) { 80 | return false; 81 | }; 82 | 83 | static DisplaceSphere = function(sphere) { 84 | return undefined; 85 | }; 86 | 87 | static Length = function() { 88 | return self.property_length; 89 | }; 90 | 91 | static NearestPoint = function(vec3) { 92 | var start = self.start; 93 | var finish = self.finish; 94 | var lvx = finish.x - start.x; 95 | var lvy = finish.y - start.y; 96 | var lvz = finish.z - start.z; 97 | var px = vec3.x - start.x; 98 | var py = vec3.y - start.y; 99 | var pz = vec3.z - start.z; 100 | var t = clamp(dot_product_3d(px, py, pz, lvx, lvy, lvz) / dot_product_3d(lvx, lvy, lvz, lvx, lvy, lvz), 0, 1); 101 | return new Vector3( 102 | start.x + lvx * t, 103 | start.y + lvy * t, 104 | start.z + lvz * t 105 | ); 106 | }; 107 | 108 | static NearestConnectionToRay = function(ray) { 109 | var line1 = self; 110 | var line2 = ray; 111 | 112 | var start = line1.start; 113 | var finish = line1.finish; 114 | var origin = line2.origin; 115 | var dir = line2.direction; 116 | 117 | var d1x = finish.x - start.x; 118 | var d1y = finish.y - start.y; 119 | var d1z = finish.z - start.z; 120 | var d2x = dir.x; 121 | var d2y = dir.y; 122 | var d2z = dir.z; 123 | var rx = start.x - origin.x; 124 | var ry = start.y - origin.y; 125 | var rz = start.z - origin.z; 126 | 127 | var f = dot_product_3d(d2x, d2y, d2z, rx, ry, rz); 128 | var c = dot_product_3d(d1x, d1y, d1z, rx, ry, rz); 129 | var b = dot_product_3d(d1x, d1y, d1z, d2y, d2z, d2z); 130 | var length_squared = dot_product_3d(d1x, d1y, d1z, d1x, d1y, d1z); 131 | 132 | // special case if the line segment is actually just 133 | // two of the same points 134 | if (length_squared == 0) { 135 | return new ColLine(start, line2.NearestPoint(start)); 136 | } 137 | 138 | var f1 = 0; 139 | var f2 = 0; 140 | var denominator = length_squared - b * b; 141 | 142 | // if the two lines are parallel, there are infinitely many shortest 143 | // connecting lines, so you can just pick a random point on line1 to 144 | // work from - we'll pick the starting point 145 | if (denominator == 0) { 146 | f1 = 0; 147 | } else { 148 | f1 = clamp((b * f - c - 1) / denominator, 0, 1); 149 | } 150 | f2 = f1 * b + f; 151 | 152 | if (f2 < 0) { 153 | f2 = 0; 154 | f1 = clamp(-c / length_squared, 0, 1); 155 | } 156 | 157 | return new ColLine( 158 | new Vector3( 159 | start.x + d1x * f1, 160 | start.y + d1y * f1, 161 | start.z + d1z * f1 162 | ), new Vector3( 163 | origin.x + d2x * f2, 164 | origin.y + d2y * f2, 165 | origin.z + d2z * f2 166 | ) 167 | ); 168 | }; 169 | 170 | static NearestConnectionToLine = function(line) { 171 | var nearest_connection_to_ray = self.NearestConnectionToRay(line.property_ray); 172 | 173 | var start = self.start; 174 | var finish = self.finish; 175 | var lvx = finish.x - start.x; 176 | var lvy = finish.y - start.y; 177 | var lvz = finish.z - start.z; 178 | var ldd = dot_product_3d(lvx, lvy, lvz, lvx, lvy, lvz); 179 | 180 | var p = nearest_connection_to_ray.start; 181 | var px = p.x - start.x; 182 | var py = p.y - start.y; 183 | var pz = p.z - start.z; 184 | var t = clamp(dot_product_3d(px, py, pz, lvx, lvy, lvz) / ldd, 0, 1); 185 | 186 | var starting_point = new Vector3( 187 | start.x + lvx * t, 188 | start.y + lvy * t, 189 | start.z + lvz * t 190 | ); 191 | 192 | var lstart = line.start; 193 | p = nearest_connection_to_ray.finish; 194 | px = p.x - lstart.x; 195 | py = p.y - lstart.y; 196 | pz = p.z - lstart.z; 197 | t = clamp(dot_product_3d(px, py, pz, lvx, lvy, lvz) / ldd, 0, 1); 198 | 199 | var ending_point = new Vector3( 200 | lstart.x + lvx * t, 201 | lstart.y + lvy * t, 202 | lstart.z + lvz * t 203 | ); 204 | 205 | return new ColLine(starting_point, ending_point); 206 | }; 207 | 208 | static GetMin = function() { 209 | return self.property_min.Clone(); 210 | }; 211 | 212 | static GetMax = function() { 213 | return self.property_max.Clone(); 214 | }; 215 | } -------------------------------------------------------------------------------- /scripts/Col_Shape_Mesh/Col_Shape_Mesh.gml: -------------------------------------------------------------------------------- 1 | function ColMesh(triangle_array) constructor { 2 | self.triangles = triangle_array; 3 | 4 | self.property_min = new Vector3(infinity, infinity, infinity); 5 | self.property_max = new Vector3(-infinity, -infinity, -infinity); 6 | 7 | var bmn = self.property_min; 8 | var bmx = self.property_max; 9 | 10 | var i = 0; 11 | repeat (array_length(triangle_array)) { 12 | var tri = triangle_array[i++]; 13 | bmn.x = min(bmn.x, tri.a.x, tri.b.x, tri.c.x); 14 | bmn.y = min(bmn.y, tri.a.y, tri.b.y, tri.c.y); 15 | bmn.z = min(bmn.z, tri.a.z, tri.b.z, tri.c.z); 16 | bmx.x = max(bmx.x, tri.a.x, tri.b.x, tri.c.x); 17 | bmx.y = max(bmx.y, tri.a.y, tri.b.y, tri.c.y); 18 | bmx.z = max(bmx.z, tri.a.z, tri.b.z, tri.c.z); 19 | } 20 | 21 | self.bounds = NewColAABBFromMinMax(bmn, bmx); 22 | 23 | self.accelerator = new self.octree(self.bounds, self.octree); 24 | self.accelerator.triangles = triangle_array; 25 | var t = get_timer(); 26 | self.accelerator.Split(COL_MESH_MAX_SPLITS); 27 | show_debug_message($"hierarching the tree took {(get_timer() - t) / 1000} ms") 28 | 29 | static octree = function(bounds, octree) constructor { 30 | self.bounds = bounds; 31 | self.octree = octree; 32 | 33 | self.triangles = []; 34 | self.children = undefined; 35 | 36 | static Split = function(depth) { 37 | if (depth == 0) return; 38 | if (array_length(self.triangles) < COL_MIN_TREE_DENSITY) return; 39 | if (self.children != undefined) return; 40 | 41 | var center = self.bounds.position; 42 | var sides = self.bounds.half_extents.Mul(0.5); 43 | 44 | self.children = [ 45 | new self.octree(new ColAABB(center.Add(new Vector3(-sides.x, sides.y, -sides.z)), sides), self.octree), 46 | new self.octree(new ColAABB(center.Add(new Vector3( sides.x, sides.y, -sides.z)), sides), self.octree), 47 | new self.octree(new ColAABB(center.Add(new Vector3(-sides.x, sides.y, sides.z)), sides), self.octree), 48 | new self.octree(new ColAABB(center.Add(new Vector3( sides.x, sides.y, sides.z)), sides), self.octree), 49 | new self.octree(new ColAABB(center.Add(new Vector3(-sides.x, -sides.y, -sides.z)), sides), self.octree), 50 | new self.octree(new ColAABB(center.Add(new Vector3( sides.x, -sides.y, -sides.z)), sides), self.octree), 51 | new self.octree(new ColAABB(center.Add(new Vector3(-sides.x, -sides.y, sides.z)), sides), self.octree), 52 | new self.octree(new ColAABB(center.Add(new Vector3( sides.x, -sides.y, sides.z)), sides), self.octree), 53 | ]; 54 | 55 | var i = 0; 56 | repeat (array_length(self.children)) { 57 | var tree = self.children[i]; 58 | var j = 0; 59 | repeat (array_length(self.triangles)) { 60 | if (tree.bounds.CheckTriangle(self.triangles[j])) { 61 | array_push(tree.triangles, self.triangles[j]); 62 | } 63 | j++; 64 | } 65 | if (array_length(tree.triangles) == 0) { 66 | self.children[i] = undefined; 67 | } else { 68 | tree.Split(depth - 1); 69 | } 70 | i++; 71 | } 72 | }; 73 | }; 74 | 75 | static quadtree = function(bounds, quadtree) constructor { 76 | self.bounds = bounds; 77 | self.quadtree = quadtree; 78 | 79 | self.triangles = []; 80 | self.children = undefined; 81 | 82 | static Split = function(depth) { 83 | if (depth == 0) return; 84 | if (array_length(self.triangles) < COL_MIN_TREE_DENSITY) return; 85 | if (self.children != undefined) return; 86 | 87 | static subdivision_factor = new Vector3(0.5, 0.5, 1); 88 | 89 | var center = self.bounds.position; 90 | var sides = self.bounds.half_extents.Mul(subdivision_factor); 91 | 92 | self.children = [ 93 | new self.quadtree(new ColAABB(center.Add(new Vector3(-sides.x, sides.y, 0)), sides), self.quadtree), 94 | new self.quadtree(new ColAABB(center.Add(new Vector3( sides.x, sides.y, 0)), sides), self.quadtree), 95 | new self.quadtree(new ColAABB(center.Add(new Vector3(-sides.x, -sides.y, 0)), sides), self.quadtree), 96 | new self.quadtree(new ColAABB(center.Add(new Vector3( sides.x, -sides.y, 0)), sides), self.quadtree), 97 | ]; 98 | 99 | var i = 0; 100 | repeat (array_length(self.children)) { 101 | var tree = self.children[i]; 102 | var j = 0; 103 | repeat (array_length(self.triangles)) { 104 | if (tree.bounds.CheckTriangle(self.triangles[j])) { 105 | array_push(tree.triangles, self.triangles[j]); 106 | } 107 | j++; 108 | } 109 | if (array_length(tree.triangles) == 0) { 110 | self.children[i] = undefined; 111 | } else { 112 | tree.Split(depth - 1); 113 | } 114 | i++; 115 | } 116 | }; 117 | }; 118 | 119 | static CheckObject = function(object) { 120 | return object.shape.CheckMesh(self); 121 | }; 122 | 123 | static CheckGeneral = function(shape) { 124 | var process_these = [self.accelerator]; 125 | 126 | while (array_length(process_these) > 0) { 127 | var tree = process_these[0]; 128 | array_delete(process_these, 0, 1); 129 | 130 | if (tree.children == undefined) { 131 | for (var i = 0, n = array_length(tree.triangles); i < n; i++) { 132 | if (shape.CheckTriangle(tree.triangles[i])) { 133 | return true; 134 | } 135 | } 136 | } else { 137 | for (var i = 0, n = array_length(tree.children); i < n; i++) { 138 | if (tree.children[i] == undefined) continue; 139 | if (shape.CheckAABB(tree.children[i].bounds)) { 140 | array_push(process_these, tree.children[i]); 141 | } 142 | } 143 | } 144 | } 145 | 146 | return false; 147 | }; 148 | 149 | static CheckPoint = function(point) { 150 | return self.CheckGeneral(point); 151 | }; 152 | 153 | static CheckSphere = function(sphere) { 154 | return self.CheckGeneral(sphere); 155 | }; 156 | 157 | static CheckAABB = function(aabb) { 158 | return self.CheckGeneral(aabb); 159 | }; 160 | 161 | static CheckPlane = function(plane) { 162 | return self.CheckGeneral(plane); 163 | }; 164 | 165 | static CheckTriangle = function(triangle) { 166 | return self.CheckGeneral(triangle); 167 | }; 168 | 169 | static CheckMesh = function(mesh) { 170 | return self.CheckGeneral(mesh); 171 | }; 172 | 173 | static CheckModel = function(model) { 174 | return false; 175 | }; 176 | 177 | static CheckOBB = function(obb) { 178 | return self.CheckGeneral(obb); 179 | }; 180 | 181 | static CheckCapsule = function(capsule) { 182 | return self.CheckGeneral(capsule); 183 | }; 184 | 185 | static CheckRay = function(ray, hit_info = undefined) { 186 | var process_these = [self.accelerator]; 187 | static dummy_hit_info = new RaycastHitInformation(); 188 | dummy_hit_info.Clear(); 189 | 190 | var hit_detected = false; 191 | 192 | while (array_length(process_these) > 0) { 193 | var tree = process_these[0]; 194 | array_delete(process_these, 0, 1); 195 | 196 | if (tree.children == undefined) { 197 | for (var i = 0; i < array_length(tree.triangles); i++) { 198 | if (ray.CheckTriangle(tree.triangles[i], hit_info)) { 199 | hit_detected = true; 200 | } 201 | } 202 | } else { 203 | for (var i = 0, n = array_length(tree.children); i < n; i++) { 204 | if (tree.children[i] == undefined) continue; 205 | if (ray.CheckAABB(tree.children[i].bounds, dummy_hit_info)) { 206 | array_push(process_these, tree.children[i]); 207 | } 208 | } 209 | } 210 | } 211 | 212 | return hit_detected; 213 | }; 214 | 215 | static CheckLine = function(line) { 216 | static hit_info = new RaycastHitInformation(); 217 | hit_info.Clear(); 218 | 219 | if (self.CheckRay(line.property_ray, hit_info)) { 220 | return (hit_info.distance <= line.property_length); 221 | } 222 | return false; 223 | }; 224 | 225 | static DisplaceSphere = function(sphere) { 226 | return undefined; 227 | }; 228 | 229 | static GetMin = function() { 230 | return self.property_min.Clone(); 231 | }; 232 | 233 | static GetMax = function() { 234 | return self.property_max.Clone(); 235 | }; 236 | } -------------------------------------------------------------------------------- /scripts/Col_World/Col_World.gml: -------------------------------------------------------------------------------- 1 | function ColObject(shape, reference, mask = 1, group = 1) constructor { 2 | self.shape = shape; 3 | self.reference = reference; 4 | self.mask = mask; // what other objects can collide with me 5 | self.group = group; // what masks i can detect collisions with 6 | shape.object = self; 7 | 8 | static CheckObject = function(object) { 9 | if (object == self) return false; 10 | if ((self.mask & object.group) == 0) return false; 11 | return self.shape.CheckObject(object); 12 | }; 13 | 14 | static CheckRay = function(ray, hit_info, group = 1) { 15 | if ((self.mask & group) == 0) return false; 16 | return self.shape.CheckRay(ray, hit_info); 17 | }; 18 | 19 | static DisplaceSphere = function(sphere) { 20 | return self.shape.DisplaceSphere(sphere); 21 | }; 22 | 23 | static GetMin = function() { 24 | return self.shape.point_min; 25 | }; 26 | 27 | static GetMax = function() { 28 | return self.shape.point_max; 29 | }; 30 | } 31 | 32 | function ColWorld(accelerator) constructor { 33 | self.accelerator = accelerator; 34 | 35 | static Add = function(object) { 36 | self.accelerator.Add(object); 37 | }; 38 | 39 | static Remove = function(object) { 40 | self.accelerator.Remove(object); 41 | }; 42 | 43 | static Update = function(object) { 44 | self.Remove(object); 45 | self.Add(object); 46 | }; 47 | 48 | static CheckObject = function(object) { 49 | return self.accelerator.CheckObject(object); 50 | }; 51 | 52 | static CheckRay = function(ray, group = 1, distance = infinity) { 53 | var hit_info = new RaycastHitInformation(); 54 | 55 | if (self.accelerator.CheckRay(ray, hit_info, group)) { 56 | if (hit_info.distance <= distance) 57 | return hit_info; 58 | } 59 | 60 | return undefined; 61 | }; 62 | 63 | static DisplaceSphere = function(sphere_object, attempts = COL_DEFAULT_SPHERE_DISPLACEMENT_ATTEMPTS) { 64 | var current_position = sphere_object.shape.position; 65 | 66 | repeat (attempts) { 67 | var collided_with = self.accelerator.CheckObject(sphere_object); 68 | if (collided_with == undefined) break; 69 | 70 | var displaced_position = collided_with.shape.DisplaceSphere(sphere_object.shape); 71 | if (displaced_position == undefined) break; 72 | 73 | sphere_object.shape.Set(displaced_position); 74 | } 75 | 76 | var displaced_position = sphere_object.shape.position; 77 | sphere_object.shape.Set(current_position); 78 | 79 | if (current_position == displaced_position) return undefined; 80 | 81 | return displaced_position; 82 | }; 83 | 84 | static GetObjectsInFrustum = function(view_mat, proj_mat) { 85 | var current_camera = camera_get_active(); 86 | static filter_camera = camera_create(); 87 | camera_set_view_mat(filter_camera, view_mat); 88 | camera_set_proj_mat(filter_camera, proj_mat); 89 | camera_apply(filter_camera); 90 | matrix_set(matrix_view, view_mat); 91 | matrix_set(matrix_projection, proj_mat); 92 | var output = []; 93 | self.accelerator.GetObjectsInFrustum(output); 94 | var n = array_unique_ext(output); 95 | array_resize(output, n); 96 | camera_apply(current_camera); 97 | return output; 98 | }; 99 | } 100 | 101 | function ColWorldOctree(bounds, depth) constructor { 102 | self.bounds = bounds; 103 | self.depth = depth; 104 | 105 | self.contents = []; 106 | self.children = undefined; 107 | 108 | static Split = function() { 109 | var center = self.bounds.position; 110 | var sides = self.bounds.half_extents.Mul(0.5); 111 | var sx = sides.x; 112 | var sy = sides.y; 113 | var sz = sides.z; 114 | var d = self.depth - 1; 115 | 116 | var cx = center.x; 117 | var cy = center.y; 118 | var cz = center.z; 119 | 120 | self.children = [ 121 | new ColWorldOctree(new ColAABB(new Vector3(cx - sx, cy + sy, cz - sz), sides), d), 122 | new ColWorldOctree(new ColAABB(new Vector3(cx + sx, cy + sy, cz - sz), sides), d), 123 | new ColWorldOctree(new ColAABB(new Vector3(cx - sx, cy + sy, cz + sz), sides), d), 124 | new ColWorldOctree(new ColAABB(new Vector3(cx + sx, cy + sy, cz + sz), sides), d), 125 | new ColWorldOctree(new ColAABB(new Vector3(cx - sx, cy - sy, cz - sz), sides), d), 126 | new ColWorldOctree(new ColAABB(new Vector3(cx + sx, cy - sy, cz - sz), sides), d), 127 | new ColWorldOctree(new ColAABB(new Vector3(cx - sx, cy - sy, cz + sz), sides), d), 128 | new ColWorldOctree(new ColAABB(new Vector3(cx + sx, cy - sy, cz + sz), sides), d), 129 | ]; 130 | 131 | array_foreach(self.children, method({ contents: self.contents }, function(node) { 132 | array_foreach (self.contents, method({ node: node }, function(item) { 133 | self.node.Add(item); 134 | })); 135 | })); 136 | }; 137 | 138 | static Add = function(object) { 139 | if (!object.shape.CheckAABB(self.bounds)) return; 140 | if (array_contains(self.contents, object)) return; 141 | 142 | array_push(self.contents, object); 143 | 144 | if (self.depth > 0) { 145 | if (self.children == undefined && array_length(self.contents) >= COL_MIN_TREE_DENSITY) { 146 | self.Split(); 147 | } 148 | 149 | if (self.children != undefined) { 150 | array_foreach(self.children, method({ object: object }, function(node) { 151 | node.Add(self.object); 152 | })); 153 | } 154 | } 155 | }; 156 | 157 | static Remove = function(object) { 158 | var index = array_get_index(self.contents, object); 159 | if (index != -1) { 160 | array_delete(self.contents, index, 1); 161 | if (self.children != undefined) { 162 | array_foreach(self.children, method({ object: object }, function(subdivision) { 163 | subdivision.Remove(self.object); 164 | })); 165 | } 166 | } 167 | }; 168 | 169 | static CheckObject = function(object) { 170 | var to_check = [self]; 171 | while (array_length(to_check) > 0) { 172 | var tree = to_check[0]; 173 | array_delete(to_check, 0, 1); 174 | if (!object.shape.CheckAABB(tree.bounds)) continue; 175 | if (tree.children == undefined) { 176 | var i = 0; 177 | repeat (array_length(tree.contents)) { 178 | if (tree.contents[i].shape.CheckObject(object)) { 179 | return tree.contents[i]; 180 | } 181 | i++; 182 | } 183 | } else { 184 | var head = array_length(to_check); 185 | var additions = array_length(tree.children); 186 | array_resize(to_check, head + additions) 187 | array_copy(to_check, head, tree.children, 0, additions); 188 | } 189 | } 190 | 191 | return undefined; 192 | }; 193 | 194 | static CheckRay = function(ray, hit_info, group = 1) { 195 | if (!ray.CheckAABB(self.bounds)) return; 196 | 197 | var result = false; 198 | if (self.children == undefined) { 199 | var i = 0; 200 | repeat (array_length(self.contents)) { 201 | if (self.contents[i++].CheckRay(ray, hit_info, group)) { 202 | result = true; 203 | } 204 | } 205 | } else { 206 | var i = 0; 207 | repeat (array_length(self.children)) { 208 | if (self.children[i++].CheckRay(ray, hit_info, group)) { 209 | result = true; 210 | } 211 | } 212 | } 213 | 214 | return result; 215 | }; 216 | 217 | static GetObjectsInFrustum = function(output) { 218 | var status = self.bounds.CheckFrustumFast(); 219 | 220 | if (status == EFrustumResults.OUTSIDE) 221 | return; 222 | 223 | if (self.children == undefined) { 224 | var output_length = array_length(output); 225 | var contents_length = array_length(self.contents); 226 | array_resize(output, output_length + contents_length); 227 | array_copy(output, output_length, self.contents, 0, contents_length); 228 | return; 229 | } 230 | 231 | array_foreach(self.children, method({ output: output }, function(node) { 232 | node.GetObjectsInFrustum(self.output); 233 | })); 234 | }; 235 | } 236 | 237 | function ColWorldQuadtree(bounds, depth) : ColWorldOctree(bounds, depth) constructor { 238 | static Split = function() { 239 | static factor = new Vector3(0.5, 0.5, 1); 240 | 241 | var center = self.bounds.position; 242 | var sides = self.bounds.half_extents.Mul(factor); 243 | var sx = sides.x; 244 | var sy = sides.y; 245 | var d = self.depth - 1; 246 | 247 | var cx = center.x; 248 | var cy = center.y; 249 | var cz = center.z; 250 | 251 | self.children = [ 252 | new ColWorldQuadtree(new ColAABB(new Vector3(cx - sx, cy + sy, cz), sides), d), 253 | new ColWorldQuadtree(new ColAABB(new Vector3(cx + sx, cy + sy, cz), sides), d), 254 | new ColWorldQuadtree(new ColAABB(new Vector3(cx + sx, cy - sy, cz), sides), d), 255 | new ColWorldQuadtree(new ColAABB(new Vector3(cx - sx, cy - sy, cz), sides), d), 256 | ]; 257 | 258 | array_foreach(self.children, method({ contents: self.contents }, function(node) { 259 | array_foreach (self.contents, method({ node: node }, function(item) { 260 | self.node.Add(item); 261 | })); 262 | })); 263 | }; 264 | } -------------------------------------------------------------------------------- /scripts/Col_Spatial_Hash/Col_Spatial_Hash.gml: -------------------------------------------------------------------------------- 1 | // feather disable GM2023 2 | function ColWorldSpatialHash(chunk_size) constructor { 3 | self.chunk_size = chunk_size; 4 | self.chunks = { }; 5 | 6 | self.bounds = undefined; 7 | self.object_record = { }; 8 | 9 | self.planes = []; 10 | 11 | static HashFunction = function(x, y, z) { 12 | return $"{x},{y},{z}"; 13 | }; 14 | 15 | static GetBoundingChunk = function(object) { 16 | var object_min = object.shape.property_min; 17 | var object_max = object.shape.property_max; 18 | 19 | if (object_min == undefined) { 20 | return undefined; 21 | } 22 | 23 | return NewColAABBFromMinMax( 24 | new Vector3(floor(object_min.x / self.chunk_size), floor(object_min.y / self.chunk_size), floor(object_min.z / self.chunk_size)), 25 | new Vector3(floor(object_max.x / self.chunk_size), floor(object_max.y / self.chunk_size), floor(object_max.z / self.chunk_size)) 26 | ); 27 | }; 28 | 29 | static GetChunk = function(x, y, z) { 30 | return self.chunks[$ self.HashFunction(x, y, z)]; 31 | }; 32 | 33 | static AddChunk = function(x, y, z, chunk) { 34 | self.chunks[$ self.HashFunction(x, y, z)] = chunk; 35 | }; 36 | 37 | static RemoveChunk = function(x, y, z) { 38 | variable_struct_remove(self.chunks, self.HashFunction(x, y, z)); 39 | }; 40 | 41 | static Contains = function(object) { 42 | return self.object_record[$ string(ptr(object))]; 43 | }; 44 | 45 | static Add = function(object) { 46 | var bounds = self.GetBoundingChunk(object); 47 | 48 | if (bounds == undefined) { 49 | if (array_get_index(self.planes, object) == -1) { 50 | array_push(self.planes, object); 51 | } 52 | return; 53 | } 54 | 55 | var bounds_min = bounds.property_min; 56 | var bounds_max = bounds.property_max; 57 | 58 | // is the object already in the spatial hash? 59 | var location = self.Contains(object); 60 | if (location != undefined) { 61 | if (location.property_min.Equals(bounds_min) && location.property_max.Equals(bounds_max)) { 62 | // object's position is the same, there's no point 63 | return; 64 | } else { 65 | self.Remove(object); 66 | } 67 | } 68 | 69 | for (var i = bounds_min.x; i <= bounds_max.x; i++) { 70 | for (var j = bounds_min.y; j <= bounds_max.y; j++) { 71 | for (var k = bounds_min.z; k <= bounds_max.z; k++) { 72 | var chunk = self.GetChunk(i, j, k); 73 | 74 | if (chunk == undefined) { 75 | var coords = new Vector3(i, j, k); 76 | var coords_min = coords.Mul(self.chunk_size); 77 | var coords_max = coords_min.Add(self.chunk_size); 78 | 79 | var chunk_bounds = NewColAABBFromMinMax(coords_min, coords_max); 80 | chunk = new ColSpatialHashNode(chunk_bounds); 81 | self.AddChunk(i, j, k, chunk); 82 | 83 | if (self.bounds == undefined) { 84 | self.bounds = NewColAABBFromMinMax(coords_min, coords_max); 85 | } else { 86 | self.bounds = NewColAABBFromMinMax( 87 | self.bounds.property_min.Min(coords_min), 88 | self.bounds.property_max.Max(coords_max) 89 | ); 90 | } 91 | } 92 | 93 | chunk.Add(object); 94 | 95 | var object_id = string(ptr(object)); 96 | self.object_record[$ object_id] = bounds; 97 | } 98 | } 99 | } 100 | }; 101 | 102 | static Remove = function(object) { 103 | var plane_index = array_get_index(self.planes, object); 104 | if (plane_index != -1) { 105 | array_delete(self.planes, plane_index, 1); 106 | return; 107 | } 108 | 109 | var location = self.Contains(object); 110 | if (location == undefined) { 111 | return; 112 | } 113 | 114 | var bounds_min = location.property_min; 115 | var bounds_max = location.property_max; 116 | 117 | for (var i = bounds_min.x; i <= bounds_max.x; i++) { 118 | for (var j = bounds_min.y; j <= bounds_max.y; j++) { 119 | for (var k = bounds_min.z; k <= bounds_max.z; k++) { 120 | var chunk = self.GetChunk(i, j, k); 121 | chunk.Remove(object); 122 | 123 | if (chunk.Size() == 0) { 124 | self.RemoveChunk(i, j, k); 125 | 126 | // you may want to resize the bounds of the spatial hash 127 | // after removing an empty chunk, but i dont know if a nice 128 | // way to do that besides looping over every chunk from 129 | // scratch so I won't be doing that here 130 | } 131 | } 132 | } 133 | } 134 | 135 | var object_id = string(ptr(object)); 136 | variable_struct_remove(self.object_record, object_id); 137 | }; 138 | 139 | static CheckObject = function(object) { 140 | for (var i = 0, n = array_length(self.planes); i < n; i++) { 141 | if (self.planes[i].CheckObject(object)) 142 | return self.planes[i]; 143 | } 144 | 145 | var bounds = self.GetBoundingChunk(object); 146 | var bounds_min = bounds.property_min; 147 | var bounds_max = bounds.property_max; 148 | 149 | for (var i = bounds_min.x; i <= bounds_max.x; i++) { 150 | for (var j = bounds_min.y; j <= bounds_max.y; j++) { 151 | for (var k = bounds_min.z; k <= bounds_max.z; k++) { 152 | var chunk = self.GetChunk(i, j, k); 153 | 154 | if (chunk != undefined) { 155 | var result = chunk.CheckObject(object); 156 | if (result != undefined) return result; 157 | } 158 | } 159 | } 160 | } 161 | 162 | return undefined; 163 | }; 164 | 165 | // https://github.com/prime31/Nez/blob/master/Nez.Portable/Physics/SpatialHash.cs 166 | static CheckRay = function(ray, group = 1) { 167 | static bounds_hit_info = new RaycastHitInformation(); 168 | bounds_hit_info.shape = undefined; 169 | bounds_hit_info.point = undefined; 170 | bounds_hit_info.distance = infinity; 171 | bounds_hit_info.normal = undefined; 172 | 173 | var cs = self.chunk_size; 174 | var rd = ray.direction; 175 | var rdx = rd.x, rdy = rd.y, rdz = rd.z; 176 | var ro = ray.origin; 177 | 178 | var hit_info = new RaycastHitInformation(); 179 | 180 | for (var i = 0, n = array_length(self.planes); i < n; i++) { 181 | self.planes[i].CheckRay(ray, hit_info, group); 182 | } 183 | 184 | self.bounds.CheckRay(ray, bounds_hit_info); 185 | 186 | // if the ray does not pass through the spatial hash at all, you can 187 | // exit early 188 | if (bounds_hit_info.point == undefined) { 189 | if (hit_info.point == undefined) { 190 | return undefined; 191 | } else { 192 | return hit_info; 193 | } 194 | } 195 | 196 | var current_cell = ro.Div(cs).Floor(); 197 | 198 | var chunk = self.GetChunk(current_cell.x, current_cell.y, current_cell.z); 199 | if (chunk != undefined) { 200 | if (chunk.CheckRay(ray, hit_info, group)) { 201 | return hit_info; 202 | } 203 | } 204 | 205 | var last_cell = bounds_hit_info.point.Div(cs).Floor(); 206 | 207 | var dx = sign(rdx); 208 | var dy = sign(rdy); 209 | var dz = sign(rdz); 210 | 211 | if (current_cell.x == last_cell.x) dx = 0; 212 | if (current_cell.y == last_cell.y) dy = 0; 213 | if (current_cell.z == last_cell.z) dz = 0; 214 | 215 | var step_x = max(dx, 0); 216 | var step_y = max(dy, 0); 217 | var step_z = max(dz, 0); 218 | var next_boundary_x = (current_cell.x + step_x) * cs; 219 | var next_boundary_y = (current_cell.y + step_y) * cs; 220 | var next_boundary_z = (current_cell.z + step_z) * cs; 221 | 222 | var max_x = (rdx != 0) ? ((next_boundary_x - ro.x) / rdx) : infinity; 223 | var max_y = (rdy != 0) ? ((next_boundary_y - ro.y) / rdy) : infinity; 224 | var max_z = (rdz != 0) ? ((next_boundary_z - ro.z) / rdz) : infinity; 225 | 226 | var lookahead_x = (rdx != 0) ? floor(cs / (rdx * dx)) : infinity; 227 | var lookahead_y = (rdy != 0) ? floor(cs / (rdy * dy)) : infinity; 228 | var lookahead_z = (rdz != 0) ? floor(cs / (rdz * dz)) : infinity; 229 | 230 | do { 231 | if (max_x < max_y) { 232 | if (max_x < max_z) { 233 | current_cell.x += dx; 234 | max_x += lookahead_x; 235 | } else { 236 | current_cell.z += dz; 237 | max_z += lookahead_z; 238 | } 239 | } else { 240 | if (max_y < max_z) { 241 | current_cell.y += dy; 242 | max_y += lookahead_y; 243 | } else { 244 | current_cell.z += dz; 245 | max_z += lookahead_z; 246 | } 247 | } 248 | 249 | chunk = self.GetChunk(current_cell.x, current_cell.y, current_cell.z); 250 | if (chunk != undefined) { 251 | if (chunk.CheckRay(ray, hit_info, group)) { 252 | return hit_info; 253 | } 254 | } 255 | } until (current_cell.Equals(last_cell)); 256 | 257 | if (hit_info.point == undefined) { 258 | return undefined; 259 | } 260 | 261 | return hit_info; 262 | }; 263 | 264 | static GetObjectsInFrustum = function(frustum, output) { 265 | // not implemented 266 | }; 267 | } 268 | 269 | function ColSpatialHashNode(bounds) constructor { 270 | self.bounds = bounds; 271 | self.objects = []; 272 | 273 | static Add = function(object) { 274 | array_push(self.objects, object); 275 | }; 276 | 277 | static Remove = function(object) { 278 | var index = array_get_index(self.objects, object); 279 | array_delete(self.objects, index, 1); 280 | }; 281 | 282 | static Size = function() { 283 | return array_length(self.objects); 284 | }; 285 | 286 | static CheckObject = function(object) { 287 | var i = 0; 288 | repeat (array_length(self.objects)) { 289 | if (self.objects[i].shape.CheckObject(object)) 290 | return self.objects[i]; 291 | i++; 292 | } 293 | return undefined; 294 | }; 295 | 296 | static CheckRay = function(ray, hit_info, group = 1) { 297 | var hit_detected = false; 298 | var i = 0; 299 | repeat (array_length(self.objects)) { 300 | if (self.objects[i++].CheckRay(ray, hit_info, group)) 301 | hit_detected = true; 302 | } 303 | return hit_detected; 304 | }; 305 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /fonts/fnt_demo/fnt_test.old.yy: -------------------------------------------------------------------------------- 1 | { 2 | "hinting": 0, 3 | "glyphOperations": 0, 4 | "interpreter": 0, 5 | "pointRounding": 0, 6 | "fontName": "Arial", 7 | "styleName": "Regular", 8 | "size": 12.0, 9 | "bold": false, 10 | "italic": false, 11 | "charset": 0, 12 | "AntiAlias": 1, 13 | "first": 0, 14 | "last": 0, 15 | "sampleText": "abcdef ABCDEF\n0123456789 .,<>\"'&!?\nthe quick brown fox jumps over the lazy dog\nTHE QUICK BROWN FOX JUMPS OVER THE LAZY DOG\nDefault character: ▯ (9647)", 16 | "includeTTF": false, 17 | "TTFName": "", 18 | "textureGroupId": { 19 | "name": "Default", 20 | "path": "texturegroups/Default", 21 | }, 22 | "ascenderOffset": 0, 23 | "glyphs": { 24 | "32": {"x":2,"y":2,"w":4,"h":18,"character":32,"shift":4,"offset":0,}, 25 | "33": {"x":165,"y":42,"w":3,"h":18,"character":33,"shift":4,"offset":1,}, 26 | "34": {"x":158,"y":42,"w":5,"h":18,"character":34,"shift":6,"offset":0,}, 27 | "35": {"x":147,"y":42,"w":9,"h":18,"character":35,"shift":9,"offset":0,}, 28 | "36": {"x":136,"y":42,"w":9,"h":18,"character":36,"shift":9,"offset":0,}, 29 | "37": {"x":120,"y":42,"w":14,"h":18,"character":37,"shift":14,"offset":0,}, 30 | "38": {"x":107,"y":42,"w":11,"h":18,"character":38,"shift":11,"offset":0,}, 31 | "39": {"x":102,"y":42,"w":3,"h":18,"character":39,"shift":3,"offset":0,}, 32 | "40": {"x":95,"y":42,"w":5,"h":18,"character":40,"shift":5,"offset":0,}, 33 | "41": {"x":88,"y":42,"w":5,"h":18,"character":41,"shift":5,"offset":0,}, 34 | "42": {"x":170,"y":42,"w":6,"h":18,"character":42,"shift":6,"offset":0,}, 35 | "43": {"x":77,"y":42,"w":9,"h":18,"character":43,"shift":9,"offset":0,}, 36 | "44": {"x":61,"y":42,"w":3,"h":18,"character":44,"shift":4,"offset":1,}, 37 | "45": {"x":54,"y":42,"w":5,"h":18,"character":45,"shift":5,"offset":0,}, 38 | "46": {"x":49,"y":42,"w":3,"h":18,"character":46,"shift":4,"offset":1,}, 39 | "47": {"x":42,"y":42,"w":5,"h":18,"character":47,"shift":4,"offset":0,}, 40 | "48": {"x":31,"y":42,"w":9,"h":18,"character":48,"shift":9,"offset":0,}, 41 | "49": {"x":24,"y":42,"w":5,"h":18,"character":49,"shift":9,"offset":1,}, 42 | "50": {"x":13,"y":42,"w":9,"h":18,"character":50,"shift":9,"offset":0,}, 43 | "51": {"x":2,"y":42,"w":9,"h":18,"character":51,"shift":9,"offset":0,}, 44 | "52": {"x":240,"y":22,"w":9,"h":18,"character":52,"shift":9,"offset":0,}, 45 | "53": {"x":66,"y":42,"w":9,"h":18,"character":53,"shift":9,"offset":0,}, 46 | "54": {"x":178,"y":42,"w":9,"h":18,"character":54,"shift":9,"offset":0,}, 47 | "55": {"x":189,"y":42,"w":9,"h":18,"character":55,"shift":9,"offset":0,}, 48 | "56": {"x":200,"y":42,"w":9,"h":18,"character":56,"shift":9,"offset":0,}, 49 | "57": {"x":186,"y":62,"w":9,"h":18,"character":57,"shift":9,"offset":0,}, 50 | "58": {"x":181,"y":62,"w":3,"h":18,"character":58,"shift":4,"offset":1,}, 51 | "59": {"x":176,"y":62,"w":3,"h":18,"character":59,"shift":4,"offset":1,}, 52 | "60": {"x":165,"y":62,"w":9,"h":18,"character":60,"shift":9,"offset":0,}, 53 | "61": {"x":154,"y":62,"w":9,"h":18,"character":61,"shift":9,"offset":0,}, 54 | "62": {"x":143,"y":62,"w":9,"h":18,"character":62,"shift":9,"offset":0,}, 55 | "63": {"x":132,"y":62,"w":9,"h":18,"character":63,"shift":9,"offset":0,}, 56 | "64": {"x":114,"y":62,"w":16,"h":18,"character":64,"shift":16,"offset":0,}, 57 | "65": {"x":100,"y":62,"w":12,"h":18,"character":65,"shift":11,"offset":-1,}, 58 | "66": {"x":89,"y":62,"w":9,"h":18,"character":66,"shift":11,"offset":1,}, 59 | "67": {"x":76,"y":62,"w":11,"h":18,"character":67,"shift":12,"offset":0,}, 60 | "68": {"x":64,"y":62,"w":10,"h":18,"character":68,"shift":12,"offset":1,}, 61 | "69": {"x":53,"y":62,"w":9,"h":18,"character":69,"shift":11,"offset":1,}, 62 | "70": {"x":42,"y":62,"w":9,"h":18,"character":70,"shift":10,"offset":1,}, 63 | "71": {"x":28,"y":62,"w":12,"h":18,"character":71,"shift":12,"offset":0,}, 64 | "72": {"x":16,"y":62,"w":10,"h":18,"character":72,"shift":12,"offset":1,}, 65 | "73": {"x":11,"y":62,"w":3,"h":18,"character":73,"shift":4,"offset":1,}, 66 | "74": {"x":2,"y":62,"w":7,"h":18,"character":74,"shift":8,"offset":0,}, 67 | "75": {"x":235,"y":42,"w":10,"h":18,"character":75,"shift":11,"offset":1,}, 68 | "76": {"x":225,"y":42,"w":8,"h":18,"character":76,"shift":9,"offset":1,}, 69 | "77": {"x":211,"y":42,"w":12,"h":18,"character":77,"shift":13,"offset":1,}, 70 | "78": {"x":228,"y":22,"w":10,"h":18,"character":78,"shift":12,"offset":1,}, 71 | "79": {"x":214,"y":22,"w":12,"h":18,"character":79,"shift":12,"offset":0,}, 72 | "80": {"x":203,"y":22,"w":9,"h":18,"character":80,"shift":11,"offset":1,}, 73 | "81": {"x":232,"y":2,"w":12,"h":18,"character":81,"shift":12,"offset":0,}, 74 | "82": {"x":213,"y":2,"w":11,"h":18,"character":82,"shift":12,"offset":1,}, 75 | "83": {"x":201,"y":2,"w":10,"h":18,"character":83,"shift":11,"offset":0,}, 76 | "84": {"x":189,"y":2,"w":10,"h":18,"character":84,"shift":10,"offset":0,}, 77 | "85": {"x":177,"y":2,"w":10,"h":18,"character":85,"shift":12,"offset":1,}, 78 | "86": {"x":164,"y":2,"w":11,"h":18,"character":86,"shift":11,"offset":0,}, 79 | "87": {"x":147,"y":2,"w":15,"h":18,"character":87,"shift":15,"offset":0,}, 80 | "88": {"x":134,"y":2,"w":11,"h":18,"character":88,"shift":11,"offset":0,}, 81 | "89": {"x":121,"y":2,"w":11,"h":18,"character":89,"shift":11,"offset":0,}, 82 | "90": {"x":109,"y":2,"w":10,"h":18,"character":90,"shift":10,"offset":0,}, 83 | "91": {"x":226,"y":2,"w":4,"h":18,"character":91,"shift":4,"offset":1,}, 84 | "92": {"x":102,"y":2,"w":5,"h":18,"character":92,"shift":4,"offset":0,}, 85 | "93": {"x":89,"y":2,"w":4,"h":18,"character":93,"shift":4,"offset":0,}, 86 | "94": {"x":79,"y":2,"w":8,"h":18,"character":94,"shift":8,"offset":0,}, 87 | "95": {"x":66,"y":2,"w":11,"h":18,"character":95,"shift":9,"offset":-1,}, 88 | "96": {"x":60,"y":2,"w":4,"h":18,"character":96,"shift":5,"offset":0,}, 89 | "97": {"x":49,"y":2,"w":9,"h":18,"character":97,"shift":9,"offset":0,}, 90 | "98": {"x":39,"y":2,"w":8,"h":18,"character":98,"shift":9,"offset":1,}, 91 | "99": {"x":29,"y":2,"w":8,"h":18,"character":99,"shift":8,"offset":0,}, 92 | "100": {"x":19,"y":2,"w":8,"h":18,"character":100,"shift":9,"offset":0,}, 93 | "101": {"x":8,"y":2,"w":9,"h":18,"character":101,"shift":9,"offset":0,}, 94 | "102": {"x":95,"y":2,"w":5,"h":18,"character":102,"shift":4,"offset":0,}, 95 | "103": {"x":2,"y":22,"w":8,"h":18,"character":103,"shift":9,"offset":0,}, 96 | "104": {"x":97,"y":22,"w":7,"h":18,"character":104,"shift":9,"offset":1,}, 97 | "105": {"x":12,"y":22,"w":2,"h":18,"character":105,"shift":4,"offset":1,}, 98 | "106": {"x":187,"y":22,"w":4,"h":18,"character":106,"shift":4,"offset":-1,}, 99 | "107": {"x":178,"y":22,"w":7,"h":18,"character":107,"shift":8,"offset":1,}, 100 | "108": {"x":174,"y":22,"w":2,"h":18,"character":108,"shift":4,"offset":1,}, 101 | "109": {"x":160,"y":22,"w":12,"h":18,"character":109,"shift":13,"offset":1,}, 102 | "110": {"x":151,"y":22,"w":7,"h":18,"character":110,"shift":9,"offset":1,}, 103 | "111": {"x":140,"y":22,"w":9,"h":18,"character":111,"shift":9,"offset":0,}, 104 | "112": {"x":130,"y":22,"w":8,"h":18,"character":112,"shift":9,"offset":1,}, 105 | "113": {"x":120,"y":22,"w":8,"h":18,"character":113,"shift":9,"offset":0,}, 106 | "114": {"x":113,"y":22,"w":5,"h":18,"character":114,"shift":5,"offset":1,}, 107 | "115": {"x":193,"y":22,"w":8,"h":18,"character":115,"shift":8,"offset":0,}, 108 | "116": {"x":106,"y":22,"w":5,"h":18,"character":116,"shift":4,"offset":0,}, 109 | "117": {"x":88,"y":22,"w":7,"h":18,"character":117,"shift":9,"offset":1,}, 110 | "118": {"x":78,"y":22,"w":8,"h":18,"character":118,"shift":8,"offset":0,}, 111 | "119": {"x":64,"y":22,"w":12,"h":18,"character":119,"shift":12,"offset":0,}, 112 | "120": {"x":54,"y":22,"w":8,"h":18,"character":120,"shift":8,"offset":0,}, 113 | "121": {"x":44,"y":22,"w":8,"h":18,"character":121,"shift":8,"offset":0,}, 114 | "122": {"x":34,"y":22,"w":8,"h":18,"character":122,"shift":8,"offset":0,}, 115 | "123": {"x":27,"y":22,"w":5,"h":18,"character":123,"shift":5,"offset":0,}, 116 | "124": {"x":23,"y":22,"w":2,"h":18,"character":124,"shift":4,"offset":1,}, 117 | "125": {"x":16,"y":22,"w":5,"h":18,"character":125,"shift":5,"offset":0,}, 118 | "126": {"x":197,"y":62,"w":9,"h":18,"character":126,"shift":9,"offset":0,}, 119 | "9647": {"x":208,"y":62,"w":10,"h":18,"character":9647,"shift":16,"offset":3,}, 120 | }, 121 | "kerningPairs": [ 122 | {"first":32,"second":65,"amount":-1,}, 123 | {"first":32,"second":902,"amount":-1,}, 124 | {"first":32,"second":913,"amount":-1,}, 125 | {"first":32,"second":916,"amount":-1,}, 126 | {"first":32,"second":923,"amount":-1,}, 127 | {"first":49,"second":49,"amount":-1,}, 128 | {"first":65,"second":32,"amount":-1,}, 129 | {"first":65,"second":84,"amount":-1,}, 130 | {"first":65,"second":86,"amount":-1,}, 131 | {"first":65,"second":89,"amount":-1,}, 132 | {"first":65,"second":160,"amount":-1,}, 133 | {"first":65,"second":8217,"amount":-1,}, 134 | {"first":70,"second":44,"amount":-1,}, 135 | {"first":70,"second":46,"amount":-1,}, 136 | {"first":70,"second":65,"amount":-1,}, 137 | {"first":76,"second":84,"amount":-1,}, 138 | {"first":76,"second":86,"amount":-1,}, 139 | {"first":76,"second":87,"amount":-1,}, 140 | {"first":76,"second":89,"amount":-1,}, 141 | {"first":76,"second":8217,"amount":-1,}, 142 | {"first":80,"second":44,"amount":-1,}, 143 | {"first":80,"second":46,"amount":-1,}, 144 | {"first":80,"second":65,"amount":-1,}, 145 | {"first":84,"second":44,"amount":-1,}, 146 | {"first":84,"second":45,"amount":-1,}, 147 | {"first":84,"second":46,"amount":-1,}, 148 | {"first":84,"second":58,"amount":-1,}, 149 | {"first":84,"second":59,"amount":-1,}, 150 | {"first":84,"second":65,"amount":-1,}, 151 | {"first":84,"second":97,"amount":-1,}, 152 | {"first":84,"second":99,"amount":-1,}, 153 | {"first":84,"second":101,"amount":-1,}, 154 | {"first":84,"second":111,"amount":-1,}, 155 | {"first":84,"second":115,"amount":-1,}, 156 | {"first":84,"second":119,"amount":-1,}, 157 | {"first":84,"second":121,"amount":-1,}, 158 | {"first":84,"second":173,"amount":-1,}, 159 | {"first":84,"second":894,"amount":-1,}, 160 | {"first":86,"second":44,"amount":-1,}, 161 | {"first":86,"second":45,"amount":-1,}, 162 | {"first":86,"second":46,"amount":-1,}, 163 | {"first":86,"second":65,"amount":-1,}, 164 | {"first":86,"second":97,"amount":-1,}, 165 | {"first":86,"second":101,"amount":-1,}, 166 | {"first":86,"second":111,"amount":-1,}, 167 | {"first":86,"second":173,"amount":-1,}, 168 | {"first":87,"second":44,"amount":-1,}, 169 | {"first":87,"second":46,"amount":-1,}, 170 | {"first":89,"second":44,"amount":-1,}, 171 | {"first":89,"second":45,"amount":-1,}, 172 | {"first":89,"second":46,"amount":-1,}, 173 | {"first":89,"second":58,"amount":-1,}, 174 | {"first":89,"second":59,"amount":-1,}, 175 | {"first":89,"second":65,"amount":-1,}, 176 | {"first":89,"second":97,"amount":-1,}, 177 | {"first":89,"second":101,"amount":-1,}, 178 | {"first":89,"second":111,"amount":-1,}, 179 | {"first":89,"second":112,"amount":-1,}, 180 | {"first":89,"second":113,"amount":-1,}, 181 | {"first":89,"second":117,"amount":-1,}, 182 | {"first":89,"second":118,"amount":-1,}, 183 | {"first":89,"second":173,"amount":-1,}, 184 | {"first":89,"second":894,"amount":-1,}, 185 | {"first":114,"second":44,"amount":-1,}, 186 | {"first":114,"second":46,"amount":-1,}, 187 | {"first":118,"second":44,"amount":-1,}, 188 | {"first":118,"second":46,"amount":-1,}, 189 | {"first":119,"second":44,"amount":-1,}, 190 | {"first":119,"second":46,"amount":-1,}, 191 | {"first":121,"second":44,"amount":-1,}, 192 | {"first":121,"second":46,"amount":-1,}, 193 | ], 194 | "ranges": [ 195 | {"lower":32,"upper":127,}, 196 | {"lower":9647,"upper":9647,}, 197 | ], 198 | "regenerateBitmap": false, 199 | "canGenerateBitmap": true, 200 | "maintainGms1Font": false, 201 | "parent": { 202 | "name": "3D Collisions - Lesson Plan", 203 | "path": "3D Collisions - Lesson Plan.yyp", 204 | }, 205 | "resourceVersion": "1.0", 206 | "name": "fnt_test", 207 | "tags": [], 208 | "resourceType": "GMFont", 209 | } -------------------------------------------------------------------------------- /scripts/Col_Shape_Capsule/Col_Shape_Capsule.gml: -------------------------------------------------------------------------------- 1 | function ColCapsule(start, finish, radius) constructor { 2 | self.line = undefined; 3 | self.radius = 0; 4 | self.Set(start, finish, radius); 5 | 6 | static Set = function(start = self.line.start, finish = self.line.finish, radius = self.radius) { 7 | if (self.line) { 8 | self.line.Set(start, finish); 9 | } else { 10 | self.line = new ColLine(start, finish); 11 | } 12 | var line = self.line; 13 | self.radius = radius; 14 | self.property_center = line.property_center; 15 | self.property_radius = line.property_length / 2 + radius; 16 | self.property_min = line.property_min.Sub(radius); 17 | self.property_max = line.property_min.Add(radius); 18 | }; 19 | 20 | static CheckObject = function(object) { 21 | return object.shape.CheckCapsule(self); 22 | }; 23 | 24 | static CheckPoint = function(point) { 25 | var nearest = self.line.NearestPoint(point.position); 26 | var dist = nearest.DistanceTo(point.position); 27 | 28 | return dist < self.radius; 29 | }; 30 | 31 | static CheckSphere = function(sphere) { 32 | var nearest = self.line.NearestPoint(sphere.position); 33 | var dist = nearest.DistanceTo(sphere.position); 34 | 35 | return dist < (self.radius + sphere.radius); 36 | }; 37 | 38 | static CheckAABB = function(aabb) { 39 | var p1 = self.property_center; 40 | var p2 = aabb.position; 41 | if (point_distance_3d(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z) >= (self.property_radius + aabb.property_radius)) return false; 42 | 43 | var r = self.radius; 44 | var line = self.line; 45 | var line_start = self.line.start; 46 | var line_finish = self.line.finish; 47 | var box_min = aabb.property_min; 48 | var box_max = aabb.property_max; 49 | var bmnx = box_min.x; 50 | var bmny = box_min.y; 51 | var bmnz = box_min.z; 52 | var bmxx = box_max.x; 53 | var bmxy = box_max.y; 54 | var bmxz = box_max.z; 55 | var lvx = line_finish.x - line_start.x; 56 | var lvy = line_finish.y - line_start.y; 57 | var lvz = line_finish.z - line_start.z; 58 | var lsx = line_start.x; 59 | var lsy = line_start.y; 60 | var lsz = line_start.z; 61 | var ldd = dot_product_3d(lvx, lvy, lvz, lvx, lvy, lvz); 62 | 63 | var nx = clamp(line_start.x, bmnx, bmxx); 64 | var ny = clamp(line_start.y, bmny, bmxy); 65 | var nz = clamp(line_start.z, bmnz, bmxz); 66 | if (point_distance_3d(nx, ny, nz, line_start.x, line_start.y, line_start.z) < r) return true; 67 | 68 | nx = clamp(line_finish.x, bmnx, bmxx); 69 | ny = clamp(line_finish.y, bmny, bmxy); 70 | nz = clamp(line_finish.z, bmnz, bmxz); 71 | if (point_distance_3d(nx, ny, nz, line_finish.x, line_finish.y, line_finish.z) < r) return true; 72 | 73 | var edges = aabb.property_edges; 74 | 75 | var i = 0; 76 | repeat (12) { 77 | var nearest_line_to_edge = edges[i++].NearestConnectionToLine(line); 78 | var nearest_start = nearest_line_to_edge.start; 79 | 80 | var px = nearest_start.x - lsx; 81 | var py = nearest_start.y - lsy; 82 | var pz = nearest_start.z - lsz; 83 | var t = clamp(dot_product_3d(px, py, pz, lvx, lvy, lvz) / ldd , 0, 1); 84 | 85 | var p = (lsx + lvx * t == nearest_start.x && lsy + lvy * t == nearest_start.y && lsz + lvz * t == nearest_start.z) ? nearest_line_to_edge.start : nearest_line_to_edge.finish; 86 | 87 | nx = clamp(p.x, bmnx, bmxx); 88 | ny = clamp(p.y, bmny, bmxy); 89 | nz = clamp(p.z, bmnz, bmxz); 90 | 91 | if (point_distance_3d(nx, ny, nz, p.x, p.y, p.z) < r) return true; 92 | } 93 | 94 | return false; 95 | }; 96 | 97 | static CheckPlane = function(plane) { 98 | var start = self.line.start; 99 | var nearest = plane.NearestPoint(start); 100 | if (point_distance_3d(nearest.x, nearest.y, nearest.z, start.x, start.y, start.z) < self.radius) return true; 101 | 102 | var finish = self.line.finish; 103 | nearest = plane.NearestPoint(finish); 104 | if (point_distance_3d(nearest.x, nearest.y, nearest.z, finish.x, finish.y, finish.z) < self.radius) return true; 105 | 106 | return self.line.CheckPlane(plane); 107 | }; 108 | 109 | static CheckOBB = function(obb) { 110 | var p1 = self.property_center; 111 | var p2 = obb.position; 112 | if (point_distance_3d(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z) >= (self.property_radius + obb.property_radius)) return false; 113 | 114 | var obb_position = obb.position; 115 | var obb_orientation = obb.property_orientation_array; 116 | var obb_size_array = [obb.size.x, obb.size.y, obb.size.z]; 117 | 118 | var r = self.radius; 119 | var line = self.line; 120 | var p = line.start; 121 | 122 | var nx = obb_position.x, ny = obb_position.y, nz = obb_position.z; 123 | var dx = p.x - nx, dy = p.y - ny, dz = p.z - nz; 124 | 125 | for (var i = 0; i < 3; i++) { 126 | var axis = obb_orientation[i]; 127 | var dist = dot_product_3d(dx, dy, dz, axis.x, axis.y, axis.z); 128 | dist = clamp(dist, -obb_size_array[i], obb_size_array[i]); 129 | nx += axis.x * dist; 130 | ny += axis.y * dist; 131 | nz += axis.z * dist; 132 | } 133 | 134 | if (point_distance_3d(nx, ny, nz, p.x, p.y, p.z) < r) return true; 135 | p = line.finish; 136 | 137 | nx = obb_position.x; 138 | ny = obb_position.y; 139 | nz = obb_position.z; 140 | dx = p.x - nx; 141 | dy = p.y - ny; 142 | dz = p.z - nz; 143 | 144 | for (var i = 0; i < 3; i++) { 145 | var axis = obb_orientation[i]; 146 | var dist = dot_product_3d(dx, dy, dz, axis.x, axis.y, axis.z); 147 | dist = clamp(dist, -obb_size_array[i], obb_size_array[i]); 148 | nx += axis.x * dist; 149 | ny += axis.y * dist; 150 | nz += axis.z * dist; 151 | } 152 | 153 | if (point_distance_3d(nx, ny, nz, p.x, p.y, p.z) < r) return true; 154 | 155 | var edges = obb.property_edges; 156 | 157 | var i = 0; 158 | repeat (12) { 159 | var nearest_line_to_edge = edges[i++].NearestConnectionToLine(line); 160 | var nearest_start = nearest_line_to_edge.start; 161 | var nearest_self = line.NearestPoint(nearest_start); 162 | 163 | p = (nearest_self.x == nearest_start.x && nearest_self.y == nearest_start.y && nearest_self.z == nearest_start.z) ? nearest_line_to_edge.start : nearest_line_to_edge.finish; 164 | 165 | nx = obb_position.x; 166 | ny = obb_position.y; 167 | nz = obb_position.z; 168 | dx = p.x - nx; 169 | dy = p.y - ny; 170 | dz = p.z - nz; 171 | 172 | for (var j = 0; j < 3; j++) { 173 | var axis = obb.property_orientation_array[j]; 174 | var dist = dot_product_3d(dx, dy, dz, axis.x, axis.y, axis.z); 175 | dist = clamp(dist, -obb_size_array[j], obb_size_array[j]); 176 | nx += axis.x * dist; 177 | ny += axis.y * dist; 178 | nz += axis.z * dist; 179 | } 180 | 181 | if (point_distance_3d(nx, ny, nz, p.x, p.y, p.z) < r) return true; 182 | } 183 | 184 | return false; 185 | }; 186 | 187 | static CheckCapsule = function(capsule) { 188 | var p1 = self.property_center; 189 | var p2 = capsule.property_center; 190 | if (point_distance_3d(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z) >= (self.property_radius + capsule.property_radius)) return false; 191 | 192 | var connecting_line = self.line.NearestConnectionToLine(capsule.line); 193 | return connecting_line.property_length < (self.radius + capsule.radius); 194 | }; 195 | 196 | static CheckTriangle = function(triangle) { 197 | var p1 = self.property_center; 198 | var p2 = triangle.property_center; 199 | if (point_distance_3d(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z) >= (self.property_radius + triangle.property_radius)) return false; 200 | 201 | var line = self.line; 202 | var target = triangle.NearestPoint(line.start); 203 | var nearest = line.NearestPoint(target); 204 | if (point_distance_3d(nearest.x, nearest.y, nearest.z, target.x, target.y, target.z) < self.radius) return true; 205 | 206 | target = triangle.NearestPoint(line.finish); 207 | nearest = line.NearestPoint(target); 208 | if (point_distance_3d(nearest.x, nearest.y, nearest.z, target.x, target.y, target.z) < self.radius) return true; 209 | 210 | return false; 211 | }; 212 | 213 | static CheckMesh = function(mesh) { 214 | return mesh.CheckCapsule(self); 215 | }; 216 | 217 | static CheckModel = function(model) { 218 | return model.CheckCapsule(self); 219 | }; 220 | 221 | static CheckRay = function(ray, hit_info = undefined) { 222 | var center = self.property_center; 223 | var nearest = ray.NearestPoint(center); 224 | if (point_distance_3d(nearest.x, nearest.y, nearest.z, center.x, center.y, center.z) >= self.property_radius) return false; 225 | 226 | var line = self.line; 227 | var cd = line.property_ray.direction.Mul(line.Length()); 228 | var rd = ray.direction; 229 | var ro = ray.origin; 230 | var oa = ro.Sub(line.start); 231 | 232 | var baba = dot_product_3d(cd.x, cd.y, cd.z, cd.x, cd.y, cd.z); 233 | var bard = dot_product_3d(cd.x, cd.y, cd.z, rd.x, rd.y, rd.z); 234 | var baoa = dot_product_3d(cd.x, cd.y, cd.z, oa.x, oa.y, oa.z); 235 | var rdoa = dot_product_3d(rd.x, rd.y, rd.z, oa.x, oa.y, oa.z); 236 | var oaoa = dot_product_3d(oa.x, oa.y, oa.z, oa.x, oa.y, oa.z); 237 | 238 | var a = baba - sqr(bard); 239 | var b = baba * rdoa - baoa * bard; 240 | var c = baba * oaoa - sqr(baoa) - sqr(self.radius) * baba; 241 | var h = sqr(b) - a * c; 242 | 243 | if (h > 0) { 244 | var t = (-b - sqrt(h)) / a; 245 | var why = baoa + t * bard; 246 | 247 | if (why > 0 && why < baba) { 248 | if (hit_info) { 249 | var contact_point = ro.Add(rd.Mul(t)); 250 | var nearest_inner_point = line.NearestPoint(contact_point); 251 | var contact_normal = contact_point.Sub(nearest_inner_point).Normalize(); 252 | hit_info.Update(t, self, contact_point, contact_normal); 253 | } 254 | return true; 255 | } 256 | 257 | var oc = (why <= 0) ? oa : ro.Sub(line.finish); 258 | b = dot_product_3d(rd.x, rd.y, rd.z, oc.x, oc.y, oc.z); 259 | c = dot_product_3d(oc.x, oc.y, oc.z, oc.x, oc.y, oc.z) - sqr(self.radius); 260 | h = sqr(b) - c; 261 | 262 | if (h > 0) { 263 | if (hit_info) { 264 | t = -b - sqrt(h); 265 | var contact_point = ro.Add(rd.Mul(t)); 266 | var nearest_inner_point = line.NearestPoint(contact_point); 267 | var contact_normal = contact_point.Sub(nearest_inner_point).Normalize(); 268 | hit_info.Update(t, self, contact_point, contact_normal); 269 | } 270 | return true; 271 | } 272 | } 273 | 274 | return false; 275 | }; 276 | 277 | static CheckLine = function(line) { 278 | var closest_line = self.line.NearestConnectionToLine(line); 279 | return closest_line.property_length < self.radius; 280 | }; 281 | 282 | static DisplaceSphere = function(sphere) { 283 | if (!self.CheckSphere(sphere)) return undefined; 284 | 285 | var ps = sphere.position; 286 | var nearest = self.line.NearestPoint(ps); 287 | 288 | if (ps.x == nearest.x && ps.y == nearest.y && ps.z == nearest.z) return undefined; 289 | 290 | var dir = ps.Sub(nearest).Normalize(); 291 | var offset = dir.Mul(sphere.radius + self.radius); 292 | 293 | return nearest.Add(offset); 294 | }; 295 | 296 | static GetMin = function() { 297 | return self.property_min.Clone(); 298 | }; 299 | 300 | static GetMax = function() { 301 | return self.property_max.Clone(); 302 | }; 303 | } -------------------------------------------------------------------------------- /scripts/Col_Shape_AABB/Col_Shape_AABB.gml: -------------------------------------------------------------------------------- 1 | function ColAABB(position, half_extents) constructor { 2 | self.position = undefined; 3 | self.half_extents = undefined; 4 | self.Set(position, half_extents); 5 | 6 | static Set = function(position = self.position, half_extents = self.half_extents) { 7 | self.position = position; 8 | self.half_extents = half_extents; 9 | 10 | self.property_min = position.Sub(half_extents); 11 | self.property_max = position.Add(half_extents); 12 | self.property_radius = point_distance_3d(0, 0, 0, half_extents.x, half_extents.y, half_extents.z); 13 | 14 | var pmin = self.property_min; 15 | var pmax = self.property_max; 16 | 17 | self.property_vertices = [ 18 | new Vector3(pmin.x, pmax.y, pmax.z), 19 | new Vector3(pmin.x, pmax.y, pmin.z), 20 | new Vector3(pmin.x, pmin.y, pmax.z), 21 | new Vector3(pmin.x, pmin.y, pmin.z), 22 | new Vector3(pmax.x, pmax.y, pmax.z), 23 | new Vector3(pmax.x, pmax.y, pmin.z), 24 | new Vector3(pmax.x, pmin.y, pmax.z), 25 | new Vector3(pmax.x, pmin.y, pmin.z) 26 | ]; 27 | 28 | var vertices = self.property_vertices; 29 | 30 | self.property_edges = [ 31 | new ColLine(vertices[0], vertices[1]), 32 | new ColLine(vertices[0], vertices[2]), 33 | new ColLine(vertices[1], vertices[3]), 34 | new ColLine(vertices[2], vertices[3]), 35 | new ColLine(vertices[4], vertices[5]), 36 | new ColLine(vertices[4], vertices[6]), 37 | new ColLine(vertices[5], vertices[7]), 38 | new ColLine(vertices[6], vertices[7]), 39 | new ColLine(vertices[0], vertices[4]), 40 | new ColLine(vertices[1], vertices[5]), 41 | new ColLine(vertices[2], vertices[6]), 42 | new ColLine(vertices[3], vertices[7]) 43 | ]; 44 | }; 45 | 46 | static CheckObject = function(object) { 47 | return object.shape.CheckAABB(self); 48 | }; 49 | 50 | static CheckPoint = function(point) { 51 | return point.CheckAABB(self); 52 | }; 53 | 54 | static CheckSphere = function(sphere) { 55 | return sphere.CheckAABB(self); 56 | }; 57 | 58 | static CheckAABB = function(aabb) { 59 | var box_min = self.property_min; 60 | var box_max = self.property_max; 61 | var other_min = aabb.property_min; 62 | var other_max = aabb.property_max; 63 | return ((box_min.x <= other_max.x) && (box_max.x >= other_min.x) && (box_min.y <= other_max.y) && (box_max.y >= other_min.y) && (box_min.z <= other_max.z) && (box_max.z >= other_min.z)); 64 | }; 65 | 66 | static CheckPlane = function(plane) { 67 | var size = self.half_extents; 68 | var normal = plane.normal; 69 | var pos = self.position; 70 | var anx = abs(normal.x); 71 | var any = abs(normal.y); 72 | var anz = abs(normal.z); 73 | var plength = dot_product_3d(anx, any, anz, size.x, size.y, size.z); 74 | var ndot = dot_product_3d(normal.x, normal.y, normal.z, pos.x, pos.y, pos.z); 75 | return (abs(ndot - plane.distance) <= plength); 76 | }; 77 | 78 | static CheckOBB = function(obb) { 79 | return obb.CheckAABB(self); 80 | }; 81 | 82 | static CheckCapsule = function(capsule) { 83 | return capsule.CheckAABB(self); 84 | }; 85 | 86 | static CheckTriangle = function(triangle) { 87 | var p1 = self.position; 88 | var p2 = triangle.property_center; 89 | if (point_distance_3d(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z) > triangle.property_radius + self.property_radius) return false; 90 | 91 | var ab = triangle.property_edge_ab; 92 | var bc = triangle.property_edge_bc; 93 | var ca = triangle.property_edge_ca; 94 | 95 | static axes = [ 96 | 1, 0, 0, 97 | 0, 1, 0, 98 | 0, 0, 1, 99 | 0, 0, 0, 100 | 0, 0, 0, 101 | 0, 0, 0, 102 | 0, 0, 0, 103 | 0, 0, 0, 104 | 0, 0, 0, 105 | 0, 0, 0, 106 | 0, 0, 0, 107 | 0, 0, 0, 108 | 0, 0, 0 109 | ]; 110 | 111 | axes[3 * 3 + 0] = triangle.property_normal.x; 112 | axes[3 * 3 + 1] = triangle.property_normal.y; 113 | axes[3 * 3 + 2] = triangle.property_normal.z; 114 | axes[4 * 3 + 1] = -ab.z; 115 | axes[4 * 3 + 2] = ab.y; 116 | axes[5 * 3 + 1] = -bc.z; 117 | axes[5 * 3 + 2] = bc.y; 118 | axes[6 * 3 + 1] = -ca.z; 119 | axes[6 * 3 + 2] = ca.y; 120 | axes[7 * 3 + 0] = ab.z; 121 | axes[7 * 3 + 2] = -ab.x; 122 | axes[8 * 3 + 0] = bc.z; 123 | axes[8 * 3 + 2] = -bc.x; 124 | axes[9 * 3 + 0] = ca.z; 125 | axes[9 * 3 + 2] = -ca.x; 126 | axes[10 * 3 + 0] = -ab.y; 127 | axes[10 * 3 + 1] = ab.x; 128 | axes[11 * 3 + 0] = -bc.y; 129 | axes[11 * 3 + 1] = bc.x; 130 | axes[12 * 3 + 0] = -ca.y; 131 | axes[12 * 3 + 1] = ca.x; 132 | 133 | var vertices = self.property_vertices; 134 | var tax = triangle.a.x; 135 | var tay = triangle.a.y; 136 | var taz = triangle.a.z; 137 | var tbx = triangle.b.x; 138 | var tby = triangle.b.y; 139 | var tbz = triangle.b.z; 140 | var tcx = triangle.c.x; 141 | var tcy = triangle.c.y; 142 | var tcz = triangle.c.z; 143 | 144 | var i = 0; 145 | repeat (13) { 146 | var ax = axes[i++]; 147 | var ay = axes[i++]; 148 | var az = axes[i++]; 149 | 150 | var vertex = vertices[0]; 151 | var dot0 = dot_product_3d(ax, ay, az, vertex.x, vertex.y, vertex.z); 152 | vertex = vertices[1]; 153 | var dot1 = dot_product_3d(ax, ay, az, vertex.x, vertex.y, vertex.z); 154 | vertex = vertices[2]; 155 | var dot2 = dot_product_3d(ax, ay, az, vertex.x, vertex.y, vertex.z); 156 | vertex = vertices[3]; 157 | var dot3 = dot_product_3d(ax, ay, az, vertex.x, vertex.y, vertex.z); 158 | vertex = vertices[4]; 159 | var dot4 = dot_product_3d(ax, ay, az, vertex.x, vertex.y, vertex.z); 160 | vertex = vertices[5]; 161 | var dot5 = dot_product_3d(ax, ay, az, vertex.x, vertex.y, vertex.z); 162 | vertex = vertices[6]; 163 | var dot6 = dot_product_3d(ax, ay, az, vertex.x, vertex.y, vertex.z); 164 | vertex = vertices[7]; 165 | var dot7 = dot_product_3d(ax, ay, az, vertex.x, vertex.y, vertex.z); 166 | var val_min_a = min(dot0, dot1, dot2, dot3, dot4, dot5, dot6, dot7); 167 | var val_max_a = max(dot0, dot1, dot2, dot3, dot4, dot5, dot6, dot7); 168 | 169 | var ada = dot_product_3d(ax, ay, az, tax, tay, taz); 170 | var adb = dot_product_3d(ax, ay, az, tbx, tby, tbz); 171 | var adc = dot_product_3d(ax, ay, az, tcx, tcy, tcz); 172 | var val_min_b = min(ada, adb, adc); 173 | var val_max_b = max(ada, adb, adc); 174 | 175 | if ((val_min_b > val_max_a) || (val_min_a > val_max_b)) { 176 | return false; 177 | } 178 | } 179 | 180 | return true; 181 | }; 182 | 183 | static CheckMesh = function(mesh) { 184 | return mesh.CheckAABB(self); 185 | }; 186 | 187 | static CheckModel = function(model) { 188 | return model.CheckAABB(self); 189 | }; 190 | 191 | static CheckRay = function(ray, hit_info = undefined) { 192 | var box_min = self.property_min; 193 | var box_max = self.property_max; 194 | 195 | var dir = ray.direction; 196 | var p = ray.origin; 197 | 198 | var ray_x = (dir.x == 0) ? 0.0001 : dir.x; 199 | var ray_y = (dir.y == 0) ? 0.0001 : dir.y; 200 | var ray_z = (dir.z == 0) ? 0.0001 : dir.z; 201 | 202 | var t1 = (box_min.x - p.x) / ray_x; 203 | var t2 = (box_max.x - p.x) / ray_x; 204 | var t3 = (box_min.y - p.y) / ray_y; 205 | var t4 = (box_max.y - p.y) / ray_y; 206 | var t5 = (box_min.z - p.z) / ray_z; 207 | var t6 = (box_max.z - p.z) / ray_z; 208 | 209 | var tmin = max( 210 | min(t1, t2), 211 | min(t3, t4), 212 | min(t5, t6) 213 | ); 214 | var tmax = min( 215 | max(t1, t2), 216 | max(t3, t4), 217 | max(t5, t6) 218 | ); 219 | 220 | if (tmax < 0) return false; 221 | if (tmin > tmax) return false; 222 | 223 | if (hit_info) { 224 | var t = tmax; 225 | if (tmin > 0) { 226 | t = tmin; 227 | } 228 | 229 | var tnormal; 230 | if (t == t1) tnormal = new Vector3(-1, 0, 0); 231 | if (t == t2) tnormal = new Vector3(+1, 0, 0); 232 | if (t == t3) tnormal = new Vector3(0, -1, 0); 233 | if (t == t4) tnormal = new Vector3(0, +1, 0); 234 | if (t == t5) tnormal = new Vector3(0, 0, -1); 235 | if (t == t6) tnormal = new Vector3(0, 0, +1); 236 | 237 | hit_info.Update(t, self, p.Add(dir.Mul(t)), tnormal); 238 | } 239 | 240 | return true; 241 | }; 242 | 243 | static CheckLine = function(line) { 244 | static hit_info = new RaycastHitInformation(); 245 | hit_info.distance = infinity; 246 | 247 | if (self.CheckRay(line.property_ray, hit_info)) { 248 | return (hit_info.distance <= line.property_length); 249 | } 250 | return false; 251 | }; 252 | 253 | static DisplaceSphere = function(sphere) { 254 | if (!sphere.CheckAABB(self)) return undefined; 255 | var ps = sphere.position; 256 | var pa = self.position; 257 | if (ps.x == pa.x && ps.y == pa.y && ps.z == pa.z) return undefined; 258 | 259 | var nearest = self.NearestPoint(ps); 260 | 261 | if (ps.x == nearest.x && nearest.y == pa.y && nearest.z == pa.z) { 262 | return undefined; 263 | } 264 | 265 | var dir = ps.Sub(nearest).Normalize(); 266 | return nearest.Add(dir.Mul(sphere.radius)); 267 | }; 268 | 269 | static NearestPoint = function(vec3) { 270 | var box_min = self.property_min; 271 | var box_max = self.property_max; 272 | return new Vector3( 273 | clamp(vec3.x, box_min.x, box_max.x), 274 | clamp(vec3.y, box_min.y, box_max.y), 275 | clamp(vec3.z, box_min.z, box_max.z) 276 | ); 277 | }; 278 | 279 | static GetInterval = function(axis) { 280 | var vertices = self.property_vertices; 281 | var ax = axis.x; 282 | var ay = axis.y; 283 | var az = axis.z; 284 | 285 | var imin = infinity; 286 | var imax = -infinity; 287 | 288 | var i = 0; 289 | repeat (8) { 290 | var vertex = vertices[i++]; 291 | var dot = dot_product_3d(ax, ay, az, vertex.x, vertex.y, vertex.z); 292 | imin = min(imin, dot); 293 | imax = max(imax, dot); 294 | } 295 | 296 | return { val_min: imin, val_max: imax }; 297 | }; 298 | 299 | static GetVertices = function() { 300 | return array_map(self.property_vertices, function(item) { 301 | return item.Clone(); 302 | }); 303 | }; 304 | 305 | static GetEdges = function() { 306 | return array_map(self.property_edges, function(item) { 307 | return new ColLine(item.start, item.finish); 308 | }); 309 | }; 310 | 311 | static GetMin = function() { 312 | return self.property_min.Clone(); 313 | }; 314 | 315 | static GetMax = function() { 316 | return self.property_max.Clone(); 317 | }; 318 | 319 | static CheckFrustum = function(frustum) { 320 | var planes = frustum.as_array; 321 | var is_intersecting_anything = false; 322 | var r = self.property_radius; 323 | var p = self.position; 324 | var px = p.x, py = p.y, pz = p.z; 325 | var i = 0; 326 | repeat (6) { 327 | var plane = planes[i++]; 328 | var n = plane.normal; 329 | var dist = dot_product_3d(n.x, n.y, n.z, px, py, pz) + plane.distance; 330 | 331 | if (dist < -r) 332 | return EFrustumResults.OUTSIDE; 333 | 334 | if (abs(dist) < r) 335 | is_intersecting_anything = true; 336 | } 337 | return is_intersecting_anything ? EFrustumResults.INTERSECTING : EFrustumResults.INSIDE; 338 | }; 339 | 340 | static CheckFrustumFast = function() { 341 | var p = self.position; 342 | return sphere_is_visible(p.x, p.y, p.z, self.property_radius) ? EFrustumResults.INSIDE : EFrustumResults.OUTSIDE; 343 | }; 344 | } -------------------------------------------------------------------------------- /scripts/Col_Vector/Col_Vector.gml: -------------------------------------------------------------------------------- 1 | function Vector2(x, y = x) constructor { 2 | self.x = x; 3 | self.y = y; 4 | 5 | static Zero = function() { return new Vector2(0); }; 6 | static One = function() { return new Vector2(1); }; 7 | static Infinity = function() { return new Vector2(infinity); }; 8 | static NegativeInfinity = function() { return new Vector2(-infinity); }; 9 | 10 | static toString = function() { 11 | return string("({0}, {1})", self.x, self.y); 12 | }; 13 | 14 | static Set = function(x, y = x) { 15 | self.x = x; 16 | self.y = y; 17 | }; 18 | 19 | static Clone = function() { 20 | return new Vector2(self.x, self.y); 21 | }; 22 | 23 | static AsLinearArray = function() { 24 | return [self.x, self.y]; 25 | }; 26 | 27 | static Add = function(val) { 28 | if (is_numeric(val)) { 29 | return new Vector2(self.x + val, self.y + val); 30 | } 31 | return new Vector2(self.x + val.x, self.y + val.y); 32 | }; 33 | 34 | static Sub = function(val) { 35 | if (is_numeric(val)) { 36 | return new Vector2(self.x - val, self.y - val); 37 | } 38 | return new Vector2(self.x - val.x, self.y - val.y); 39 | }; 40 | 41 | static Mul = function(val) { 42 | if (is_numeric(val)) { 43 | return new Vector2(self.x * val, self.y * val); 44 | } 45 | return new Vector2(self.x * val.x, self.y * val.y); 46 | }; 47 | 48 | static Div = function(val) { 49 | if (is_numeric(val)) { 50 | return new Vector2(self.x / val, self.y / val); 51 | } 52 | return new Vector2(self.x / val.x, self.y / val.y); 53 | }; 54 | 55 | static Magnitude = function() { 56 | return point_distance(0, 0, self.x, self.y); 57 | }; 58 | 59 | static DistanceTo = function(val) { 60 | return point_distance(val.x, val.y, self.x, self.y); 61 | }; 62 | 63 | static Dot = function(val) { 64 | return dot_product(self.x, self.y, val.x, val.y); 65 | }; 66 | 67 | static Equals = function(val) { 68 | return (self.x == val.x) && (self.y == val.y); 69 | }; 70 | 71 | static Normalize = function() { 72 | var mag = point_distance(0, 0, self.x, self.y); 73 | return new Vector2(self.x / mag, self.y / mag); 74 | }; 75 | 76 | static Clamp = function(a, b) { 77 | if (is_struct(a) || is_struct(b)) { 78 | return new Vector2(clamp(self.x, a.x, b.x), clamp(self.y, a.y, b.y)); 79 | } 80 | return new Vector2(clamp(self.x, a, b), clamp(self.y, a, b)); 81 | }; 82 | 83 | static ClampMagnitude = function(magnitude) { 84 | var d = point_distance(0, 0, self.x, self.y) / magnitude; 85 | return new Vector2(self.x / d, self.y / d); 86 | }; 87 | 88 | static Abs = function() { 89 | return new Vector2(abs(self.x), abs(self.y)); 90 | }; 91 | 92 | static Frac = function() { 93 | return new Vector2(frac(self.x), frac(self.y)); 94 | }; 95 | 96 | static Project = function(direction) { 97 | var f = dot_product(self.x, self.y, direction.x, direction.y) / dot_product(direction.x, direction.y, direction.x, direction.y); 98 | return new Vector2(direction.x * f, direction.y * f); 99 | }; 100 | 101 | static Min = function(val) { 102 | if (is_numeric(val)) { 103 | return new Vector2(min(self.x, val), min(self.y, val)); 104 | } 105 | return new Vector2(min(self.x, val.x), min(self.y, val.y)); 106 | }; 107 | 108 | static Max = function(val) { 109 | if (is_numeric(val)) { 110 | return new Vector2(max(self.x, val), max(self.y, val)); 111 | } 112 | return new Vector2(max(self.x, val.x), max(self.y, val.y)); 113 | }; 114 | 115 | static Floor = function() { 116 | return new Vector2(floor(self.x), floor(self.y)); 117 | }; 118 | 119 | static Ceil = function() { 120 | return new Vector2(ceil(self.x), ceil(self.y)); 121 | }; 122 | 123 | static Round = function() { 124 | return new Vector2(round(self.x), round(self.y)); 125 | }; 126 | 127 | static Lerp = function(target, amount) { 128 | return new Vector2(lerp(self.x, target.x, amount), lerp(self.y, target.y, amount)); 129 | }; 130 | 131 | static Angle = function(vec2) { 132 | return darccos(dot_product(self.x, self.y, vec2.x, vec2.y) / (point_distance(0, 0, self.x, self.y) * point_distance(0, 0, vec2.x, vec2.y))); 133 | }; 134 | 135 | static Approach = function(target, amount) { 136 | var dist = max(point_distance(target.x, target.y, self.x, self.y) - amount, 0); 137 | var f = dist / amount; 138 | 139 | return new Vector2( 140 | lerp(self.x, target.x, f), 141 | lerp(self.y, target.y, f) 142 | ); 143 | }; 144 | } 145 | 146 | function Vector3(x, y = x, z = x) constructor { 147 | self.x = x; 148 | self.y = y; 149 | self.z = z; 150 | 151 | static Zero = function() { return new Vector3(0); }; 152 | static One = function() { return new Vector3(1); }; 153 | static Infinity = function() { return new Vector3(infinity); }; 154 | static NegativeInfinity = function() { return new Vector3(-infinity); }; 155 | 156 | static toString = function() { 157 | return string("({0}, {1}, {2})", self.x, self.y, self.z); 158 | }; 159 | 160 | static Set = function(x, y, z) { 161 | self.x = x; 162 | self.y = y; 163 | self.z = z; 164 | }; 165 | 166 | static Clone = function() { 167 | return new Vector3(self.x, self.y, self.z); 168 | }; 169 | 170 | static AsLinearArray = function() { 171 | return [self.x, self.y, self.z]; 172 | }; 173 | 174 | static Add = function(val) { 175 | if (is_numeric(val)) { 176 | return new Vector3(self.x + val, self.y + val, self.z + val); 177 | } 178 | return new Vector3(self.x + val.x, self.y + val.y, self.z + val.z); 179 | }; 180 | 181 | static Sub = function(val) { 182 | if (is_numeric(val)) { 183 | return new Vector3(self.x - val, self.y - val, self.z - val); 184 | } 185 | return new Vector3(self.x - val.x, self.y - val.y, self.z - val.z); 186 | }; 187 | 188 | static Mul = function(val) { 189 | if (is_numeric(val)) { 190 | return new Vector3(self.x * val, self.y * val, self.z * val); 191 | } 192 | return new Vector3(self.x * val.x, self.y * val.y, self.z * val.z); 193 | }; 194 | 195 | static Div = function(val) { 196 | if (is_numeric(val)) { 197 | return new Vector3(self.x / val, self.y / val, self.z / val); 198 | } 199 | return new Vector3(self.x / val.x, self.y / val.y, self.z / val.z); 200 | }; 201 | 202 | static Magnitude = function() { 203 | return point_distance_3d(0, 0, 0, self.x, self.y, self.z); 204 | }; 205 | 206 | static DistanceTo = function(val) { 207 | return point_distance_3d(val.x, val.y, val.z, self.x, self.y, self.z); 208 | }; 209 | 210 | static Dot = function(val) { 211 | return dot_product_3d(self.x, self.y, self.z, val.x, val.y, val.z); 212 | }; 213 | 214 | static Cross = function(val) { 215 | return new Vector3(self.y * val.z - val.y * self.z, self.z * val.x - val.z * self.x, self.x * val.y - val.x * self.y); 216 | }; 217 | 218 | static Equals = function(val) { 219 | return (self.x == val.x) && (self.y == val.y) && (self.z == val.z); 220 | }; 221 | 222 | static Normalize = function() { 223 | var mag = point_distance_3d(0, 0, 0, self.x, self.y, self.z); 224 | return new Vector3(self.x / mag, self.y / mag, self.z / mag); 225 | }; 226 | 227 | static Clamp = function(a, b) { 228 | if (is_struct(a) || is_struct(b)) { 229 | return new Vector3(clamp(self.x, a.x, b.x), clamp(self.y, a.y, b.y), clamp(self.z, a.z, b.z)); 230 | } 231 | return new Vector3(clamp(self.x, a, b), clamp(self.y, a, b), clamp(self.z, a, b)); 232 | }; 233 | 234 | static ClampMagnitude = function(magnitude) { 235 | var d = point_distance_3d(0, 0, 0, self.x, self.y, self.z) / magnitude; 236 | return new Vector3(self.x / d, self.y / d, self.z / d); 237 | }; 238 | 239 | static Abs = function() { 240 | return new Vector3(abs(self.x), abs(self.y), abs(self.z)); 241 | }; 242 | 243 | static Frac = function() { 244 | return new Vector3(abs(self.x), frac(self.y), frac(self.z)); 245 | }; 246 | 247 | static Project = function(direction) { 248 | var f = dot_product_3d(self.x, self.y, self.z, direction.x, direction.y, direction.z) / dot_product_3d(direction.x, direction.y, direction.z, direction.x, direction.y, direction.z); 249 | return new Vector3(direction.x * f, direction.y * f, direction.z * f); 250 | }; 251 | 252 | static Min = function(val) { 253 | if (is_numeric(val)) { 254 | return new Vector3(min(self.x, val), min(self.y, val), min(self.z, val)); 255 | } 256 | return new Vector3(min(self.x, val.x), min(self.y, val.y), min(self.z, val.z)); 257 | }; 258 | 259 | static Max = function(val) { 260 | if (is_numeric(val)) { 261 | return new Vector3(max(self.x, val), max(self.y, val), max(self.z, val)); 262 | } 263 | return new Vector3(max(self.x, val.x), max(self.y, val.y), max(self.z, val.z)); 264 | }; 265 | 266 | static Floor = function() { 267 | return new Vector3(floor(self.x), floor(self.y), floor(self.z)); 268 | }; 269 | 270 | static Ceil = function() { 271 | return new Vector3(ceil(self.x), ceil(self.y), ceil(self.z)); 272 | }; 273 | 274 | static Round = function() { 275 | return new Vector3(round(self.x), round(self.y), round(self.z)); 276 | }; 277 | 278 | static Lerp = function(target, amount) { 279 | return new Vector3(lerp(self.x, target.x, amount), lerp(self.y, target.y, amount), lerp(self.z, target.z, amount)); 280 | }; 281 | 282 | static Angle = function(vec3) { 283 | return darccos(dot_product_3d(self.x, self.y, self.z, vec3.x, vec3.y, vec3.z) / (point_distance_3d(0, 0, 0, self.x, self.y, self.z) * point_distance_3d(0, 0, 0, vec3.x, vec3.y, vec3.z))); 284 | }; 285 | 286 | static Approach = function(target, amount) { 287 | var dist = max(point_distance_3d(target.x, target.y, target.z, self.x, self.y, self.z) - amount, 0); 288 | var f = dist / amount; 289 | 290 | return new Vector3( 291 | lerp(self.x, target.x, f), 292 | lerp(self.y, target.y, f), 293 | lerp(self.z, target.z, f) 294 | ); 295 | }; 296 | } 297 | 298 | function Vector4(x, y = x, z = x, w = x) constructor { 299 | self.x = x; 300 | self.y = y; 301 | self.z = z; 302 | self.w = w; 303 | 304 | static Zero = function() { return new Vector4(0); }; 305 | static One = function() { return new Vector4(1); }; 306 | static Infinity = function() { return new Vector4(infinity); }; 307 | static NegativeInfinity = function() { return new Vector4(-infinity); }; 308 | 309 | static toString = function() { 310 | return string("({0}, {1}, {2}, {3})", self.x, self.y, self.z, self.w); 311 | }; 312 | 313 | static Set = function(x, y, z, w) { 314 | self.x = x; 315 | self.y = y; 316 | self.z = z; 317 | self.w = w; 318 | }; 319 | 320 | static Clone = function() { 321 | return new Vector4(self.x, self.y, self.z, self.w); 322 | }; 323 | 324 | static AsLinearArray = function() { 325 | return [self.x, self.y, self.z, self.w]; 326 | }; 327 | 328 | static Add = function(val) { 329 | if (is_numeric(val)) { 330 | return new Vector4(self.x + val, self.y + val, self.z + val, self.w + val); 331 | } 332 | return new Vector4(self.x + val.x, self.y + val.y, self.z + val.z, self.w + val.w); 333 | }; 334 | 335 | static Sub = function(val) { 336 | if (is_numeric(val)) { 337 | return new Vector4(self.x - val, self.y - val, self.z - val, self.w - val); 338 | } 339 | return new Vector4(self.x - val.x, self.y - val.y, self.z - val.z, self.w - val.w); 340 | }; 341 | 342 | static Mul = function(val) { 343 | if (is_numeric(val)) { 344 | return new Vector4(self.x * val, self.y * val, self.z * val, self.w * val); 345 | } 346 | return new Vector4(self.x * val.x, self.y * val.y, self.z * val.z, self.w * val.w); 347 | }; 348 | 349 | static Div = function(val) { 350 | if (is_numeric(val)) { 351 | return new Vector4(self.x / val, self.y / val, self.z / val, self.w / val); 352 | } 353 | return new Vector4(self.x / val.x, self.y / val.y, self.z / val.z, self.w / val.w); 354 | }; 355 | 356 | static Magnitude = function() { 357 | return sqrt(sqr(self.x) + sqr(self.y) + sqr(self.z) + sqr(self.w)); 358 | }; 359 | 360 | static DistanceTo = function(val) { 361 | return sqrt(sqr(self.x - val.x) + sqr(self.y - val.y) + sqrt(self.z - val.z) + sqr(self.w - val.w)); 362 | }; 363 | 364 | static Dot = function(val) { 365 | return dot_product_3d(self.x, self.y, self.z, val.x, val.y, val.z) + self.w * val.w; 366 | }; 367 | 368 | static Equals = function(val) { 369 | return (self.x == val.x) && (self.y == val.y) && (self.z == val.z) && (self.w == val.w); 370 | }; 371 | 372 | static Normalize = function() { 373 | var mag = sqrt(sqr(self.x) + sqr(self.y) + sqr(self.z) + sqr(self.w)); 374 | return new Vector4(self.x / mag, self.y / mag, self.z / mag, self.w / mag); 375 | }; 376 | 377 | static Clamp = function(a, b) { 378 | if (is_struct(a) || is_struct(b)) { 379 | return new Vector4(clamp(self.x, a.x, b.x), clamp(self.y, a.y, b.y), clamp(self.z, a.z, b.z), clamp(self.w, a.w, b.w)); 380 | } 381 | return new Vector4(clamp(self.x, a, b), clamp(self.y, a, b), clamp(self.z, a, b), clamp(self.w, a, b)); 382 | }; 383 | 384 | static ClampMagnitude = function(magnitude) { 385 | var d = sqrt(sqr(self.x) + sqr(self.y) + sqr(self.z) + sqr(self.w)) / magnitude; 386 | return new Vector4(self.x / d, self.y / d, self.z / d, self.w / d); 387 | }; 388 | 389 | static Abs = function() { 390 | return new Vector4(abs(self.x), abs(self.y), abs(self.z), abs(self.w)); 391 | }; 392 | 393 | static Frac = function() { 394 | return new Vector4(frac(self.x), frac(self.y), frac(self.z), frac(self.w)); 395 | }; 396 | 397 | static Project = function(direction) { 398 | var f = (dot_product_3d(self.x, self.y, self.z, direction.x, direction.y, direction.z) + self.w * direction.w) / (dot_product_3d(direction.x, direction.y, direction.z, direction.x, direction.y, direction.z) + direction.w * direction.w); 399 | return new Vector4(direction.x * f, direction.y * f, direction.z * f, direction.w * f); 400 | }; 401 | 402 | static Min = function(val) { 403 | if (is_numeric(val)) { 404 | return new Vector4(min(self.x, val), min(self.y, val), min(self.z, val), min(self.w, val)); 405 | } 406 | return new Vector4(min(self.x, val.x), min(self.y, val.y), min(self.z, val.z), min(self.w, val.w)); 407 | }; 408 | 409 | static Max = function(val) { 410 | if (is_numeric(val)) { 411 | return new Vector4(max(self.x, val), max(self.y, val), max(self.z, val), max(self.w, val)); 412 | } 413 | return new Vector4(max(self.x, val.x), max(self.y, val.y), max(self.z, val.z), max(self.w, val.w)); 414 | }; 415 | 416 | static Floor = function() { 417 | return new Vector4(floor(self.x), floor(self.y), floor(self.z), floor(self.w)); 418 | }; 419 | 420 | static Ceil = function() { 421 | return new Vector4(ceil(self.x), ceil(self.y), ceil(self.z), ceil(self.w)); 422 | }; 423 | 424 | static Round = function() { 425 | return new Vector4(round(self.x), round(self.y), round(self.z), round(self.w)); 426 | }; 427 | 428 | static Lerp = function(target, amount) { 429 | return new Vector4(lerp(self.x, target.x, amount), lerp(self.y, target.y, amount), lerp(self.z, target.z, amount), lerp(self.w, target.w, amount)); 430 | }; 431 | 432 | static Angle = function(vec4) { 433 | return darccos((dot_product_3d(self.x, self.y, self.z, vec4.x, vec4.y, vec4.z) + self.w * vec4.w) / (sqrt(sqr(self.x) + sqr(self.y) + sqr(self.z) + sqr(self.w)) * sqrt(sqr(vec4.x) + sqr(vec4.y) + sqr(vec4.z) + sqr(vec4.w)))); 434 | }; 435 | 436 | static Approach = function(target, amount) { 437 | var dist = max(sqrt(sqr(self.x - target.x) + sqr(self.y - target.y) + sqrt(self.z - target.z) + sqr(self.w - target.w)) - amount, 0); 438 | var f = dist / amount; 439 | 440 | return new Vector4( 441 | lerp(self.x, target.x, f), 442 | lerp(self.y, target.y, f), 443 | lerp(self.z, target.z, f), 444 | lerp(self.w, target.w, f) 445 | ); 446 | }; 447 | } 448 | 449 | new Vector2(0); 450 | new Vector3(0); 451 | new Vector4(0); -------------------------------------------------------------------------------- /fonts/fnt_demo/fnt_demo.yy: -------------------------------------------------------------------------------- 1 | { 2 | "$GMFont":"", 3 | "%Name":"fnt_demo", 4 | "AntiAlias":1, 5 | "applyKerning":0, 6 | "ascender":0, 7 | "ascenderOffset":0, 8 | "bold":true, 9 | "canGenerateBitmap":true, 10 | "charset":0, 11 | "first":0, 12 | "fontName":"Calibri", 13 | "glyphOperations":0, 14 | "glyphs":{ 15 | "32":{"character":32,"h":26,"offset":0,"shift":5,"w":5,"x":2,"y":2,}, 16 | "33":{"character":33,"h":26,"offset":2,"shift":7,"w":4,"x":36,"y":86,}, 17 | "34":{"character":34,"h":26,"offset":1,"shift":9,"w":7,"x":27,"y":86,}, 18 | "35":{"character":35,"h":26,"offset":0,"shift":10,"w":11,"x":14,"y":86,}, 19 | "36":{"character":36,"h":26,"offset":0,"shift":11,"w":10,"x":2,"y":86,}, 20 | "37":{"character":37,"h":26,"offset":0,"shift":15,"w":15,"x":231,"y":58,}, 21 | "38":{"character":38,"h":26,"offset":0,"shift":15,"w":15,"x":214,"y":58,}, 22 | "39":{"character":39,"h":26,"offset":1,"shift":5,"w":3,"x":209,"y":58,}, 23 | "40":{"character":40,"h":26,"offset":1,"shift":7,"w":5,"x":202,"y":58,}, 24 | "41":{"character":41,"h":26,"offset":1,"shift":7,"w":5,"x":195,"y":58,}, 25 | "42":{"character":42,"h":26,"offset":1,"shift":10,"w":9,"x":42,"y":86,}, 26 | "43":{"character":43,"h":26,"offset":0,"shift":10,"w":10,"x":183,"y":58,}, 27 | "44":{"character":44,"h":26,"offset":0,"shift":5,"w":5,"x":164,"y":58,}, 28 | "45":{"character":45,"h":26,"offset":0,"shift":6,"w":6,"x":156,"y":58,}, 29 | "46":{"character":46,"h":26,"offset":1,"shift":6,"w":4,"x":150,"y":58,}, 30 | "47":{"character":47,"h":26,"offset":0,"shift":9,"w":9,"x":139,"y":58,}, 31 | "48":{"character":48,"h":26,"offset":0,"shift":11,"w":11,"x":126,"y":58,}, 32 | "49":{"character":49,"h":26,"offset":1,"shift":11,"w":9,"x":115,"y":58,}, 33 | "50":{"character":50,"h":26,"offset":0,"shift":11,"w":10,"x":103,"y":58,}, 34 | "51":{"character":51,"h":26,"offset":0,"shift":11,"w":10,"x":91,"y":58,}, 35 | "52":{"character":52,"h":26,"offset":0,"shift":11,"w":11,"x":78,"y":58,}, 36 | "53":{"character":53,"h":26,"offset":0,"shift":11,"w":10,"x":171,"y":58,}, 37 | "54":{"character":54,"h":26,"offset":0,"shift":11,"w":11,"x":53,"y":86,}, 38 | "55":{"character":55,"h":26,"offset":0,"shift":11,"w":10,"x":66,"y":86,}, 39 | "56":{"character":56,"h":26,"offset":0,"shift":11,"w":11,"x":78,"y":86,}, 40 | "57":{"character":57,"h":26,"offset":0,"shift":11,"w":10,"x":80,"y":114,}, 41 | "58":{"character":58,"h":26,"offset":1,"shift":6,"w":4,"x":74,"y":114,}, 42 | "59":{"character":59,"h":26,"offset":0,"shift":6,"w":5,"x":67,"y":114,}, 43 | "60":{"character":60,"h":26,"offset":0,"shift":10,"w":10,"x":55,"y":114,}, 44 | "61":{"character":61,"h":26,"offset":0,"shift":10,"w":10,"x":43,"y":114,}, 45 | "62":{"character":62,"h":26,"offset":1,"shift":10,"w":9,"x":32,"y":114,}, 46 | "63":{"character":63,"h":26,"offset":1,"shift":10,"w":8,"x":22,"y":114,}, 47 | "64":{"character":64,"h":26,"offset":0,"shift":19,"w":18,"x":2,"y":114,}, 48 | "65":{"character":65,"h":26,"offset":0,"shift":13,"w":13,"x":235,"y":86,}, 49 | "66":{"character":66,"h":26,"offset":1,"shift":12,"w":11,"x":222,"y":86,}, 50 | "67":{"character":67,"h":26,"offset":0,"shift":11,"w":11,"x":209,"y":86,}, 51 | "68":{"character":68,"h":26,"offset":1,"shift":13,"w":12,"x":195,"y":86,}, 52 | "69":{"character":69,"h":26,"offset":1,"shift":10,"w":9,"x":184,"y":86,}, 53 | "70":{"character":70,"h":26,"offset":1,"shift":10,"w":8,"x":174,"y":86,}, 54 | "71":{"character":71,"h":26,"offset":0,"shift":13,"w":13,"x":159,"y":86,}, 55 | "72":{"character":72,"h":26,"offset":1,"shift":13,"w":11,"x":146,"y":86,}, 56 | "73":{"character":73,"h":26,"offset":1,"shift":6,"w":4,"x":140,"y":86,}, 57 | "74":{"character":74,"h":26,"offset":0,"shift":7,"w":6,"x":132,"y":86,}, 58 | "75":{"character":75,"h":26,"offset":1,"shift":11,"w":11,"x":119,"y":86,}, 59 | "76":{"character":76,"h":26,"offset":1,"shift":9,"w":8,"x":109,"y":86,}, 60 | "77":{"character":77,"h":26,"offset":1,"shift":18,"w":16,"x":91,"y":86,}, 61 | "78":{"character":78,"h":26,"offset":1,"shift":14,"w":12,"x":64,"y":58,}, 62 | "79":{"character":79,"h":26,"offset":0,"shift":14,"w":14,"x":48,"y":58,}, 63 | "80":{"character":80,"h":26,"offset":1,"shift":11,"w":10,"x":36,"y":58,}, 64 | "81":{"character":81,"h":26,"offset":0,"shift":14,"w":15,"x":22,"y":30,}, 65 | "82":{"character":82,"h":26,"offset":1,"shift":12,"w":11,"x":2,"y":30,}, 66 | "83":{"character":83,"h":26,"offset":0,"shift":10,"w":10,"x":233,"y":2,}, 67 | "84":{"character":84,"h":26,"offset":0,"shift":10,"w":11,"x":220,"y":2,}, 68 | "85":{"character":85,"h":26,"offset":1,"shift":14,"w":12,"x":206,"y":2,}, 69 | "86":{"character":86,"h":26,"offset":0,"shift":12,"w":13,"x":191,"y":2,}, 70 | "87":{"character":87,"h":26,"offset":0,"shift":19,"w":19,"x":170,"y":2,}, 71 | "88":{"character":88,"h":26,"offset":0,"shift":12,"w":12,"x":156,"y":2,}, 72 | "89":{"character":89,"h":26,"offset":0,"shift":11,"w":11,"x":143,"y":2,}, 73 | "90":{"character":90,"h":26,"offset":0,"shift":10,"w":10,"x":131,"y":2,}, 74 | "91":{"character":91,"h":26,"offset":1,"shift":7,"w":5,"x":15,"y":30,}, 75 | "92":{"character":92,"h":26,"offset":0,"shift":9,"w":9,"x":120,"y":2,}, 76 | "93":{"character":93,"h":26,"offset":0,"shift":7,"w":6,"x":103,"y":2,}, 77 | "94":{"character":94,"h":26,"offset":0,"shift":10,"w":11,"x":90,"y":2,}, 78 | "95":{"character":95,"h":26,"offset":-1,"shift":10,"w":12,"x":76,"y":2,}, 79 | "96":{"character":96,"h":26,"offset":0,"shift":6,"w":6,"x":68,"y":2,}, 80 | "97":{"character":97,"h":26,"offset":0,"shift":10,"w":10,"x":56,"y":2,}, 81 | "98":{"character":98,"h":26,"offset":1,"shift":11,"w":10,"x":44,"y":2,}, 82 | "99":{"character":99,"h":26,"offset":0,"shift":9,"w":9,"x":33,"y":2,}, 83 | "100":{"character":100,"h":26,"offset":0,"shift":11,"w":10,"x":21,"y":2,}, 84 | "101":{"character":101,"h":26,"offset":0,"shift":11,"w":10,"x":9,"y":2,}, 85 | "102":{"character":102,"h":26,"offset":0,"shift":7,"w":7,"x":111,"y":2,}, 86 | "103":{"character":103,"h":26,"offset":0,"shift":10,"w":10,"x":39,"y":30,}, 87 | "104":{"character":104,"h":26,"offset":1,"shift":11,"w":10,"x":156,"y":30,}, 88 | "105":{"character":105,"h":26,"offset":1,"shift":5,"w":4,"x":51,"y":30,}, 89 | "106":{"character":106,"h":26,"offset":-1,"shift":5,"w":6,"x":18,"y":58,}, 90 | "107":{"character":107,"h":26,"offset":1,"shift":10,"w":9,"x":7,"y":58,}, 91 | "108":{"character":108,"h":26,"offset":1,"shift":5,"w":3,"x":2,"y":58,}, 92 | "109":{"character":109,"h":26,"offset":1,"shift":17,"w":15,"x":235,"y":30,}, 93 | "110":{"character":110,"h":26,"offset":1,"shift":11,"w":10,"x":223,"y":30,}, 94 | "111":{"character":111,"h":26,"offset":0,"shift":11,"w":11,"x":210,"y":30,}, 95 | "112":{"character":112,"h":26,"offset":1,"shift":11,"w":10,"x":198,"y":30,}, 96 | "113":{"character":113,"h":26,"offset":0,"shift":11,"w":10,"x":186,"y":30,}, 97 | "114":{"character":114,"h":26,"offset":1,"shift":7,"w":7,"x":177,"y":30,}, 98 | "115":{"character":115,"h":26,"offset":0,"shift":8,"w":8,"x":26,"y":58,}, 99 | "116":{"character":116,"h":26,"offset":0,"shift":7,"w":7,"x":168,"y":30,}, 100 | "117":{"character":117,"h":26,"offset":1,"shift":11,"w":9,"x":145,"y":30,}, 101 | "118":{"character":118,"h":26,"offset":0,"shift":10,"w":10,"x":133,"y":30,}, 102 | "119":{"character":119,"h":26,"offset":0,"shift":16,"w":16,"x":115,"y":30,}, 103 | "120":{"character":120,"h":26,"offset":0,"shift":10,"w":10,"x":103,"y":30,}, 104 | "121":{"character":121,"h":26,"offset":0,"shift":10,"w":10,"x":91,"y":30,}, 105 | "122":{"character":122,"h":26,"offset":0,"shift":8,"w":8,"x":81,"y":30,}, 106 | "123":{"character":123,"h":26,"offset":0,"shift":7,"w":7,"x":72,"y":30,}, 107 | "124":{"character":124,"h":26,"offset":3,"shift":10,"w":4,"x":66,"y":30,}, 108 | "125":{"character":125,"h":26,"offset":1,"shift":7,"w":7,"x":57,"y":30,}, 109 | "126":{"character":126,"h":26,"offset":0,"shift":10,"w":10,"x":92,"y":114,}, 110 | "9647":{"character":9647,"h":26,"offset":4,"shift":20,"w":13,"x":104,"y":114,}, 111 | }, 112 | "hinting":0, 113 | "includeTTF":false, 114 | "interpreter":0, 115 | "italic":false, 116 | "kerningPairs":[ 117 | {"amount":-1,"first":65,"second":63,}, 118 | {"amount":-1,"first":65,"second":84,}, 119 | {"amount":-1,"first":65,"second":86,}, 120 | {"amount":-1,"first":65,"second":87,}, 121 | {"amount":-1,"first":65,"second":89,}, 122 | {"amount":-1,"first":65,"second":116,}, 123 | {"amount":-1,"first":65,"second":121,}, 124 | {"amount":-1,"first":65,"second":221,}, 125 | {"amount":-1,"first":65,"second":253,}, 126 | {"amount":-1,"first":65,"second":255,}, 127 | {"amount":-1,"first":65,"second":356,}, 128 | {"amount":-1,"first":65,"second":357,}, 129 | {"amount":-1,"first":65,"second":372,}, 130 | {"amount":-1,"first":65,"second":374,}, 131 | {"amount":-1,"first":65,"second":375,}, 132 | {"amount":-1,"first":65,"second":376,}, 133 | {"amount":-1,"first":65,"second":538,}, 134 | {"amount":-1,"first":65,"second":539,}, 135 | {"amount":-1,"first":65,"second":7808,}, 136 | {"amount":-1,"first":65,"second":7810,}, 137 | {"amount":-1,"first":65,"second":7812,}, 138 | {"amount":-1,"first":65,"second":7922,}, 139 | {"amount":-1,"first":65,"second":7923,}, 140 | {"amount":-1,"first":65,"second":7924,}, 141 | {"amount":-1,"first":65,"second":7925,}, 142 | {"amount":-1,"first":65,"second":7926,}, 143 | {"amount":-1,"first":65,"second":7927,}, 144 | {"amount":-1,"first":65,"second":7928,}, 145 | {"amount":-1,"first":65,"second":7929,}, 146 | {"amount":-1,"first":65,"second":8216,}, 147 | {"amount":-1,"first":65,"second":8217,}, 148 | {"amount":-1,"first":65,"second":8220,}, 149 | {"amount":-1,"first":65,"second":8221,}, 150 | {"amount":-1,"first":66,"second":89,}, 151 | {"amount":-1,"first":66,"second":221,}, 152 | {"amount":-1,"first":66,"second":374,}, 153 | {"amount":-1,"first":66,"second":376,}, 154 | {"amount":-1,"first":66,"second":7922,}, 155 | {"amount":-1,"first":66,"second":7924,}, 156 | {"amount":-1,"first":66,"second":7926,}, 157 | {"amount":-1,"first":66,"second":7928,}, 158 | {"amount":1,"first":67,"second":8217,}, 159 | {"amount":1,"first":67,"second":8221,}, 160 | {"amount":-2,"first":70,"second":44,}, 161 | {"amount":-1,"first":70,"second":46,}, 162 | {"amount":-1,"first":70,"second":65,}, 163 | {"amount":-1,"first":70,"second":74,}, 164 | {"amount":-1,"first":70,"second":192,}, 165 | {"amount":-1,"first":70,"second":193,}, 166 | {"amount":-1,"first":70,"second":194,}, 167 | {"amount":-1,"first":70,"second":195,}, 168 | {"amount":-1,"first":70,"second":196,}, 169 | {"amount":-1,"first":70,"second":197,}, 170 | {"amount":-1,"first":70,"second":198,}, 171 | {"amount":-1,"first":70,"second":256,}, 172 | {"amount":-1,"first":70,"second":258,}, 173 | {"amount":-1,"first":70,"second":260,}, 174 | {"amount":1,"first":70,"second":297,}, 175 | {"amount":-1,"first":70,"second":308,}, 176 | {"amount":-1,"first":70,"second":506,}, 177 | {"amount":-1,"first":70,"second":7840,}, 178 | {"amount":-1,"first":70,"second":7842,}, 179 | {"amount":-1,"first":70,"second":7844,}, 180 | {"amount":-1,"first":70,"second":7846,}, 181 | {"amount":-1,"first":70,"second":7848,}, 182 | {"amount":-1,"first":70,"second":7850,}, 183 | {"amount":-1,"first":70,"second":7852,}, 184 | {"amount":-1,"first":70,"second":7854,}, 185 | {"amount":-1,"first":70,"second":7856,}, 186 | {"amount":-1,"first":70,"second":7858,}, 187 | {"amount":-1,"first":70,"second":7860,}, 188 | {"amount":-1,"first":70,"second":7862,}, 189 | {"amount":-1,"first":75,"second":67,}, 190 | {"amount":-1,"first":75,"second":71,}, 191 | {"amount":-1,"first":75,"second":79,}, 192 | {"amount":-1,"first":75,"second":81,}, 193 | {"amount":-1,"first":75,"second":118,}, 194 | {"amount":-1,"first":75,"second":119,}, 195 | {"amount":-1,"first":75,"second":121,}, 196 | {"amount":-1,"first":75,"second":199,}, 197 | {"amount":-1,"first":75,"second":210,}, 198 | {"amount":-1,"first":75,"second":211,}, 199 | {"amount":-1,"first":75,"second":212,}, 200 | {"amount":-1,"first":75,"second":213,}, 201 | {"amount":-1,"first":75,"second":214,}, 202 | {"amount":-1,"first":75,"second":253,}, 203 | {"amount":-1,"first":75,"second":255,}, 204 | {"amount":-1,"first":75,"second":262,}, 205 | {"amount":-1,"first":75,"second":264,}, 206 | {"amount":-1,"first":75,"second":266,}, 207 | {"amount":-1,"first":75,"second":268,}, 208 | {"amount":-1,"first":75,"second":284,}, 209 | {"amount":-1,"first":75,"second":286,}, 210 | {"amount":-1,"first":75,"second":288,}, 211 | {"amount":-1,"first":75,"second":290,}, 212 | {"amount":1,"first":75,"second":297,}, 213 | {"amount":-1,"first":75,"second":332,}, 214 | {"amount":-1,"first":75,"second":334,}, 215 | {"amount":-1,"first":75,"second":336,}, 216 | {"amount":-1,"first":75,"second":338,}, 217 | {"amount":-1,"first":75,"second":373,}, 218 | {"amount":-1,"first":75,"second":375,}, 219 | {"amount":-1,"first":75,"second":416,}, 220 | {"amount":-1,"first":75,"second":7809,}, 221 | {"amount":-1,"first":75,"second":7811,}, 222 | {"amount":-1,"first":75,"second":7813,}, 223 | {"amount":-1,"first":75,"second":7884,}, 224 | {"amount":-1,"first":75,"second":7886,}, 225 | {"amount":-1,"first":75,"second":7888,}, 226 | {"amount":-1,"first":75,"second":7890,}, 227 | {"amount":-1,"first":75,"second":7892,}, 228 | {"amount":-1,"first":75,"second":7894,}, 229 | {"amount":-1,"first":75,"second":7896,}, 230 | {"amount":-1,"first":75,"second":7898,}, 231 | {"amount":-1,"first":75,"second":7900,}, 232 | {"amount":-1,"first":75,"second":7902,}, 233 | {"amount":-1,"first":75,"second":7904,}, 234 | {"amount":-1,"first":75,"second":7906,}, 235 | {"amount":-1,"first":75,"second":7923,}, 236 | {"amount":-1,"first":75,"second":7925,}, 237 | {"amount":-1,"first":75,"second":7927,}, 238 | {"amount":-1,"first":75,"second":7929,}, 239 | {"amount":-1,"first":76,"second":84,}, 240 | {"amount":-1,"first":76,"second":86,}, 241 | {"amount":-1,"first":76,"second":87,}, 242 | {"amount":-2,"first":76,"second":89,}, 243 | {"amount":-1,"first":76,"second":118,}, 244 | {"amount":-1,"first":76,"second":119,}, 245 | {"amount":-1,"first":76,"second":121,}, 246 | {"amount":-1,"first":76,"second":183,}, 247 | {"amount":-2,"first":76,"second":221,}, 248 | {"amount":-1,"first":76,"second":253,}, 249 | {"amount":-1,"first":76,"second":255,}, 250 | {"amount":-1,"first":76,"second":356,}, 251 | {"amount":-1,"first":76,"second":372,}, 252 | {"amount":-1,"first":76,"second":373,}, 253 | {"amount":-2,"first":76,"second":374,}, 254 | {"amount":-1,"first":76,"second":375,}, 255 | {"amount":-2,"first":76,"second":376,}, 256 | {"amount":-1,"first":76,"second":538,}, 257 | {"amount":-1,"first":76,"second":7808,}, 258 | {"amount":-1,"first":76,"second":7809,}, 259 | {"amount":-1,"first":76,"second":7810,}, 260 | {"amount":-1,"first":76,"second":7811,}, 261 | {"amount":-1,"first":76,"second":7812,}, 262 | {"amount":-1,"first":76,"second":7813,}, 263 | {"amount":-2,"first":76,"second":7922,}, 264 | {"amount":-1,"first":76,"second":7923,}, 265 | {"amount":-2,"first":76,"second":7924,}, 266 | {"amount":-1,"first":76,"second":7925,}, 267 | {"amount":-2,"first":76,"second":7926,}, 268 | {"amount":-1,"first":76,"second":7927,}, 269 | {"amount":-2,"first":76,"second":7928,}, 270 | {"amount":-1,"first":76,"second":7929,}, 271 | {"amount":-2,"first":76,"second":8216,}, 272 | {"amount":-1,"first":76,"second":8217,}, 273 | {"amount":-2,"first":76,"second":8220,}, 274 | {"amount":-1,"first":76,"second":8221,}, 275 | {"amount":-1,"first":76,"second":8729,}, 276 | {"amount":-1,"first":79,"second":88,}, 277 | {"amount":-1,"first":79,"second":89,}, 278 | {"amount":-1,"first":79,"second":221,}, 279 | {"amount":-1,"first":79,"second":374,}, 280 | {"amount":-1,"first":79,"second":376,}, 281 | {"amount":-1,"first":79,"second":7922,}, 282 | {"amount":-1,"first":79,"second":7924,}, 283 | {"amount":-1,"first":79,"second":7926,}, 284 | {"amount":-1,"first":79,"second":7928,}, 285 | ], 286 | "last":0, 287 | "lineHeight":0, 288 | "maintainGms1Font":false, 289 | "name":"fnt_demo", 290 | "parent":{ 291 | "name":"Test stuff", 292 | "path":"folders/Test stuff.yy", 293 | }, 294 | "pointRounding":0, 295 | "ranges":[ 296 | {"lower":32,"upper":127,}, 297 | {"lower":9647,"upper":9647,}, 298 | ], 299 | "regenerateBitmap":false, 300 | "resourceType":"GMFont", 301 | "resourceVersion":"2.0", 302 | "sampleText":"abcdef ABCDEF\n0123456789 .,<>\"'&!?\nthe quick brown fox jumps over the lazy dog\nTHE QUICK BROWN FOX JUMPS OVER THE LAZY DOG\nDefault character: ▯ (9647)", 303 | "sdfSpread":8, 304 | "size":16.0, 305 | "styleName":"Bold", 306 | "textureGroupId":{ 307 | "name":"Default", 308 | "path":"texturegroups/Default", 309 | }, 310 | "TTFName":"", 311 | "usesSDF":false, 312 | } --------------------------------------------------------------------------------