{"id":408,"date":"2025-07-08T16:46:03","date_gmt":"2025-07-08T06:46:03","guid":{"rendered":"https:\/\/nonlinearexperience.com\/?p=408"},"modified":"2025-07-19T10:51:35","modified_gmt":"2025-07-19T00:51:35","slug":"collision-detection","status":"publish","type":"post","link":"https:\/\/nonlinearexperience.com\/index.php\/2025\/07\/08\/collision-detection\/","title":{"rendered":"Collision detection"},"content":{"rendered":"<h1 class=\"wp-block-post-title\">Collision detection<\/h1>\n\n\n<p>See also:<\/p>\n\n\n\n<p>System:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Concepts<\/h2>\n\n\n\n<p>hitboxes<\/p>\n\n\n\n<p>separating axis theorem\u2026<\/p>\n\n\n\n<p>most of the time you can use rectangle\/rectangle collisions\u2026<\/p>\n\n\n\n<p>Tile based collision is the simplest &#8211; uses a very broad phase approach &#8211; just need to know where we are in the tile array &#8211; lots less info to search\u2026<\/p>\n\n\n\n<p>Inverse collision detection<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Assumes we collide with everything EXCEPT floor &#8211; so check only for floor and if its anything else, its a collision<\/li>\n\n\n\n<li>But what about pickup items etc?<\/li>\n<\/ul>\n\n\n\n<p>Broad phase and narrow phase<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Collision reactions<\/h3>\n\n\n\n<p>What happens when you collide? is there an element of just STOPPING &#8211; or do you slightly overshoot, then bounce back (such as in porklike)?<\/p>\n\n\n\n<p>collision on pickup items &#8211; e.g. what is the &#8216;collision reaction&#8217; depending on proprty<\/p>\n\n\n\n<p>what about jump down as a collision reaction<\/p>\n\n\n\n<p>Properties<\/p>\n\n\n\n<p>which side did we collide with?<\/p>\n\n\n\n<p>which sides react &#8211; top, bottom, left, right<\/p>\n\n\n\n<p>what is the reaction &#8211; trigger &#8211; text, bounce back, damage, push, animation of<\/p>\n\n\n\n<p>ALTTP<\/p>\n\n\n\n<p>Things on a 45 degree angle &#8211;&nbsp;<\/p>\n\n\n\n<p>Character is moving right (green arrow) &#8211; and will move both right and up in the following instance:<br><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Point collision<\/h2>\n\n\n\n<p>Is the mouse touching the item?<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>define sprites bounds (rectangular): left, right, top, bottom (add this as properties for each sprite)<\/li>\n\n\n\n<li>define point of mouse<\/li>\n\n\n\n<li>run the test: pointX &gt; sprite.left() &amp;&amp; pointX &lt; sprite.right() &amp;&amp; pointY &gt; sprite.top() &amp;&amp; pointY &lt; sprite.bottom();<\/li>\n\n\n\n<li>do what needs to be done &#8211; set a var, move the item, change a property etc. etc.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Circle Circle collision<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>get distance between circles &#8211; (vector &gt; magnitude = Math.sqrt(vx * vx + vy * vy)<\/li>\n\n\n\n<li>get radii &#8211; totalRadii = (c1.width \/ 2) + (c2.width \/ 2)<\/li>\n\n\n\n<li>if distance (magnitude) is less than combination half of each ones radius (totalRadii) &#8211; they are colliding<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Preventing circles overlapping<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>When the circles collide, find out by how much they\u2019re overlapping (overlap = totalRadii\u2013 magnitude)<\/li>\n\n\n\n<li>Push the circles apart by the amount of overlap.&nbsp;<\/li>\n<\/ul>\n\n\n\n<p>(\/\/Normalize the vector. \/\/These numbers tell us the direction of the collision dx = vx \/ magnitude; dy = vy \/ magnitude; \/\/Move circle 1 out of the collision by multiplying \/\/the overlap with the normalized vector and add it to circle 1&#8217;s position c1.x += overlap * dx; c1.y += overlap * dy;)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Rectangle collisions<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Find out how far apart the rectangles are. Use a vector between the rectangles\u2019 center points to figure this out, just as you did with circles.<\/li>\n\n\n\n<li>Check to see if the distance between the rectangles is less than their combined half-widths. If it is, a collision might be occurring on the X axis. But you don\u2019t know this yet. You also have to check the Y axis.<\/li>\n\n\n\n<li>Check to see if the distance between the rectangles on the Y axis is less than their combined halfheights. If it is, then you know that a collision is definitely happening.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">AABB Collision Detection<\/h2>\n\n\n\n<p>AABB Collision Detection relies on all colliding entities to have \u201caxis-aligned bounding boxes\u201d, which simply means their collision boxes contain no rotation in our world space, which allows us to use a simple math formula to test for collision:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\nif rect1.x is not &gt; rect2.x + rect2.width and\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0rect1.x + rect1.width is not &lt; rect2.x and\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0rect1.y is not &gt; rect2.y + rect2.height and\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0rect1.y + rect1.height is not &lt; rect2.y:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0collision is true\nelse\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0collision is false\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Essentially, the formula is merely checking if the two boxes are colliding in any way.<\/p>\n\n\n\n<p>We can use AABB Collision Detection to detect whether our Ball is colliding with our Paddles and react accordingly.<\/p>\n\n\n\n<p>We can apply similar logic to detect if the Ball collides with a window boundary.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">TESTING FOR EDGES<\/h2>\n\n\n\n<p>oh, is that what this next thing is?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">DIRECTIONAL COLLISIONS<\/h2>\n\n\n\n<p><a href=\"https:\/\/www.youtube.com\/watch?v=r-Y-N4cLd10\">Advanced Tile Based Collision Detection AND Response in Javascript<\/a><\/p>\n\n\n\n<p>Tile collision types<\/p>\n\n\n\n<p>5 &#8211; top &#8211; can be used for platforms that can be jumped through\u2026<\/p>\n\n\n\n<p>4 &#8211; top, left, right<\/p>\n\n\n\n<p>3 &#8211; right<\/p>\n\n\n\n<p>2 &#8211; left<\/p>\n\n\n\n<p>1 &#8211;&nbsp;<\/p>\n\n\n\n<p>Only check collision from the designated side &#8211; e.g. if its checking left, then ignore coming from the right etc.<\/p>\n\n\n\n<p>See also: <a href=\"https:\/\/docs.google.com\/document\/d\/1AG3jOFts8Txf6aYTNznSe3lBOa0GsQ8yWp8YigJkfGc\/edit#heading=h.uyi7l8dkf3us\">Collision Blocks<\/a><\/p>\n\n\n\n<p>We DON&#8217;T want to set this up manually &#8211; use &#8217;tiled&#8217; &#8211; See also: <a href=\"https:\/\/docs.google.com\/document\/d\/1AG3jOFts8Txf6aYTNznSe3lBOa0GsQ8yWp8YigJkfGc\/edit#heading=h.q2cwztccjud0\">TILED IMAGES<\/a><\/p>\n\n\n\n<p>Phaser has:<\/p>\n\n\n\n<p>collideDown: boolean<\/p>\n\n\n\n<p>collideLeft: boolean<\/p>\n\n\n\n<p>collideRight: boolean<\/p>\n\n\n\n<p>collideUp: boolean<\/p>\n\n\n\n<p>See: https:\/\/newdocs.phaser.io\/docs\/3.60.0\/Phaser.Tilemaps.Tile#collideLeft<\/p>\n\n\n\n<p>Create custom tile set for collisions in tiled &#8211; it describes the above cardinal directions, which can then be extrapolated into a directional collision map in phaser.<\/p>\n\n\n\n<p>IS THIS THE BEST APPROACH?<\/p>\n\n\n\n<p>4 direction collision set<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXd2k2pUajtWxADUSlFkjUAWMbvryZuu-RLBIwegTZN9IluMdtaFYA_u6xaKcwUIjpLLpH27qVHIb-jGTI7L0lyl5NHeek7D9CaO3q3MhH3FB_sTO8oWPj7N_Tyjnljye9qDXoUegg40GdfWhw4J-P14d_5P?key=qInBJpW04kC1Sm63MHgkfg\" alt=\"\"\/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXeICx81XhdAtX2azt4zSIVsOW6e9QqU_TFzwfPMf4qW3VFcv01Z9KcYtCWjXrlpbGUktnDfMzuzhzn6DjS8zGm6Wca6zvDIHZCgqxDxTEK1ssnJBZd6kUAd_1hIvc-b1M5QYldKgxy8h6gePfvUK3ycO7E?key=qInBJpW04kC1Sm63MHgkfg\" alt=\"\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Collision layers<\/h2>\n\n\n\n<p>grid engine<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/Annoraaq\/grid-engine\">https:\/\/github.com\/Annoraaq\/grid-engine<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/medium.com\/swlh\/grid-based-movement-in-a-top-down-2d-rpg-with-phaser-3-e3a3486eb2fd\">https:\/\/medium.com\/swlh\/grid-based-movement-in-a-top-down-2d-rpg-with-phaser-3-e3a3486eb2fd<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/pablo.gg\/en\/blog\/coding\/i-made-a-top-down-game-version-of-my-blog-with-phaser-and-react\">https:\/\/pablo.gg\/en\/blog\/coding\/i-made-a-top-down-game-version-of-my-blog-with-phaser-and-react<\/a><\/p>\n\n\n\n<p>only put them where required &#8211; e.g. just put them around the edge of a body of water &#8211; no need to fill the body of water<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">COLLISION REACTIONS<\/h2>\n\n\n\n<p>collision data drawn from the map data &#8211; e.g. now we have hit it &#8211; what do we do?<\/p>\n\n\n\n<p>impassable<\/p>\n\n\n\n<p>fall<\/p>\n\n\n\n<p>jump down<\/p>\n\n\n\n<p>door<\/p>\n\n\n\n<p>transition<\/p>\n\n\n\n<p>is it better to organise this by LAYER &#8211; or by PROPERTY? may be easier to edit and maintain if it is by LAYER\u2026<\/p>\n\n\n\n<p>look up item by x\/y &#8211; then&nbsp;<\/p>\n\n\n\n<p>maybe find out more about how the engine in question manages collisions &#8211; then optimise for that approach\u2026<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A-STAR Pathfinding<\/h2>\n\n\n\n<p>http:\/\/buildnewgames.com\/astar\/<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Resources<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><br><\/p>\n","protected":false},"excerpt":{"rendered":"<p>See also: System: Concepts hitboxes separating axis theorem\u2026 most of the time you can use rectangle\/rectangle collisions\u2026 Tile based collision is the simplest &#8211; uses a very broad phase approach &#8211; just need to know where we are in the tile array &#8211; lots less info to search\u2026 Inverse collision detection Broad phase and narrow [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"wp-custom-template-nlx-the-knowledge-page","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[],"class_list":["post-408","post","type-post","status-publish","format-standard","hentry","category-the-knowledge"],"_links":{"self":[{"href":"https:\/\/nonlinearexperience.com\/index.php\/wp-json\/wp\/v2\/posts\/408","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nonlinearexperience.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nonlinearexperience.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nonlinearexperience.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nonlinearexperience.com\/index.php\/wp-json\/wp\/v2\/comments?post=408"}],"version-history":[{"count":3,"href":"https:\/\/nonlinearexperience.com\/index.php\/wp-json\/wp\/v2\/posts\/408\/revisions"}],"predecessor-version":[{"id":497,"href":"https:\/\/nonlinearexperience.com\/index.php\/wp-json\/wp\/v2\/posts\/408\/revisions\/497"}],"wp:attachment":[{"href":"https:\/\/nonlinearexperience.com\/index.php\/wp-json\/wp\/v2\/media?parent=408"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nonlinearexperience.com\/index.php\/wp-json\/wp\/v2\/categories?post=408"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nonlinearexperience.com\/index.php\/wp-json\/wp\/v2\/tags?post=408"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}