tail wag works
This commit is contained in:
+35
-11
@@ -108,18 +108,41 @@ func _setup_tail() -> void:
|
||||
push_error("BullLegs: not enough tail bones found")
|
||||
return
|
||||
|
||||
for i in range(_tail_idx.size() - 1):
|
||||
var a: Transform3D = _skeleton.get_bone_global_rest(_tail_idx[i])
|
||||
var b: Transform3D = _skeleton.get_bone_global_rest(_tail_idx[i + 1])
|
||||
_tail_lengths.append((b.origin - a.origin).length())
|
||||
_tail_rest_dir.append((b.origin - a.origin).normalized())
|
||||
_tail_rest_dir.append(_tail_rest_dir[-1])
|
||||
|
||||
# Initialise world positions first
|
||||
for idx: int in _tail_idx:
|
||||
var world: Vector3 = _skeleton.to_global(_skeleton.get_bone_global_rest(idx).origin)
|
||||
_tail_world.append(world)
|
||||
_tail_prev.append(world)
|
||||
|
||||
# Detect degenerate rest pose (FBX bones all at same position)
|
||||
var max_sep: float = 0.0
|
||||
for i in range(_tail_world.size() - 1):
|
||||
max_sep = maxf(max_sep, _tail_world[i].distance_to(_tail_world[i + 1]))
|
||||
if max_sep < 0.01:
|
||||
push_warning("BullLegs: tail bones have zero separation in rest pose, distributing along spine")
|
||||
var root: Vector3 = _tail_world[0]
|
||||
# Backward-downward direction in world space from the skeleton
|
||||
var back: Vector3 = (_skeleton.global_transform.basis.z + Vector3.DOWN * 0.3).normalized()
|
||||
for i in range(_tail_world.size()):
|
||||
_tail_world[i] = root + back * (i * 0.09)
|
||||
_tail_prev[i] = _tail_world[i]
|
||||
|
||||
# Segment lengths in world space — used by the Verlet length constraint
|
||||
const MIN_SEG: float = 0.06
|
||||
for i in range(_tail_world.size() - 1):
|
||||
var seg_len: float = _tail_world[i].distance_to(_tail_world[i + 1])
|
||||
_tail_lengths.append(maxf(seg_len, MIN_SEG))
|
||||
|
||||
# Rest directions in SKELETON-LOCAL space — must match point_dir_skel in _apply_tail
|
||||
# so that Quaternion(rest_dir, point_dir_skel) operates in a consistent frame.
|
||||
# _tail_world holds world positions; to_local converts them to skeleton space.
|
||||
for i in range(_tail_world.size() - 1):
|
||||
var p1_skel: Vector3 = _skeleton.to_local(_tail_world[i])
|
||||
var p2_skel: Vector3 = _skeleton.to_local(_tail_world[i + 1])
|
||||
var seg_skel: Vector3 = p2_skel - p1_skel
|
||||
_tail_rest_dir.append(seg_skel.normalized() if seg_skel.length() > 0.001 else Vector3(0, 0, 1))
|
||||
_tail_rest_dir.append(_tail_rest_dir[-1])
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if not _skeleton:
|
||||
@@ -271,7 +294,7 @@ func _step_launch(_delta: float) -> void:
|
||||
_foot[id] = _launch_feet[id]
|
||||
|
||||
|
||||
func _step_ragdoll(delta: float) -> void:
|
||||
func _step_ragdoll(_delta: float) -> void:
|
||||
# Procedural floppy dangle — NOT real physics ragdoll
|
||||
var time: float = _state_time
|
||||
var amp: float = DP.f("ragdoll_wobble_amp")
|
||||
@@ -335,10 +358,10 @@ func _get_tucked_foot(id: String) -> Vector3:
|
||||
|
||||
|
||||
func _apply_ik() -> void:
|
||||
var skel_inv: Transform3D = _skeleton.global_transform.affine_inverse()
|
||||
for id: String in _ik:
|
||||
var ik: SkeletonIK3D = _ik[id]
|
||||
var target_local: Vector3 = _skeleton.get_parent().to_local(_foot[id])
|
||||
ik.target = Transform3D(Basis.IDENTITY, target_local)
|
||||
ik.target = Transform3D(Basis.IDENTITY, skel_inv * _foot[id])
|
||||
|
||||
|
||||
# ── Tail ──────────────────────────────────────────────────────────────────────
|
||||
@@ -365,7 +388,8 @@ func _update_tail(delta: float) -> void:
|
||||
var vel: Vector3 = (_tail_world[i] - _tail_prev[i]) * damping
|
||||
_tail_prev[i] = _tail_world[i]
|
||||
# Add wag force (sinusoidal side-to-side)
|
||||
var wag := _bull.global_transform.basis.x * sin(time * DP.f("tail_wag_freq") + i * 0.5) * wag_strength
|
||||
var wag := _bull.global_transform.basis.x \
|
||||
* sin(time * DP.f("tail_wag_freq") + i * 0.5) * wag_strength
|
||||
_tail_world[i] = _tail_world[i] + vel + gravity * (delta * delta) + wag * delta
|
||||
|
||||
# Length constraint
|
||||
|
||||
Reference in New Issue
Block a user