I need help getting a cable system to work

Godot Version

Godot 4.6

Question

I’ve been trying to get a wire working that wraps and unwraps around objects. Solutions involving physics based ropes don’t work for my case. I’ve gotten wrapping to work, but the unwrapping side has been giving me trouble for awhile. Here is what I’ve got so far:

extends Node3D

@onready var tip: Node3D = $Tip
@onready var segments: Node3D = $Segments
const ROPE_SEGMENT = preload("uid://d4h861jbj5jt3")

@export var end_node: Node3D

var points: Array = [Vector3.ZERO]
var angles: Array = [[]]
var previous_points: Array = [Vector3.ZERO]

func _ready() -> void:
	points[0] = global_position

func _physics_process(delta: float) -> void:
	
	tip.position.x -= 4.0*delta if Input.is_action_pressed("ui_left") else 0.0
	tip.position.x += 4.0*delta if Input.is_action_pressed("ui_right") else 0.0
	tip.position.z -= 4.0*delta if Input.is_action_pressed("ui_up") else 0.0
	tip.position.z += 4.0*delta if Input.is_action_pressed("ui_down") else 0.0
	
	points[points.size()-1] = global_position
	
	for i in segments.get_child_count():
		var child: Node3D = segments.get_child(i)
		var ray: RayCast3D = child.get_node("RayCast3D")
		var child_count = segments.get_child_count()
		
		child.visible = true
		child.get_node("MeshInstance3D").visible = true #TEMPORARY
		
		if i == 0:
			child.global_position = end_node.global_position
			if not child.global_position.is_equal_approx(points[i]): child.look_at(points[i])
			child.scale.z = child.global_position.distance_to(points[i])/2.0
			previous_points[i] = child.global_position
		else:
			child.global_position = points[i-1]
			if not child.global_position.is_equal_approx(points[i]): child.look_at(points[i])
			child.scale.z = child.global_position.distance_to(points[i])/2.0
			previous_points[i] = child.global_position
			continue
		
		if child_count>1:
			#INSERT UNWRAP LOGIC
			pass
		if ray.is_colliding():
			var wrap: bool = true
			var collision_point: Vector3 = ray.get_collision_point()
			for p in points.size(): if points[p].distance_to(collision_point) < 0.02: wrap = false
			
			if wrap:
				var new_seg = ROPE_SEGMENT.instantiate()
				#new_seg.hide()
				segments.add_child(new_seg)
				segments.move_child(new_seg, 1)
				
				points.insert(0, collision_point)
				angles.insert(0, [global_position, previous_points[i], collision_point])
				previous_points.insert(0, collision_point)
				
				return
		
		previous_points[i] = child.global_position
		

Heres my setup for the node with the script:

image

Here’s the actual wire segments:

image
I can’t upload a video showing what it looks like right now since I’m a new user.

Is anyone able to help get this working? I’ve already looked at the few posts from people trying to do similar things, though none of that helped me :confused:

Do you have any code that you wrote that attempted the unwrapping? Seeing your attempts would be helpful.

I’ll try to recreate a few of them