Skip to content

Instantly share code, notes, and snippets.

@RepComm
Last active June 30, 2024 02:43
Show Gist options
  • Save RepComm/e807effe728121d811438631b625266b to your computer and use it in GitHub Desktop.
Save RepComm/e807effe728121d811438631b625266b to your computer and use it in GitHub Desktop.
2d spring implementation for godot v4 gdscript, simply assign a and b RigidBody2D, script doesn't have to be attached to rigidbodys, just needs to be in the scene
extends Node2D
@export
var a: RigidBody2D = null
@export
var b: RigidBody2D = null
@export
var a_affected: bool = false
@export
var b_affected: bool = false
@export
var stiffness = 10
@export
var rest_length = 10
@export
var damping = 0.5
#a.position - b.position
var v_pos_diff = Vector2()
#calculated length currently at
var v_actual_length: float = 1
#normalized direction from a to b
var v_a_dir = Vector2()
#v_a_dir as euler
var v_a_angle = Vector2()
var v_b_dir = Vector2()
var v_b_angle = Vector2()
#diff of body velocities
var v_vel_diff = 0
#dot product of a-b velocity and a->b direction
var v_vel_diff_dot = 0
#current damping applied in step
var v_damp_force = 0
#spring to resting length force
var v_spring_force = 0
var v_total_force = 0
var v_a_force = Vector2()
var v_b_force = Vector2()
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _physics_process(delta):
if a == null or b == null:
return
#doesn't create a new vec, just fyi
v_pos_diff = b.position - a.position
v_actual_length = v_pos_diff.length()
v_a_dir = v_pos_diff.normalized()
v_a_angle = v_a_dir.angle()
v_b_dir = -v_a_dir
v_b_angle = v_b_dir.angle()
v_vel_diff = b.linear_velocity - a.linear_velocity
v_vel_diff_dot = v_vel_diff.dot(v_a_dir)
#calculate damp force
v_damp_force = v_vel_diff_dot * damping
#Hooke's law spring force
v_spring_force = (v_actual_length - rest_length) * stiffness
v_total_force = v_spring_force + v_damp_force
v_a_force = (v_a_dir * v_total_force) / a.mass
v_b_force = (v_b_dir * v_total_force) / b.mass
if not a_affected and not a.freeze:
a.apply_central_force(v_a_force)
if not b_affected and not b.freeze:
b.apply_central_force(v_b_force)
self.position = a.position.lerp(b.position, 0.5)
self.rotation = v_a_angle
self.scale.x = v_actual_length / rest_length
pass
@RepComm
Copy link
Author

RepComm commented Jun 30, 2024

Revision 2: extends Node2D, scales self x based on a and b rigid bodies, positions self between a and b rigid bodies, rotates to align between a and b rigid bodies. You can attach a visual object as a child to the spring to represent the spring on screen and have full control of what is rendered.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment