RapidGameFramework
Reusable Godot managers for data-driven small games
Loading...
Searching...
No Matches
constraint_solver.gd
Go to the documentation of this file.
1extends RefCounted
2
3
6
7
8
9func resolve_collisions(bodies:Dictionary, contacts:Array, positional_percent:float = 0.8, slop:float = 0.01) -> Dictionary:
10 var next = bodies.duplicate(true)
11 for contact in contacts:
12 var a_id = str(contact.get("a", {}).get("id", ""))
13 var b_id = str(contact.get("b", {}).get("id", ""))
14 if not next.has(a_id) or not next.has(b_id):
15 continue
16 var a = next[a_id].duplicate(true)
17 var b = next[b_id].duplicate(true)
18 var normal = contact.get("normal", Vector2.RIGHT)
19 var penetration = float(contact.get("penetration", 0.0))
20 var inv_a = float(a.get("inv_mass", 0.0))
21 var inv_b = float(b.get("inv_mass", 0.0))
22 var inv_total = inv_a + inv_b
23 if inv_total <= 0.0:
24 continue
25 var relative_velocity = b.get("velocity", Vector2.ZERO) - a.get("velocity", Vector2.ZERO)
26 var velocity_along_normal = relative_velocity.dot(normal)
27 if velocity_along_normal < 0.0:
28 var restitution = min(float(a.get("restitution", 0.1)), float(b.get("restitution", 0.1)))
29 var impulse_magnitude = -(1.0 + restitution) * velocity_along_normal / inv_total
30 var impulse = normal * impulse_magnitude
31 a["velocity"] = a.get("velocity", Vector2.ZERO) - impulse * inv_a
32 b["velocity"] = b.get("velocity", Vector2.ZERO) + impulse * inv_b
33 var correction = normal * max(penetration - slop, 0.0) / inv_total * positional_percent
34 a["position"] = a.get("position", Vector2.ZERO) - correction * inv_a
35 b["position"] = b.get("position", Vector2.ZERO) + correction * inv_b
36 next[a_id] = a
37 next[b_id] = b
38 return next
39
40
41
42func solve_distance_constraint(bodies:Dictionary, constraint:Dictionary) -> Dictionary:
43 var next = bodies.duplicate(true)
44 var a_id = str(constraint.get("a", ""))
45 var b_id = str(constraint.get("b", ""))
46 if not next.has(a_id) or not next.has(b_id):
47 return next
48 var a = next[a_id].duplicate(true)
49 var b = next[b_id].duplicate(true)
50 var delta = b.get("position", Vector2.ZERO) - a.get("position", Vector2.ZERO)
51 var distance = delta.length()
52 if distance <= 0.0001:
53 return next
54 var target = float(constraint.get("distance", distance))
55 var stiffness = clamp(float(constraint.get("stiffness", 1.0)), 0.0, 1.0)
56 var normal = delta / distance
57 var inv_a = float(a.get("inv_mass", 0.0))
58 var inv_b = float(b.get("inv_mass", 0.0))
59 var inv_total = inv_a + inv_b
60 if inv_total <= 0.0:
61 return next
62 var correction = normal * (distance - target) * stiffness / inv_total
63 a["position"] = a.get("position", Vector2.ZERO) + correction * inv_a
64 b["position"] = b.get("position", Vector2.ZERO) - correction * inv_b
65 next[a_id] = a
66 next[b_id] = b
67 return next
68
69
70
71func solve_constraints(bodies:Dictionary, constraints:Array, iterations:int = 1) -> Dictionary:
72 var next = bodies.duplicate(true)
73 for _i in range(max(1, iterations)):
74 for constraint in constraints:
75 if str(constraint.get("type", "distance")) == "distance":
76 next = solve_distance_constraint(next, constraint)
77 return next
float
Resolve contacts with impulse response and positional correction.