SchildDerStaerke/scripts/enemy.gd

100 lines
2.7 KiB
GDScript

extends Unit
class_name Enemy
@export var player: Player
@export var chasing_range := 30.0
@export var attack_range := 3.0
@export var enemy_reward_gold = 100
@export var attacks := ["Unarmed_Melee_Attack_Punch_A", "Unarmed_Melee_Attack_Punch_B", "Unarmed_Melee_Attack_Kick"]
const ANIM_IWR_PARAM := "parameters/IWR/blend_position"
@onready var navigation_agent: NavigationAgent3D = $NavigationAgent3D
func _ready() -> void:
health = maximum_health
stamina = maximum_stamina
reward_gold = enemy_reward_gold
state_changed.connect(_on_state_changed)
func _physics_process(delta: float) -> void:
# Guards
if state == States.dead or player == null:
return
if player.state == States.dead:
state = States.idle
return
# Apply gravity
velocity.y += -gravity * delta
# Zustandsableitung
var distance_to_player := global_position.distance_to(player.global_position)
var desired_state := _determine_state(distance_to_player)
if desired_state != state:
state = desired_state
# Navigation immer auf Spieler ausrichten
navigation_agent.set_target_position(player.global_position)
# Bewegungs-Update je nach Zustand
match state:
States.chasing:
_update_chasing_navigation()
States.attacking, States.idle:
_stop_horizontal_movement()
_:
pass
move_and_slide()
func _determine_state(distance: float) -> States:
if distance <= attack_range:
return States.attacking
elif distance <= chasing_range:
return States.chasing
else:
return States.idle
func _update_chasing_navigation() -> void:
if navigation_agent.is_navigation_finished() or navigation_agent.is_target_reached():
_stop_horizontal_movement()
return
var next_path_position: Vector3 = navigation_agent.get_next_path_position()
# Prüfen, ob die Position unterschiedlich ist, bevor look_at aufgerufen wird
if not model.global_position.is_equal_approx(next_path_position):
model.look_at(next_path_position, Vector3.UP)
# Nur horizontale Bewegung steuern, vertikale Komponente beibehalten
var to_next := next_path_position - global_position
to_next.y = 0.0
var desired := to_next.normalized() * speed
var vy := velocity.y
velocity.x = desired.x
velocity.z = desired.z
velocity.y = vy
# Animation (IWR) nach lokaler Geschwindigkeit blenden
var v_local: Vector3 = velocity * model.transform.basis
anim_tree.set(ANIM_IWR_PARAM, Vector2(v_local.x, -v_local.z) / speed)
func _stop_horizontal_movement() -> void:
var vy := velocity.y
velocity = Vector3.ZERO
velocity.y = vy
func _on_state_changed(_old_state: States, new_state: States) -> void:
name_changed.emit(unit_name, States.keys()[new_state])
match new_state:
States.attacking:
if can_spend_stamina(attack_cost):
spend_stamina(attack_cost)
if attacks.size() > 0:
anim_state.travel(attacks.pick_random())