diff options
Diffstat (limited to 'src/verlet.odin')
| -rw-r--r-- | src/verlet.odin | 80 |
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 + } + } + } +} |
