feat: add player sword combat, dash, and hostile wolf/raider visuals

This commit is contained in:
Rijad Zuzo
2026-08-11 20:49:43 +02:00
parent 292cdd9153
commit b62f7b86cc
12 changed files with 564 additions and 1 deletions
+152
View File
@@ -0,0 +1,152 @@
class_name HostileCombatant
extends Node3D
const FOLLOW_SPEED := 6.0
const ARRIVE_DISTANCE := 0.5
var combatant_id: StringName
var combatant: CombatantStateRecord
var simulation_manager: Node
var is_dead_visual := false
var flash_tween: Tween
var spawn_scale := Vector3.ONE
func _ready() -> void:
spawn_scale = Vector3.ONE
scale = Vector3.ONE * 0.001
var tween := create_tween()
tween.set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
tween.tween_property(self, "scale", Vector3.ONE, 0.28)
func bind(combatant_id_value: StringName, manager: Node) -> void:
combatant_id = combatant_id_value
simulation_manager = manager
combatant = manager.get_combatant(combatant_id) as CombatantStateRecord
if combatant == null:
return
global_position = combatant.get_position()
_build_body(combatant.get_kind())
combatant.changed.connect(_on_combatant_changed)
func _process(delta: float) -> void:
if is_dead_visual or combatant == null or not is_instance_valid(combatant):
return
if not combatant.is_alive():
_play_death()
return
var target_position := combatant.get_position()
var to_target := target_position - global_position
if to_target.length() <= ARRIVE_DISTANCE:
return
global_position += to_target.normalized() * minf(FOLLOW_SPEED * delta, to_target.length())
rotation.y = lerp_angle(rotation.y, atan2(to_target.x, to_target.z), delta * 8.0)
func _on_combatant_changed(_state: CombatantStateRecord) -> void:
if combatant == null or combatant.get_health() >= combatant.get_max_health():
return
_flash_hit()
func _flash_hit() -> void:
if flash_tween != null and flash_tween.is_valid():
flash_tween.kill()
flash_tween = create_tween()
flash_tween.tween_property(self, "scale", Vector3.ONE * 0.85, 0.06)
flash_tween.tween_property(self, "scale", Vector3.ONE, 0.12)
func _play_death() -> void:
is_dead_visual = true
stop_travel_visual()
var tween := create_tween()
tween.set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN)
tween.tween_property(self, "scale", Vector3(0.001, 0.001, 0.001), 0.45)
tween.tween_callback(queue_free)
func stop_travel_visual() -> void:
pass
func _build_body(kind: StringName) -> void:
if kind == SimulationIds.COMBATANT_KIND_WOLF:
_build_wolf()
else:
_build_raider()
func _build_raider() -> void:
var tunic := StandardMaterial3D.new()
tunic.albedo_color = Color(0.4, 0.13, 0.1, 1.0)
tunic.roughness = 0.85
var skin := StandardMaterial3D.new()
skin.albedo_color = Color(0.8, 0.58, 0.36, 1.0)
skin.roughness = 0.9
var metal := StandardMaterial3D.new()
metal.albedo_color = Color(0.55, 0.55, 0.58, 1.0)
metal.roughness = 0.35
_add_mesh("Body", CylinderMesh.new(), Vector3(0.0, 1.1, 0.0), tunic)
_add_mesh("Head", SphereMesh.new(), Vector3(0.0, 1.7, 0.0), skin)
var blade := BoxMesh.new()
blade.size = Vector3(0.06, 0.72, 0.14)
_add_mesh("Sword", blade, Vector3(0.42, 1.25, 0.0), metal, Vector3(0.0, 0.0, -0.2))
var shield := CylinderMesh.new()
shield.top_radius = 0.3
shield.bottom_radius = 0.3
shield.height = 0.12
_add_mesh(
"Shield", shield, Vector3(-0.42, 1.15, 0.0), metal, Vector3.ZERO, Vector3(1.57, 0.0, 0.0)
)
func _build_wolf() -> void:
var fur := StandardMaterial3D.new()
fur.albedo_color = Color(0.32, 0.32, 0.34, 1.0)
fur.roughness = 0.95
var eye := StandardMaterial3D.new()
eye.albedo_color = Color(0.95, 0.5, 0.12, 1.0)
eye.roughness = 0.3
var body := SphereMesh.new()
body.radius = 0.34
body.height = 0.68
_add_mesh("Body", body, Vector3(0.0, 0.55, 0.0), fur, Vector3.ZERO, Vector3(1.57, 0.0, 0.0))
var head := SphereMesh.new()
head.radius = 0.2
head.height = 0.4
_add_mesh("Head", head, Vector3(0.0, 0.62, -0.42), fur, Vector3.ZERO, Vector3(1.57, 0.0, 0.0))
var tail := BoxMesh.new()
tail.size = Vector3(0.1, 0.1, 0.5)
_add_mesh("Tail", tail, Vector3(0.0, 0.72, 0.42), fur, Vector3(0.6, 0.0, 0.0))
var leg_mesh := CylinderMesh.new()
leg_mesh.top_radius = 0.06
leg_mesh.bottom_radius = 0.06
leg_mesh.height = 0.42
for leg_x in [-0.18, 0.18]:
for leg_z in [-0.2, 0.2]:
_add_mesh("Leg", leg_mesh, Vector3(leg_x, 0.21, leg_z), fur)
func _add_mesh(
node_name: String,
mesh: PrimitiveMesh,
local_position: Vector3,
material: Material,
rotation_offset: Vector3 = Vector3.ZERO,
mesh_rotation: Vector3 = Vector3.ZERO
) -> void:
var mesh_instance := MeshInstance3D.new()
mesh_instance.name = node_name
mesh_instance.mesh = mesh
mesh_instance.material_override = material
mesh_instance.position = local_position
if not rotation_offset.is_zero_approx():
mesh_instance.rotation = rotation_offset
if not mesh_rotation.is_zero_approx():
mesh_instance.rotation += mesh_rotation
add_child(mesh_instance)