aboutsummaryrefslogtreecommitdiff
path: root/src/verlet.odin
diff options
context:
space:
mode:
authoriamcheeseman <[hidden email]>2026-01-17 18:19:57 -0500
committeriamcheeseman <[hidden email]>2026-01-17 18:19:57 -0500
commitdb10e319cc2201924815b2d8c9a4c2d21c2bfbb6 (patch)
tree17c7d1b0e485dc07161cbdca80ae2239fd6146c5 /src/verlet.odin
parenteee06361048e34f6ca21348e8776636da95ef3f8 (diff)
Verlet ropes :)
Diffstat (limited to 'src/verlet.odin')
-rw-r--r--src/verlet.odin80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/verlet.odin b/src/verlet.odin
new file mode 100644
index 0000000..1434109
--- /dev/null
+++ b/src/verlet.odin
@@ -0,0 +1,80 @@
+package demonchime
+
+import "core:math"
+import "core:math/linalg"
+
+import rl "vendor:raylib"
+
+import "phys"
+
+VERLET_STEPS :: 50
+VERLET_MIN_DIST_TO_PLAYER :: 8
+
+Verlet_Node :: struct {
+ pos: Vec2,
+ prev_pos: Vec2,
+ accel: Vec2,
+ is_static: bool,
+}
+
+Verlet_Rope :: struct {
+ nodes: []Verlet_Node,
+ node_length: f32,
+}
+
+create_verlet_node :: proc(pos: Vec2, is_static := false) -> Verlet_Node {
+ return Verlet_Node{
+ pos = pos,
+ prev_pos = pos,
+ is_static = is_static,
+ }
+}
+
+update_verlet_node :: proc(node: ^Verlet_Node) {
+ if node.is_static {
+ return
+ }
+
+ dt: f32 = FIXED_UPDATE_RATE
+
+ node.accel.y += GRAVITY
+
+ player_pos := phys.get_position(player.body)
+ player_dist := linalg.distance(node.pos, player_pos)
+ if player_dist < VERLET_MIN_DIST_TO_PLAYER {
+ dir := linalg.normalize(node.pos - player_pos)
+ node.pos = player_pos + dir * VERLET_MIN_DIST_TO_PLAYER
+ }
+
+ prev_pos := node.pos
+ node.pos = (node.pos * 2 - node.prev_pos) + node.accel * (dt*dt)
+ node.prev_pos = prev_pos
+
+ node.accel = {}
+}
+
+update_verlet_rope :: proc(rope: ^Verlet_Rope) {
+ for &node in rope.nodes {
+ update_verlet_node(&node)
+ }
+
+ for _ in 0..<VERLET_STEPS {
+ for i in 0..<len(rope.nodes) - 1 {
+ cur := &rope.nodes[i]
+ nex := &rope.nodes[i + 1]
+
+ dist := linalg.distance(cur.pos, nex.pos)
+ err := dist - rope.node_length
+ dir := linalg.normalize(nex.pos - cur.pos)
+
+ if cur.is_static && !nex.is_static {
+ nex.pos -= dir * err
+ } else if !cur.is_static && nex.is_static {
+ cur.pos += dir * err
+ } else if !cur.is_static && !nex.is_static {
+ cur.pos += dir * err * 0.5
+ nex.pos -= dir * err * 0.5
+ }
+ }
+ }
+}