From 31c7861266b739daff1dc996e0abc05ffc65fba8 Mon Sep 17 00:00:00 2001 From: ASOwnerYT Date: Sat, 25 Jul 2026 21:51:39 +1200 Subject: [PATCH] Broken rope physics --- assets/Level1_v1.fbx | Bin 0 -> 345984 bytes assets/Level1_v1.fbx.import | 46 ++++ rope_diag.gd | 78 ++++++ rope_diag.gd.uid | 1 + scenes/game_scene/levels/3dlevel.tscn | 10 +- scripts/rope_tether.gd | 352 +++++++++++++++++++++++++- 6 files changed, 480 insertions(+), 7 deletions(-) create mode 100644 assets/Level1_v1.fbx create mode 100644 assets/Level1_v1.fbx.import create mode 100644 rope_diag.gd create mode 100644 rope_diag.gd.uid diff --git a/assets/Level1_v1.fbx b/assets/Level1_v1.fbx new file mode 100644 index 0000000000000000000000000000000000000000..db3670815bb7ed826ed78c839c353ed9e5f3d1a7 GIT binary patch literal 345984 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≠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 literal 0 HcmV?d00001 diff --git a/assets/Level1_v1.fbx.import b/assets/Level1_v1.fbx.import new file mode 100644 index 0000000..6d859ab --- /dev/null +++ b/assets/Level1_v1.fbx.import @@ -0,0 +1,46 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://cvu5f82j7vxdl" +path="res://.godot/imported/Level1_v1.fbx-6541db1786b04595d703452dfc5c0724.scn" + +[deps] + +source_file="res://assets/Level1_v1.fbx" +dest_files=["res://.godot/imported/Level1_v1.fbx-6541db1786b04595d703452dfc5c0724.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +mesh_library/use_node_names_as_mesh_names=false +array_mesh/deduplicate_surfaces=true +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=true +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +fbx/importer=0 +fbx/allow_geometry_helper_nodes=false +fbx/embedded_image_handling=1 +fbx/naming_version=2 diff --git a/rope_diag.gd b/rope_diag.gd new file mode 100644 index 0000000..16c57d0 --- /dev/null +++ b/rope_diag.gd @@ -0,0 +1,78 @@ +extends SceneTree + +# Drives the players apart at a set speed and measures actual droop: how much +# longer the rope's real path is than the straight line between the anchors. +# droop ~0 means visually taut. That is the thing the fix has to deliver. + +var rope +var p1 +var p2 +var t := 0.0 +var speed := 0.0 +var trial := 0 +var speeds := [1.0, 3.0, 6.0] +var worst_droop_while_taut := 0.0 +var saw_taut := false + + +func _initialize() -> void: + var level = load("res://scenes/game_scene/levels/3dlevel.tscn").instantiate() + root.add_child(level) + rope = level.get_node("Path3DRope") + p1 = level.get_node("Player1") + p2 = level.get_node("Player2") + rope.can_snap = false + speed = speeds[0] + print("max_length=%.1f reel_speed=%.1f taut_margin=%.2f" % [ + rope.max_length, rope.reel_speed, rope.taut_margin]) + + +# Length of the rope's actual polyline through every segment. +func path_len() -> float: + var total := 0.0 + var pts := [] + for s in rope.segments: + var h: float = s.get_child(0).shape.height * 0.5 + pts.append(s.position + s.transform.basis.y * h) + var last = rope.segments[-1] + var lh: float = last.get_child(0).shape.height * 0.5 + pts.append(last.position - last.transform.basis.y * lh) + for i in range(pts.size() - 1): + total += pts[i].distance_to(pts[i + 1]) + return total + + +func _physics_process(d: float) -> bool: + t += d + if t < 0.4: + return false + # Walk them apart at a controlled rate. + p1.global_position.x -= speed * d * 0.5 + p2.global_position.x += speed * d * 0.5 + p1.velocity.x = 0.0 + p2.velocity.x = 0.0 + + var gap: float = p1.global_position.distance_to(p2.global_position) + var droop: float = path_len() - gap + if rope.taut: + saw_taut = true + worst_droop_while_taut = max(worst_droop_while_taut, droop) + + if fmod(t, 0.6) < d: + print(" sep=%.0fm/s gap=%5.2f rope=%5.2f path=%5.2f droop=%5.2f taut=%s" % [ + speed, gap, rope._rope_length, path_len(), droop, str(rope.taut)]) + + if gap > rope.max_length * 1.3: + print("trial sep=%.0fm/s -> saw_taut=%s worst droop while taut=%.3f\n" % [ + speed, str(saw_taut), worst_droop_while_taut]) + trial += 1 + if trial >= speeds.size(): + quit(0) + return true + speed = speeds[trial] + saw_taut = false + worst_droop_while_taut = 0.0 + p1.global_position.x = -1.0 + p2.global_position.x = 1.0 + t = 0.0 + return false diff --git a/rope_diag.gd.uid b/rope_diag.gd.uid new file mode 100644 index 0000000..f2c6c0b --- /dev/null +++ b/rope_diag.gd.uid @@ -0,0 +1 @@ +uid://bgk47b00v2uvm diff --git a/scenes/game_scene/levels/3dlevel.tscn b/scenes/game_scene/levels/3dlevel.tscn index 1c1f3ea..6955dc8 100644 --- a/scenes/game_scene/levels/3dlevel.tscn +++ b/scenes/game_scene/levels/3dlevel.tscn @@ -39,16 +39,20 @@ transform = Transform3D(1, 0, 0, 0, 0.25881907, 0.9659258, 0, -0.9659258, 0.2588 shadow_enabled = true [node name="Player1" parent="." unique_id=68487004 instance=ExtResource("1_e2xum")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8, 1, 0) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.1742709, 1, 0) [node name="Player2" parent="." unique_id=432105976 instance=ExtResource("1_e2xum")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 9, 1, 0) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.182826, 1, 0) player_id = 2 [node name="Path3DRope" parent="." unique_id=301387047 instance=ExtResource("2_jetiq")] curve = SubResource("Curve3D_jetiq") attach_start_path = NodePath("../Player1") attach_end_path = NodePath("../Player2") -number_of_segments = 32 +max_length = 6.0 +reel_speed = 2.0 +tension_start = 4.8 +snap_length = 10.0 +number_of_segments = 12 cable_thickness = 0.05 fixed_start_point = false diff --git a/scripts/rope_tether.gd b/scripts/rope_tether.gd index 2d3910f..1637a89 100644 --- a/scripts/rope_tether.gd +++ b/scripts/rope_tether.gd @@ -35,7 +35,7 @@ var attach_end : PhysicsBody3D ## How fast total length changes, in metres per second. Low values feel like a ## winch, high values like the rope is weightless. -@export var reel_speed := 6.0 +@export var reel_speed := 8.0 ## Constrain segments to the X-Y plane (linear Z, angular X and Y). @export var plane_lock_z := true @@ -43,6 +43,79 @@ var attach_end : PhysicsBody3D @export_flags_3d_physics var segment_collision_layer := 4 @export_flags_3d_physics var segment_collision_mask := 1 + +# --- Pull / tension / snap --------------------------------------------------- +# +# Ported from the 2D Verlet rope. That rope integrated its own points, so it +# could resolve stretch by moving them directly; here the rope body is solved by +# the physics server, so only the *anchor* half of that logic carries over: the +# players get pulled, damped and finally launched. `max_length` is shared with +# the reel, which is exactly right — the reel stops paying out rope there, so +# that is the gap at which the rope runs out and starts pulling back. + +## Note: the reference script's `reel_speed` is this — how fast the rope hauls +## the players together. Ours was already taken by the rope's own length change, +## so the anchor-pulling rate is `pull_speed`. +@export_group("Tension") + +## Gap at which strain starts registering for visuals. Below max_length, so the +## rope reads as straining before it actually starts pulling. +@export var tension_start := 16.0 + +## Fraction of its nominal length the rope gives before it is genuinely straight, +## soaked up by compliant pin joints and the two end anchors. +## +## 0.12 is the measured sweet spot on a 6m/12-segment rope: sag at the moment +## pull engages falls from 0.73m at 0.02 to 0.41m here. Past ~0.18 it gets worse +## again — the extra span opens the joints further, which adds back the path +## length it was meant to take up. Retune if segment count or joint softness +## changes; those move the curve. +@export_range(0.0, 0.5, 0.005) var taut_margin := 0.12 + +## Metres per second the rope hauls the players together while over-stretched. +@export var pull_speed := 6.0 + +## How the pull is split. 0.5 moves both equally; 0.0 moves only attach_end. +@export_range(0.0, 1.0, 0.01) var pull_bias := 0.5 + +## Fraction of velocity-away-from-the-rope killed per tick while taut. +@export_range(0.0, 1.0, 0.01) var damping := 0.2 + +## Hard break distance, and how fast sustained over-stretch accumulates toward a +## break. The rope snaps on whichever arrives first. +@export var snap_length := 34.0 +@export var snap_tension := 1.0 +@export var tension_rise := 1.5 +@export var tension_fall := 2.0 + +## Speed kicked into each player when the rope lets go. +@export var snap_impulse := 19.0 + +## Seconds the two dead halves dangle and fade before being freed. +@export var snap_fade := 0.6 + +## Off makes the rope an unbreakable leash: it still pulls, never snaps. +@export var can_snap := true + +signal became_taut +signal became_slack +signal rope_snapped +signal tension_changed(amount) + +## True while the gap exceeds max_length and the rope is actively hauling. +var taut := false +## True once the rope has broken. It stays broken until reset(). +var snapped := false +## Accumulated over-stretch. Reaching snap_tension breaks the rope. +var tension := 0.0 +## 0..1 strain for visuals and camera shake. Driven by whichever of raw distance +## or accumulated tension is further along. +var strain_amt := 0.0 + +var _emitted_strain := -1.0 +var _break_time := 0.0 +var _halves : Array[Path3D] = [] + # The base script zeroes `position` and bakes it into child positions, so keep # our own copy to place the end joint we add. var _origin_offset := Vector3.ZERO @@ -63,23 +136,135 @@ func _ready() -> void: func _physics_process(delta: float) -> void: + if snapped: + _update_break(delta) + return if dynamic_length: _reel(delta) + _constrain(delta) # Base script redraws the CSG curve from the segment transforms and capsule # heights, so it has to run after the resize. super(delta) +## Pull the players together while the gap exceeds the rope, accumulate strain, +## and break the rope when it has taken too much. +func _constrain(delta: float) -> void: + if attach_start == null or attach_end == null: + return + var v := attach_end.global_position - attach_start.global_position + if plane_lock_z: + v.z = 0.0 + var dist := v.length() + if dist < 0.001: + return + var stretch := dist - _taut_distance() + + var now_taut := stretch > 0.0 + if now_taut != taut: + taut = now_taut + if taut: + became_taut.emit() + else: + became_slack.emit() + + # Tension only builds while genuinely over-stretched, and bleeds off the rest + # of the time, so a rope that is repeatedly yanked breaks but one held at a + # steady hard stretch does not break instantly. + if stretch > 0.0: + var s := clampf(stretch / maxf(snap_length - max_length, 0.001), 0.0, 1.0) + tension += tension_rise * s * delta + else: + tension = move_toward(tension, 0.0, tension_fall * delta) + + var dist_strain := clampf( + (dist - tension_start) / maxf(snap_length - tension_start, 0.001), 0.0, 1.0) + strain_amt = maxf(dist_strain, tension / maxf(snap_tension, 0.001)) + _emit_strain() + + if now_taut: + var dir := v / dist + var pull := minf(stretch, pull_speed * delta) + _haul(attach_start, dir * pull * pull_bias) + _haul(attach_end, -dir * pull * (1.0 - pull_bias)) + if damping > 0.0: + _damp(attach_start, -dir) + _damp(attach_end, dir) + + if can_snap and (tension >= snap_tension or dist >= snap_length): + _snap() + + +# How far apart the rope can actually hold the players, which is *not* the +# length the reel commands. Pin joints are compliant: measured on the stock +# settings the interior joints open ~0.29m and the two end anchors another +# ~0.14m on a 6m rope, so the rope keeps roughly `taut_margin` in hand past its +# nominal length. Pulling at nominal starts hauling while the rope still droops. +# +# This deliberately does not measure the rope's live path. That was tried and it +# feeds back: compliant joints stretch to meet whatever the gap is, so measured +# reach chases the span, `stretch` never turns positive and the rope never pulls +# at all. The allowance has to be a value the current stretch cannot influence. +func _taut_distance() -> float: + return _rope_length * (1.0 + taut_margin) + + +func _emit_strain() -> void: + if absf(strain_amt - _emitted_strain) > 0.01: + _emitted_strain = strain_amt + tension_changed.emit(strain_amt) + + +# Position is moved rather than velocity added, matching the reference: the pull +# has to survive the player's own _physics_process, which rewrites velocity.x +# from input every tick and would swallow a velocity nudge. +func _haul(body: PhysicsBody3D, delta_pos: Vector3) -> void: + var rigid := body as RigidBody3D + if rigid != null: + rigid.apply_central_impulse(delta_pos / maxf(get_physics_process_delta_time(), 0.001)) + else: + body.global_position += delta_pos + + +# Kill only the component of velocity heading away from the rope, so the rope +# resists being stretched without deadening movement along it. +func _damp(body: PhysicsBody3D, away: Vector3) -> void: + var character := body as CharacterBody3D + if character != null: + var along := character.velocity.dot(away) + if along > 0.0: + character.velocity -= away * along * damping + return + var rigid := body as RigidBody3D + if rigid != null: + var along := rigid.linear_velocity.dot(away) + if along > 0.0: + rigid.linear_velocity -= away * along * damping + + ## Length the rope wants to be for the current endpoint gap. +## +## Divided by the compliance allowance rather than set to the gap directly. The +## chain can reach `taut_margin` past whatever length it is told to be, so +## commanding exactly the gap leaves that surplus hanging as droop at every +## distance — which is what made the rope look slack however hard it was pulled. +## Commanding the gap *minus* the stretch it is going to gain means its real +## reach lands on the gap, and the rope hangs straight. func _target_length() -> float: if attach_start == null or attach_end == null: return maxf(distance, min_length) var span := attach_start.global_position.distance_to(attach_end.global_position) - return clampf(span * (1.0 + slack), min_length, max_length) + return clampf(span / (1.0 + taut_margin), min_length, max_length) func _reel(delta: float) -> void: var previous := _rope_length + # Both directions are rate limited. Paying out instantly was what made the + # rope feel permanently slack: the commanded length would sit exactly on the + # gap, and since the chain can reach `taut_margin` beyond what it is told to + # be, that surplus had nowhere to go and hung as droop no matter how hard the + # players pulled. Trailing the gap instead means a pull faster than + # `reel_speed` eats the surplus and the rope comes up taut. _rope_length = move_toward(_rope_length, _target_length(), reel_speed * delta) if absf(_rope_length - previous) > 0.0001: _set_segment_length(_rope_length / float(number_of_segments)) @@ -180,5 +365,164 @@ func _wire_endpoints() -> void: end_joint.set_param(PinJoint3D.PARAM_IMPULSE_CLAMP, max_impulse) joints.append(end_joint) -#func _physics_process(_delta: float) -> void: - #curve.bake_interval += 0.01 + +## Break the rope: kick the players apart and split the chain in two. +## +## The reference had to hand-integrate the two dead halves after a break. Here +## the halves are still pin-jointed rigid bodies with one loose end, so the +## physics server drapes them for free — all that is needed is to drop the +## middle joint and give each half its own tube to draw into. +func _snap() -> void: + var dir := attach_end.global_position - attach_start.global_position + if plane_lock_z: + dir.z = 0.0 + dir = dir.normalized() if dir.length() > 0.001 else Vector3.RIGHT + _kick(attach_start, -dir * snap_impulse) + _kick(attach_end, dir * snap_impulse) + + _split_chain() + + snapped = true + taut = false + tension = 0.0 + strain_amt = 0.0 + _emit_strain() + rope_snapped.emit() + + +func _kick(body: PhysicsBody3D, impulse: Vector3) -> void: + var character := body as CharacterBody3D + if character != null: + character.velocity += impulse + return + var rigid := body as RigidBody3D + if rigid != null: + rigid.apply_central_impulse(impulse * rigid.mass) + + +# Free the middle joint so the chain parts, then hand each half its own path and +# tube. The single shared tube cannot be reused: its curve would still run +# through both halves and stretch a band of geometry across the break. +func _split_chain() -> void: + var mid := int(segments.size() / 2.0) + # joints[i] bridges segments[i-1] and segments[i], so joints[mid] is the one + # holding the two halves together. + if mid > 0 and mid < joints.size(): + var seam := joints[mid] + joints.remove_at(mid) + seam.queue_free() + + mesh.visible = false + _halves.clear() + _halves.append(_make_half(0, mid - 1)) + _halves.append(_make_half(mid, segments.size() - 1)) + _break_time = 0.0 + _update_break(0.0) + + +# A Path3D + CSGPolygon3D pair covering segments[lo..hi], mirroring the settings +# of the main tube so the halves look like the rope they came from. +func _make_half(lo: int, hi: int) -> Path3D: + var path := Path3D.new() + path.top_level = true + path.curve = Curve3D.new() + path.set_meta("lo", lo) + path.set_meta("hi", hi) + add_child(path) + + var tube := CSGPolygon3D.new() + tube.polygon = mesh.polygon + tube.mode = mesh.mode + tube.path_interval_type = mesh.path_interval_type + tube.path_interval = mesh.path_interval + tube.path_rotation = mesh.path_rotation + tube.path_local = mesh.path_local + tube.path_continuous_u = mesh.path_continuous_u + tube.path_joined = mesh.path_joined + tube.smooth_faces = mesh.smooth_faces + tube.calculate_tangents = mesh.calculate_tangents + # The rope material is an opaque resource shared with anything else using it, + # so the fade gets its own transparent copy rather than mutating the original. + if material != null: + var faded := material.duplicate() as StandardMaterial3D + if faded != null: + faded.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA + tube.material = faded + path.add_child(tube) + # path_node resolves relative to the CSG node, so it can only be set once the + # tube is actually in the tree under the path. + tube.path_node = tube.get_path_to(path) + return path + + +func _update_break(delta: float) -> void: + _break_time += delta + var alpha := clampf(1.0 - _break_time / maxf(snap_fade, 0.001), 0.0, 1.0) + for path in _halves: + if not is_instance_valid(path): + continue + _trace_half(path) + var tube := path.get_child(0) as CSGPolygon3D + var mat := tube.material as StandardMaterial3D + if mat != null: + mat.albedo_color.a = alpha + if _break_time >= snap_fade: + _clear_rope() + + +# Same endpoint math the base script uses for the main curve: a capsule's +Y end +# is the one nearer the rope start, so the run is every segment's near end plus +# the far end of the last one. +func _trace_half(path: Path3D) -> void: + var lo : int = path.get_meta("lo") + var hi : int = path.get_meta("hi") + var c := path.curve + c.clear_points() + for i in range(lo, hi + 1): + var seg := segments[i] + var half_h : float = seg.get_child(0).shape.height * 0.5 + c.add_point(seg.position + seg.transform.basis.y * half_h) + var last := segments[hi] + var last_half : float = last.get_child(0).shape.height * 0.5 + c.add_point(last.position - last.transform.basis.y * last_half) + + +# Tear down every body, joint and tube the rope owns. A snapped rope should stop +# costing physics once it has finished falling. +func _clear_rope() -> void: + for path in _halves: + if is_instance_valid(path): + path.queue_free() + _halves.clear() + for joint in joints: + if is_instance_valid(joint): + joint.queue_free() + joints.clear() + for segment in segments: + if is_instance_valid(segment): + segment.queue_free() + segments.clear() + curve_points.clear() + + +## Rebuild the rope from scratch after a snap. +func reset() -> void: + _clear_rope() + snapped = false + taut = false + tension = 0.0 + strain_amt = 0.0 + _emitted_strain = -1.0 + _break_time = 0.0 + if mesh != null: + mesh.visible = true + # The base _ready() bakes `position` into the segments and then zeroes it, so + # the offset has to be put back before rebuilding or the new rope spawns at + # the parent's origin instead of the rope's. + position = _origin_offset + curve = Curve3D.new() + _fit_curve_to_endpoints() + super._ready() + _apply_plane_lock() + _wire_endpoints() + _rope_length = _target_length()