The Setup
Building a ship-driving game in Godot 4.7. The player picks up a power cable plug and drags it toward a relay control panel. The cable needs to feel real — pull the plug, the crate at the other end drags along. Push the crate, the plug follows.
The Problem
Godot 4 PinJoints connect two RigidBody3D nodes, maintaining a fixed distance between them. Chain enough of them together and you get rope physics. But the default setup relies on frozen kinematic anchors at both ends — these absorb all forces and break the chain.
The crate (30kg RigidBody3D) and the cable plug (5kg RigidBody3D) need to be PART of the chain, not outside it. Setting @export var start_rigidbody: RigidBody3D in the .tscn file via NodePath should resolve at scene load. It doesn’t. Godot 4 silently drops the reference, leaving a frozen anchor in its place.
The Debug Trail
Built a diagnostic harness that instantiated the full test scene and printed every RigidBody3D, every PinJoint, and every connection. Found:
start_rigidbody = null— despite the Crate being a valid RigidBody3D siblingjoint[0]: CableStartAnchor → CableSegment_0— frozen anchor, not the crate- Forces did transfer (crate moved 2.6m when plug teleported 7m), but through indirect position-setting in
_update_anchor_positions(), not through the physics chain
The Fix
Added _resolve_rigidbody_refs() in _ready(), before _build_cable(). Walks from the endpoint node (a CableSocket, 3 levels deep inside the Crate scene) up the parent chain until it finds a RigidBody3D:
func _resolve_rigidbody_refs() -> void:
if not start_rigidbody:
var node: Node = _get_start_endpoint_node()
while node and not (node is RigidBody3D):
node = node.get_parent()
if node is RigidBody3D:
start_rigidbody = node as RigidBody3D
# Same for end_rigidbody
Result: joint[0]: Crate ←PinJoint→ CableSegment_0. Zero frozen anchors. Direct force chain:
Crate (30kg RB) ↔ seg0 ↔ seg1 ↔ ... ↔ seg11 ↔ FreeCableEnd (5kg RB)
The Terminal Screen
Also built a CRT-style terminal display for the relay control panel. Renders to a SubViewport at 320×240, projected onto a QuadMesh in 3D space. Green text when repaired, red when broken. Random diagnostic messages fill template slots (relay IDs, ping times, hex checksums, packet counts) with a glitch effect at 15% probability in broken mode.
Toggling is_repaired on the panel node switches the screen text in real time — works in the editor via @tool script.
Test Harness
16/16 headless tests pass: crate follows plug when pulled, plug follows crate when pushed, segments stay within 2× expected spacing, no frozen anchors, direct PinJoint connections verified.
Key Numbers
- 12 cable segments, mass 1.0kg each
- PinJoint bias 0.9, impulse clamp 20.0 per joint
- Spring resistance on end node: 300N/m, velocity damping 40N·s/m
- Crate mass 30kg, plug mass 5kg
- 32 terminal message templates (10 broken + 10 repaired + mode‑switch lines)
Leave a Reply