missing files
This commit is contained in:
+161
@@ -0,0 +1,161 @@
|
||||
extends CharacterBody3D
|
||||
|
||||
enum State { WANDER, RAGDOLL }
|
||||
|
||||
var _state: State = State.WANDER
|
||||
var _skeleton: Skeleton3D = null
|
||||
var _sim: PhysicalBoneSimulator3D = null
|
||||
var _wander_target: Vector3 = Vector3.ZERO
|
||||
var _idle_timer: float = 0.0
|
||||
|
||||
@onready var _mesh: Node3D = $matador_v02
|
||||
@onready var _hit_area: Area3D = $HitArea
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
add_to_group(&"matador")
|
||||
_skeleton = _find_skeleton(_mesh)
|
||||
if _skeleton:
|
||||
_sim = _setup_physical_bones()
|
||||
_hit_area.body_entered.connect(_on_body_entered)
|
||||
_pick_wander_target()
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if not is_on_floor():
|
||||
velocity += get_gravity() * delta
|
||||
match _state:
|
||||
State.WANDER: _tick_wander(delta)
|
||||
State.RAGDOLL: _tick_ragdoll(delta)
|
||||
|
||||
|
||||
func _tick_wander(delta: float) -> void:
|
||||
if _idle_timer > 0.0:
|
||||
_idle_timer -= delta
|
||||
velocity.x = move_toward(velocity.x, 0.0, 10.0 * delta)
|
||||
velocity.z = move_toward(velocity.z, 0.0, 10.0 * delta)
|
||||
move_and_slide()
|
||||
return
|
||||
|
||||
var dx: float = _wander_target.x - global_position.x
|
||||
var dz: float = _wander_target.z - global_position.z
|
||||
if Vector2(dx, dz).length() < 0.8:
|
||||
_idle_timer = randf_range(DP.f("mat_idle_min"), DP.f("mat_idle_max"))
|
||||
_pick_wander_target()
|
||||
else:
|
||||
var dir := Vector3(dx, 0.0, dz).normalized()
|
||||
var spd := DP.f("mat_walk_speed")
|
||||
velocity.x = dir.x * spd
|
||||
velocity.z = dir.z * spd
|
||||
_mesh.rotation.y = lerp_angle(
|
||||
_mesh.rotation.y, atan2(velocity.x, velocity.z), delta * 8.0)
|
||||
move_and_slide()
|
||||
|
||||
|
||||
func _tick_ragdoll(delta: float) -> void:
|
||||
velocity.x = move_toward(velocity.x, 0.0, 5.0 * delta)
|
||||
velocity.z = move_toward(velocity.z, 0.0, 5.0 * delta)
|
||||
move_and_slide()
|
||||
|
||||
|
||||
func _on_body_entered(body: Node3D) -> void:
|
||||
if _state == State.RAGDOLL:
|
||||
return
|
||||
if not body.is_in_group(&"player"):
|
||||
return
|
||||
var player := body as CharacterBody3D
|
||||
if player.velocity.length() < DP.f("mat_hit_threshold"):
|
||||
return
|
||||
var hit_dir := (global_position - player.global_position).normalized()
|
||||
_enter_ragdoll(hit_dir, player.velocity.length())
|
||||
|
||||
|
||||
func _enter_ragdoll(hit_dir: Vector3, bull_speed: float) -> void:
|
||||
_state = State.RAGDOLL
|
||||
hit_dir.y = 0.0
|
||||
hit_dir = hit_dir.normalized()
|
||||
velocity = Vector3(hit_dir.x, 0.5, hit_dir.z) * bull_speed * 0.4
|
||||
|
||||
if not _sim:
|
||||
return
|
||||
_sim.active = true
|
||||
var strength := DP.f("mat_ragdoll_impulse")
|
||||
for child: Node in _sim.get_children():
|
||||
if child is PhysicalBone3D:
|
||||
var scatter := Vector3(
|
||||
randf_range(-0.3, 0.3),
|
||||
randf_range(0.2, 0.8),
|
||||
randf_range(-0.3, 0.3))
|
||||
(child as PhysicalBone3D).apply_central_impulse(
|
||||
(hit_dir + scatter).normalized() * strength)
|
||||
|
||||
|
||||
func _pick_wander_target() -> void:
|
||||
var radius := DP.f("mat_wander_radius")
|
||||
var angle := randf() * TAU
|
||||
var dist := randf_range(2.0, radius)
|
||||
_wander_target = Vector3(cos(angle) * dist, 0.0, sin(angle) * dist)
|
||||
|
||||
|
||||
# ── 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)
|
||||
|
||||
# [bone_name, sphere_radius] or [bone_name, capsule_radius, capsule_height]
|
||||
const BONES: Array = [
|
||||
["matador", 0.18],
|
||||
["chest", 0.13, 0.30],
|
||||
["head", 0.14],
|
||||
["arm_L", 0.07, 0.22],
|
||||
["arm_R", 0.07, 0.22],
|
||||
["forearm_L", 0.06, 0.22],
|
||||
["forearm_R", 0.06, 0.22],
|
||||
["leg_L", 0.10, 0.32],
|
||||
["leg_R", 0.10, 0.32],
|
||||
["shin_L", 0.08, 0.28],
|
||||
["shin_R", 0.08, 0.28],
|
||||
]
|
||||
|
||||
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.linear_damp = 0.5
|
||||
pb.angular_damp = 0.5
|
||||
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:
|
||||
if node is Skeleton3D:
|
||||
return node as Skeleton3D
|
||||
for child: Node in node.get_children():
|
||||
var r := _find_skeleton(child)
|
||||
if r:
|
||||
return r
|
||||
return null
|
||||
Reference in New Issue
Block a user