Godot Version
4.3
Question
I’ve built a cable physical simulation scene. Scene gets two links of RigidBody2D anchors and 1 link of Line2D. If parent scene has just one instance of cable scene everything works well. But if I add another one both cable shapes become same and chaotic.
Cable scene tree
Cable scene code
extends Node2D
@export_group("line_settings")
@export var chain_length: float = 500
@export var link_count: int = 10
@export var smoothness: float = 0.3
@export_group("physical_settings")
@export var mass: float = 0.1
@export var inertia: float = 100
@export var softness: float = 0.1
@export var resilience: float = 3000
@export var link_linear_damp: float = 0.1
@export var link_angular_damp: float = 10
@export_group("outer_nodes")
@export var anchor1: PhysicsBody2D
@export var anchor2: PhysicsBody2D
@export var line: Line2D
@export_flags_2d_physics var layers
@export_flags_2d_physics var mask
var links: Array[RigidBody2D]
var joints: Array[PinJoint2D]
func _ready() -> void:
var length = chain_length/link_count
generate_chain(length)
func get_self_position(body:Node2D) -> Vector2:
return ((body.global_position - self.global_position).rotated(-self.global_rotation)/self.global_scale)
func get_self_rotation(body:Node2D) -> float:
return (body.global_rotation - self.global_rotation)
func generate_chain(length) -> void:
#clear existing chain
for link in links:
if is_instance_valid(link):
link.queue_free()
links.clear()
joints.clear()
for child in $Chain.get_children():
child.queue_free()
#generate links
for i in range(link_count):
var link = add_link(length)
link.position = Vector2(get_self_position(anchor1).x + length*i, get_self_position(anchor1).y)
link.inertia = inertia
$Chain.add_child(link)
links.append(link)
await get_tree().process_frame
#generate joints
$Path2D.curve.clear_points()
for i in range(link_count):
var body_a = anchor1 if i == 0 else links[i-1]
var body_b = links[i]
var joint = add_joint(body_a, body_b)
body_b.add_child(joint)
joints.append(joint)
if anchor2 != null:
var body_a = links[-1]
body_a.position = Vector2(get_self_position(anchor2).x-length, get_self_position(anchor2).y)
var joint = add_joint(body_a, anchor2)
joint.position = Vector2(length*self.global_scale.x, 0)
body_a.add_child(joint)
joints.append(joint)
await get_tree().process_frame
#generate points
for joint in joints:
$Path2D.curve.add_point(get_self_position(joint))
func add_link(length) -> RigidBody2D:
var link = RigidBody2D.new()
link.mass = mass/link_count
link.linear_damp = link_linear_damp
link.angular_damp = link_angular_damp
link.center_of_mass_mode = 1
link.center_of_mass = Vector2(length/2, 0)
link.collision_layer = layers
link.collision_mask = mask
var collider = CollisionShape2D.new()
collider.disabled = true
var shape = SegmentShape2D.new()
shape.a = Vector2(0, 0)
shape.b = Vector2(length*self.global_scale.x, 0)
collider.shape = shape
link.add_child(collider)
return link
func add_joint(body_a: PhysicsBody2D, body_b: PhysicsBody2D) -> PinJoint2D:
var joint = PinJoint2D.new()
joint.softness = softness
joint.ready.connect(func():
joint.node_a = joint.get_path_to(body_a)
joint.node_b = joint.get_path_to(body_b)
)
return joint
func _process(_delta: float) -> void:
# prevent index is out of bounds error on start
while $Path2D.curve.point_count < len(joints): return
var length = chain_length/link_count
for i in range(len(links)):
var link = links[i]
var depending_body = anchor1 if i == 0 else links[i-1]
var torqe = resilience*(get_self_rotation(depending_body)-get_self_rotation(link))
link.apply_torque(torqe)
for i in range(len(joints)):
$Path2D.curve.set_point_position(i, get_self_position(joints[i]))
if i==0:
joints[i].global_position = anchor1.global_position
elif i==len(joints)-1:
joints[i].global_position = anchor2.global_position
else:
var prev_joint = joints[i-1]
var next_joint = joints[i+1]
var vector = get_self_position(next_joint)-get_self_position(prev_joint)
vector = length*smoothness*vector.normalized()
$Path2D.curve.set_point_in(i, -vector)
$Path2D.curve.set_point_out(i, vector)
Path2D code
extends Path2D
#Wire up signals on enter tree, since they are removed in exit tree
func _ready() -> void:
var line = $"..".line
line.points = curve.tessellate()
#lock_node(line)
if not curve.changed.is_connected(curve_changed):
curve.changed.connect(curve_changed)
func lock_node(node:Node):
node.set_meta("_edit_lock_", true)
func _enter_tree():
if not curve.changed.is_connected(curve_changed):
curve.changed.connect(curve_changed)
#Clean up signals (ie. when closing scene) to prevent error messages in the editor
func _exit_tree():
if curve.changed.is_connected(curve_changed):
curve.changed.disconnect(curve_changed)
func curve_changed():
var line = $"..".line
line.points = curve.tessellate()
Тестовая сцена


