{"author_link":"\/users\/nozomu57","author_name":"Nozomu57","author_uid":"nozomu57","comments":[],"epoch":1683494334,"event":"LD53","format":"md","ldjam_node_id":370244,"likes":10,"metadata":{"p_key":"84524","p_author":"Nozomu57","p_authorkey":"1354631","p_urlkey":"295272","p_title":"Rope math: deconstruction of DETOUR's main mechanic","p_cat":"LDJam ","p_event":"LD53","p_time":"1683494334","p_likes":"10","p_comments":"0","p_status":"WAYBACK","us_key":"1354631","us_name":"Nozomu57","us_username":"nozomu57","event_start":"1682726400","event_key":"118","event_name":"Ludum Dare 53"},"node":{"id":370244,"parent":354774,"_superparent":332127,"author":354631,"type":"post","subtype":"","subsubtype":"","published":"2023-05-07T21:18:54Z","created":"2023-05-07T20:49:03Z","modified":"2023-05-07T22:35:47Z","_trust":1,"version":1144149,"slug":"rope-math-deconstruction-of-detours-main-mechanic","name":"Rope math: deconstruction of DETOUR's main mechanic","body":"Hello! As last idea for a post about [our puzzle-game DETOUR](https:\/\/ldjam.com\/events\/ludum-dare\/53\/detour), I wanted to make an overview of how I implemented rope physics (or should I say \"wire physics\"?)\n\n**What do we want?**\n- We want to draw a line between the player and the charging station, and this line to update on player's movement.\n- When this line touches pillar, we want to \"bend\" the line around the corner, adding a new turning point for the line.\u00a0\n- Repeat for each corner we meet.\n- Also, if we start to \"unwind\" the wire, detach from the pillar when necessary.\n\n*example from our final build:*\n![Day 3 (small).gif](\/\/\/raw\/749\/65\/z\/5b92c.gif)\n\n**So, how do we implement it?**\n\nOne way to do this is use some physics engine: pillars are collidable objects, rope is a chain of collidable objects, they collide with each other. This method was scrapped early on because of one big reason: physics is wonky, rope will wiggle around, glitch at corners, and in general behave not 100% predictable. Not what we want for a puzzle game.\n\nSo we choose the \"nerdy\" way: **maths**. It actually turned out to be easier than I expected, but still required lots of steps to be implemented. I'll try to explain step by step. I am using Godot and its internal objects like Line2D and Area2D, but the concept should work for any game engine (or even extrapolated to no engine at all, if needed).\n\n**1)** For visuals, I use Line2D. In its primitive form it's just a set of lines connecting your points in order.\n\n**2)** Points are stored in an array somewhere in code. First point is always charger (which is immovable), last point is always player (so on player's movement we update last point's position and redraw the line).\n\n**3)** Also, on player's movement we trigger a special \"update detection\" function. For each pair of points (at first it's just 2 points in line), we add a rectangular CollisionShape to the Area2D detection of the line, with the length of distance between lines and the width of the line (more or less). It looks something like this:\n\n![Godot_v3.5.1-stable_win64_4KVf8JlpUX.png](\/\/\/raw\/749\/65\/z\/5b91a.png)\n\nIt\u2019s arguably the only use of build-in \u201cphysics\u201d, but in our case it\u2019s just for detecting intersections between rectangles, which technically could also be done manually by calculating intersection of two rectangle\u2019s edges :)\n\n**4)** Add small collision rectangles to each of the 4 corners in each pillar. When some of the corners detects an intersection with one of the line\u2019s collider, it sends its position to the line. Line adds a new point before the last one, basically splitting the last edge in two new edges (not forgetting to add a new collider for newly emerged edge). Corner remembers which two parts of wire it is already touching, so we don\u2019t create new points for them. The result already looks promising:\n\n![first.gif](\/\/\/raw\/749\/65\/z\/5b923.gif)\n\nThere is only one caveat: we can\u2019t unwind the rope for now. For that, we\u2019ll need more math!\n\n**5)** How do we check if we should be still touching the rope? The secret is just to compare angles! Let\u2019s assume that line between player and second to last point is angled at Y degrees to the horizon, and second to last + third to last points form an X angle:\n\n![IMG_4918.JPG](\/\/\/raw\/749\/65\/z\/5b925.jpg)\n\nNow we can see that if Y>X, then player is still \u201caround the corner\u201d and the wire should still touch the corner. And if the player backtracks and Y becomes lesser than X, then we should \u201cunsnap\u201d from the corner by deleting the second to last point. Sounds good? Let\u2019s test:\n\n![second.gif](\/\/\/raw\/749\/65\/z\/5b927.gif)\n*They got us in the first half, not gonna lie.*\n\nBut we missed just one last calculation:\n\n**6)** If we wrap around the corner \u201ccounterclockwise\u201d (in comparison to \u201cclockwise in step 5\u201d), we should actually wait for Y to become **greater** than X, because everything is mirrored. There is an easy fix: when our line collides with the corner, we also check which side from the edge is the corner situated. It\u2019s actually also just a math comparison between two angles:\n\n![IMG_4919.JPG](\/\/\/raw\/749\/65\/z\/5b928.jpg)\n\nWe store this side alongside line\u2019s points and use it to determine whether we should use \u201c>\u201d or \u201c<\u201d in step 5.\n\nWell, seems like that's it! How does it look?\n\n![Level 3 Final.gif](\/\/\/raw\/749\/65\/z\/5b929.gif)\n*Awesome, it works now!*\n\n___________\n\nOf course, this is a generalisation of the whole idea. I had to implement some \u201cusual game hacks\u201d to make it work as expected:\n- Corner\u2019s point is a bit outside corner\u2019s collider\n- I needed some \u201csmall negative delta angle\u201d in unsnapping function so I don\u2019t unsnap immediately after snapping,\n- Comparison between angles behaves funnily at +-180 degrees\n\nAlso, this logic has limitations. I can\u2019t have moving blocks (but should be easy enough to implement, just moving points inside line and more angle comparisons). Also I tried to do a maze level and failed miserably because line touches dozens of corners at the same time (and I was too lazy to fix that for only one level):\n![photo_2023-04-30_20-44-54.jpg](\/\/\/raw\/749\/65\/z\/5b92a.jpg)\n\nWhat is the moral of the story? Idk, maybe that some complex looking ideas can become simple enough if you can destructure them into simple steps.\n \nIf you liked this post (I genuinely don\u2019t know if this was an interesting read), please leave a like and play our little rope-based arcade-puzzle DETOUR :)\n\nhttps:\/\/ldjam.com\/events\/ludum-dare\/53\/detour","scope":"public","node-timestamp":"2023-05-07T21:21:39Z","meta":[],"path":"\/events\/ludum-dare\/53\/detour\/rope-math-deconstruction-of-detours-main-mechanic","parents":[1,5,9,332127,354774],"files":[],"files-timestamp":0,"love":10,"love-timestamp":"2023-05-07T22:35:47Z","comments":1,"comments-timestamp":"2023-05-07T22:12:24Z","_wayback":{"timestamp":"20230507224243","url":"https:\/\/api.ldjam.com\/vx\/node2\/get\/370251+370249+370248+370244+370234+370245+370232+370243+370241+370239?author&parent&superparent"}},"node_metadata":{"n_key":"370244","n_urlkey":"295272","n_parent":"354774","n_path":"\/events\/ludum-dare\/53\/detour\/rope-math-deconstruction-of-detours-main-mechanic","n_slug":"rope-math-deconstruction-of-deto","n_type":"post","n_subtype":"","n_subsubtype":"","n_author":"354631","n_created":"1683492543","n_modified":"1683498947","n_version":"1144149","n_status":"WAYBACK"},"source_url":"https:\/\/ldjam.com\/events\/ludum-dare\/53\/detour\/rope-math-deconstruction-of-detours-main-mechanic","text":"Hello! As last idea for a post about [our puzzle-game DETOUR](https:\/\/ldjam.com\/events\/ludum-dare\/53\/detour), I wanted to make an overview of how I implemented rope physics (or should I say \"wire physics\"?)\n\n**What do we want?**\n- We want to draw a line between the player and the charging station, and this line to update on player's movement.\n- When this line touches pillar, we want to \"bend\" the line around the corner, adding a new turning point for the line.\u00a0\n- Repeat for each corner we meet.\n- Also, if we start to \"unwind\" the wire, detach from the pillar when necessary.\n\n*example from our final build:*\n![Day 3 (small).gif](\/\/\/raw\/749\/65\/z\/5b92c.gif)\n\n**So, how do we implement it?**\n\nOne way to do this is use some physics engine: pillars are collidable objects, rope is a chain of collidable objects, they collide with each other. This method was scrapped early on because of one big reason: physics is wonky, rope will wiggle around, glitch at corners, and in general behave not 100% predictable. Not what we want for a puzzle game.\n\nSo we choose the \"nerdy\" way: **maths**. It actually turned out to be easier than I expected, but still required lots of steps to be implemented. I'll try to explain step by step. I am using Godot and its internal objects like Line2D and Area2D, but the concept should work for any game engine (or even extrapolated to no engine at all, if needed).\n\n**1)** For visuals, I use Line2D. In its primitive form it's just a set of lines connecting your points in order.\n\n**2)** Points are stored in an array somewhere in code. First point is always charger (which is immovable), last point is always player (so on player's movement we update last point's position and redraw the line).\n\n**3)** Also, on player's movement we trigger a special \"update detection\" function. For each pair of points (at first it's just 2 points in line), we add a rectangular CollisionShape to the Area2D detection of the line, with the length of distance between lines and the width of the line (more or less). It looks something like this:\n\n![Godot_v3.5.1-stable_win64_4KVf8JlpUX.png](\/\/\/raw\/749\/65\/z\/5b91a.png)\n\nIt\u2019s arguably the only use of build-in \u201cphysics\u201d, but in our case it\u2019s just for detecting intersections between rectangles, which technically could also be done manually by calculating intersection of two rectangle\u2019s edges :)\n\n**4)** Add small collision rectangles to each of the 4 corners in each pillar. When some of the corners detects an intersection with one of the line\u2019s collider, it sends its position to the line. Line adds a new point before the last one, basically splitting the last edge in two new edges (not forgetting to add a new collider for newly emerged edge). Corner remembers which two parts of wire it is already touching, so we don\u2019t create new points for them. The result already looks promising:\n\n![first.gif](\/\/\/raw\/749\/65\/z\/5b923.gif)\n\nThere is only one caveat: we can\u2019t unwind the rope for now. For that, we\u2019ll need more math!\n\n**5)** How do we check if we should be still touching the rope? The secret is just to compare angles! Let\u2019s assume that line between player and second to last point is angled at Y degrees to the horizon, and second to last + third to last points form an X angle:\n\n![IMG_4918.JPG](\/\/\/raw\/749\/65\/z\/5b925.jpg)\n\nNow we can see that if Y>X, then player is still \u201caround the corner\u201d and the wire should still touch the corner. And if the player backtracks and Y becomes lesser than X, then we should \u201cunsnap\u201d from the corner by deleting the second to last point. Sounds good? Let\u2019s test:\n\n![second.gif](\/\/\/raw\/749\/65\/z\/5b927.gif)\n*They got us in the first half, not gonna lie.*\n\nBut we missed just one last calculation:\n\n**6)** If we wrap around the corner \u201ccounterclockwise\u201d (in comparison to \u201cclockwise in step 5\u201d), we should actually wait for Y to become **greater** than X, because everything is mirrored. There is an easy fix: when our line collides with the corner, we also check which side from the edge is the corner situated. It\u2019s actually also just a math comparison between two angles:\n\n![IMG_4919.JPG](\/\/\/raw\/749\/65\/z\/5b928.jpg)\n\nWe store this side alongside line\u2019s points and use it to determine whether we should use \u201c>\u201d or \u201c<\u201d in step 5.\n\nWell, seems like that's it! How does it look?\n\n![Level 3 Final.gif](\/\/\/raw\/749\/65\/z\/5b929.gif)\n*Awesome, it works now!*\n\n___________\n\nOf course, this is a generalisation of the whole idea. I had to implement some \u201cusual game hacks\u201d to make it work as expected:\n- Corner\u2019s point is a bit outside corner\u2019s collider\n- I needed some \u201csmall negative delta angle\u201d in unsnapping function so I don\u2019t unsnap immediately after snapping,\n- Comparison between angles behaves funnily at +-180 degrees\n\nAlso, this logic has limitations. I can\u2019t have moving blocks (but should be easy enough to implement, just moving points inside line and more angle comparisons). Also I tried to do a maze level and failed miserably because line touches dozens of corners at the same time (and I was too lazy to fix that for only one level):\n![photo_2023-04-30_20-44-54.jpg](\/\/\/raw\/749\/65\/z\/5b92a.jpg)\n\nWhat is the moral of the story? Idk, maybe that some complex looking ideas can become simple enough if you can destructure them into simple steps.\n \nIf you liked this post (I genuinely don\u2019t know if this was an interesting read), please leave a like and play our little rope-based arcade-puzzle DETOUR :)\n\nhttps:\/\/ldjam.com\/events\/ludum-dare\/53\/detour","title":"Rope math: deconstruction of DETOUR's main mechanic","wayback_source":{"timestamp":"20230507224243","url":"https:\/\/api.ldjam.com\/vx\/node2\/get\/370251+370249+370248+370244+370234+370245+370232+370243+370241+370239?author&parent&superparent"}}