Files
mmo/systems/ai_system.gd
Marek Lenczewski f1d34ebf1d update
2026-04-04 00:00:15 +02:00

92 lines
3.4 KiB
GDScript

extends Node
enum State { IDLE, CHASE, ATTACK, RETURN }
func _physics_process(delta: float) -> void:
_process_group(delta, EnemyData)
_process_group(delta, BossData)
func _process_group(delta: float, data_source: Node) -> void:
for entity in data_source.entities:
if not is_instance_valid(entity) or not data_source.is_alive(entity):
continue
var data: Dictionary = data_source.entities[entity]
var state: int = data["state"]
match state:
State.IDLE:
entity.velocity.x = 0
entity.velocity.z = 0
State.CHASE:
_chase(entity, data, data_source)
State.ATTACK:
_attack(entity, data, data_source, delta)
State.RETURN:
_return_to_spawn(entity, data, data_source, delta)
func _chase(entity: Node, data: Dictionary, data_source: Node) -> void:
if not is_instance_valid(data["target"]):
data["state"] = State.RETURN
return
var base: EnemyStats = data_source.get_base(entity)
var attack_range: float = base.attack_range
var dist: float = entity.global_position.distance_to(data["target"].global_position)
if dist <= attack_range:
data["state"] = State.ATTACK
return
var nav_agent: NavigationAgent3D = entity.get_node_or_null("NavigationAgent3D")
if not nav_agent:
return
nav_agent.target_position = data["target"].global_position
var next_pos := nav_agent.get_next_path_position()
var direction: Vector3 = (next_pos - entity.global_position).normalized()
direction.y = 0
entity.velocity.x = direction.x * base.speed
entity.velocity.z = direction.z * base.speed
func _attack(entity: Node, data: Dictionary, data_source: Node, delta: float) -> void:
data["attack_timer"] -= delta
if not is_instance_valid(data["target"]):
data["state"] = State.RETURN
return
var base: EnemyStats = data_source.get_base(entity)
var dist: float = entity.global_position.distance_to(data["target"].global_position)
if dist > base.attack_range:
data["state"] = State.CHASE
return
if data["attack_timer"] <= 0:
data["attack_timer"] = base.attack_cooldown
EventBus.damage_requested.emit(entity, data["target"], base.attack_damage)
entity.velocity.x = 0
entity.velocity.z = 0
func _return_to_spawn(entity: Node, data: Dictionary, data_source: Node, delta: float) -> void:
var spawn_pos: Vector3 = data["spawn_position"]
var dist: float = entity.global_position.distance_to(spawn_pos)
if dist < 1.0:
data["state"] = State.IDLE
entity.velocity.x = 0
entity.velocity.z = 0
return
var base: EnemyStats = data_source.get_base(entity)
var nav_agent: NavigationAgent3D = entity.get_node_or_null("NavigationAgent3D")
if not nav_agent:
return
nav_agent.target_position = spawn_pos
var next_pos := nav_agent.get_next_path_position()
var direction: Vector3 = (next_pos - entity.global_position).normalized()
direction.y = 0
entity.velocity.x = direction.x * base.speed
entity.velocity.z = direction.z * base.speed
_regenerate(entity, data, data_source, delta)
func _regenerate(entity: Node, data: Dictionary, data_source: Node, delta: float) -> void:
var health: float = data["health"]
var max_health: float = data["max_health"]
if health < max_health:
var base: EnemyStats = data_source.get_base(entity)
var rate: float = base.regen_fast
if health >= max_health * 0.99:
rate = base.regen_slow
health = min(health + max_health * rate * delta, max_health)
data_source.set_health(entity, health)