From 6a67bfea3672ef0437c3e623b9c49bbc17e62e38 Mon Sep 17 00:00:00 2001 From: Richard Aasa Date: Thu, 25 Jun 2026 00:17:12 +0300 Subject: [PATCH] better ragdoll, launch ragdolls on slam weee --- blood_burst.gd.uid | 1 + debug_params.gd | 5 +++ matador.gd | 76 +------------------------------------ matador_ragdoll.gd | 85 ++++++++++++++++++++++++++++++++++++++++++ matador_ragdoll.gd.uid | 1 + 5 files changed, 93 insertions(+), 75 deletions(-) create mode 100644 blood_burst.gd.uid create mode 100644 matador_ragdoll.gd create mode 100644 matador_ragdoll.gd.uid diff --git a/blood_burst.gd.uid b/blood_burst.gd.uid new file mode 100644 index 0000000..581dd00 --- /dev/null +++ b/blood_burst.gd.uid @@ -0,0 +1 @@ +uid://cnhmhom4w5o3i diff --git a/debug_params.gd b/debug_params.gd index cbc0cf8..4eb4ede 100644 --- a/debug_params.gd +++ b/debug_params.gd @@ -99,6 +99,11 @@ func _register_all() -> void: _reg_f("Matador", "mat_idle_max", 2.5, 0.5, 10.0, 0.1) _reg_f("Matador", "mat_hit_threshold", 4.0, 1.0, 30.0) _reg_f("Matador", "mat_ragdoll_impulse", 6.0, 0.5, 20.0) + # Ragdoll joint limits — lower swing/twist = stiffer corpse that keeps its + # shape; higher angular damp settles the flail instead of flopping flat. + _reg_f("Matador", "mat_joint_swing", 35.0, 0.0, 180.0, 1.0) + _reg_f("Matador", "mat_joint_twist", 40.0, 0.0, 180.0, 1.0) + _reg_f("Matador", "mat_ragdoll_damp", 1.5, 0.0, 10.0, 0.1) _reg_f("Matador", "mat_flee_range", 3.5, 2.0, 40.0) _reg_f("Matador", "mat_flee_speed", 5.5, 0.5, 12.0) _reg_f("Matador", "mat_charge_speed", 10.0, 1.0, 30.0) diff --git a/matador.gd b/matador.gd index 401171a..389310a 100644 --- a/matador.gd +++ b/matador.gd @@ -80,7 +80,7 @@ func _ready() -> void: _skeleton = _find_skeleton(_mesh) _anim_player = _find_anim_player(_mesh) if _skeleton: - _sim = _setup_physical_bones() + _sim = MatadorRagdoll.build(_skeleton) if _anim_player: for anim in [_ANIM_RUN, _ANIM_IDLE, _ANIM_ATTACK, _ANIM_ROLL]: _ensure_loop(anim) @@ -914,80 +914,6 @@ func _apply_sword_grip() -> void: DP.f("sword_rest_rot_x"), DP.f("sword_rest_rot_y"), DP.f("sword_rest_rot_z")) -# ── Ragdoll setup ───────────────────────────────────────────────────────────── - -func _setup_physical_bones() -> PhysicalBoneSimulator3D: - for child: Node in _skeleton.get_children(): - if child is PhysicalBoneSimulator3D: - (child as PhysicalBoneSimulator3D).active = false - return child as PhysicalBoneSimulator3D - - var sim := PhysicalBoneSimulator3D.new() - sim.active = false - _skeleton.add_child(sim) - - const BONES: Array = [ - ["matador", 0.18], - ["COG", 0.12], - ["chest", 0.13, 0.30], - ["head", 0.14], - ["collarbone_L", 0.06, 0.18], - ["collarbone_R", 0.06, 0.18], - ["arm_L", 0.07, 0.22], - ["arm_R", 0.07, 0.22], - ["forearm_L", 0.06, 0.22], - ["forearm_R", 0.06, 0.22], - ["hand_L", 0.05, 0.12], - ["hand_R", 0.05, 0.12], - ["leg_L", 0.10, 0.32], - ["leg_R", 0.10, 0.32], - ["shin_L", 0.08, 0.28], - ["shin_R", 0.08, 0.28], - ["foot_L", 0.07, 0.18], - ["foot_R", 0.07, 0.18], - # Muleta (cape) spine — a free 3-link chain so the cape ragdolls with the - # body instead of hanging frozen in the air. See the cape tweak below. - ["Bone", 0.04, 0.30], - ["Bone.001", 0.04, 0.34], - ["Bone.002", 0.04, 0.30], - ] - - for entry: Array in BONES: - var bname: String = entry[0] - if _skeleton.find_bone(bname) == -1: - continue - var pb := PhysicalBone3D.new() - pb.bone_name = bname - pb.joint_type = PhysicalBone3D.JOINT_TYPE_PIN - pb.mass = 0.4 - pb.linear_damp = 0.1 - pb.angular_damp = 0.2 - pb.collision_layer = 1 - pb.collision_mask = 1 - if bname.begins_with("Bone"): - # Cape: light and draggy so it flutters like cloth; layer 0 makes its - # collision one-way (drapes onto body/floor without shoving the corpse). - pb.mass = 0.15 - pb.linear_damp = 0.5 - pb.angular_damp = 0.7 - pb.collision_layer = 0 - var cs := CollisionShape3D.new() - var use_capsule: bool = entry.size() >= 3 - if use_capsule: - var cap := CapsuleShape3D.new() - cap.radius = entry[1] - cap.height = entry[2] - cs.shape = cap - else: - var sph := SphereShape3D.new() - sph.radius = entry[1] - cs.shape = sph - pb.add_child(cs) - sim.add_child(pb) - - return sim - - # ── Utility ─────────────────────────────────────────────────────────────────── func _find_skeleton(node: Node) -> Skeleton3D: diff --git a/matador_ragdoll.gd b/matador_ragdoll.gd new file mode 100644 index 0000000..6770be7 --- /dev/null +++ b/matador_ragdoll.gd @@ -0,0 +1,85 @@ +class_name MatadorRagdoll +extends RefCounted +## Builds the matador's physical-bone ragdoll. Body joints are cone-twist with +## limited swing/twist (DP-tunable) so the corpse keeps its silhouette instead of +## folding into a flat "deflated" pile; the cape stays free (PIN) so it drapes. + +# [bone, radius] → sphere collider; [bone, radius, height] → capsule. +const _BONES: Array = [ + ["matador", 0.18], + ["COG", 0.12], + ["chest", 0.13, 0.30], + ["head", 0.14], + ["collarbone_L", 0.06, 0.18], + ["collarbone_R", 0.06, 0.18], + ["arm_L", 0.07, 0.22], + ["arm_R", 0.07, 0.22], + ["forearm_L", 0.06, 0.22], + ["forearm_R", 0.06, 0.22], + ["hand_L", 0.05, 0.12], + ["hand_R", 0.05, 0.12], + ["leg_L", 0.10, 0.32], + ["leg_R", 0.10, 0.32], + ["shin_L", 0.08, 0.28], + ["shin_R", 0.08, 0.28], + ["foot_L", 0.07, 0.18], + ["foot_R", 0.07, 0.18], + ["Bone", 0.04, 0.30], + ["Bone.001", 0.04, 0.34], + ["Bone.002", 0.04, 0.30], +] + + +# Reuse an existing simulator if the rig already has one, else build the bodies. +static func build(skeleton: Skeleton3D) -> PhysicalBoneSimulator3D: + for child: Node in skeleton.get_children(): + if child is PhysicalBoneSimulator3D: + (child as PhysicalBoneSimulator3D).active = false + return child as PhysicalBoneSimulator3D + + var sim := PhysicalBoneSimulator3D.new() + sim.active = false + skeleton.add_child(sim) + + var swing := DP.f("mat_joint_swing") + var twist := DP.f("mat_joint_twist") + var damp := DP.f("mat_ragdoll_damp") + + for entry: Array in _BONES: + var bname: String = entry[0] + if skeleton.find_bone(bname) == -1: + continue + var pb := PhysicalBone3D.new() + pb.bone_name = bname + pb.mass = 0.4 + pb.linear_damp = 0.1 + pb.collision_layer = 1 + pb.collision_mask = 1 + if bname.begins_with("Bone"): + # Cape: floppy cloth — free swing, light, draggy, one-way collision. + pb.joint_type = PhysicalBone3D.JOINT_TYPE_PIN + pb.mass = 0.15 + pb.linear_damp = 0.5 + pb.angular_damp = 0.7 + pb.collision_layer = 0 + else: + # Body: cone-twist joints cap how far each bone bends from its rest + # pose, so the silhouette holds; extra angular damp settles the flail. + pb.joint_type = PhysicalBone3D.JOINT_TYPE_CONE + pb.angular_damp = damp + pb.set(&"joint_constraints/swing_span", swing) + pb.set(&"joint_constraints/twist_span", twist) + var cs := CollisionShape3D.new() + if entry.size() >= 3: + var cap := CapsuleShape3D.new() + cap.radius = entry[1] + cap.height = entry[2] + cs.shape = cap + else: + var sph := SphereShape3D.new() + sph.radius = entry[1] + cs.shape = sph + pb.add_child(cs) + sim.add_child(pb) + + return sim diff --git a/matador_ragdoll.gd.uid b/matador_ragdoll.gd.uid new file mode 100644 index 0000000..95cdaa0 --- /dev/null +++ b/matador_ragdoll.gd.uid @@ -0,0 +1 @@ +uid://dmf04b5exnejn