This commit is contained in:
Marek Le
2026-03-29 22:58:23 +02:00
parent b9ed399d34
commit 80a65fa555
19 changed files with 217 additions and 58 deletions

View File

@@ -5,6 +5,7 @@ enum State { IDLE, CHASE, ATTACK, RETURN }
var state: int = State.IDLE
var target: Node3D = null
var spawn_position: Vector3
var portal: Node3D = null
var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity")
@onready var health: Node = $Health
@@ -12,6 +13,7 @@ var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity")
func _ready() -> void:
spawn_position = global_position
add_to_group("enemies")
add_to_group("targetable")
EventBus.entity_died.connect(_on_entity_died)
func _on_entity_died(entity: Node) -> void:
@@ -39,7 +41,7 @@ func _engage(new_target: Node3D) -> void:
func _alert_nearby() -> void:
var enemies := get_tree().get_nodes_in_group("enemies")
for enemy in enemies:
if enemy != self and is_instance_valid(enemy):
if enemy != self and is_instance_valid(enemy) and "state" in enemy:
if enemy.state == enemy.State.IDLE:
var dist: float = global_position.distance_to(enemy.global_position)
if dist <= 3.0:

View File

@@ -1,7 +1,9 @@
extends Node
const AGGRO_DECAY := 1.0
const PORTAL_RADIUS := 10.0
var aggro_table: Dictionary = {}
var seconds_outside := 0.0
@onready var enemy: CharacterBody3D = get_parent()
@@ -10,15 +12,32 @@ func _ready() -> void:
EventBus.entity_died.connect(_on_entity_died)
func _process(delta: float) -> void:
var outside_portal := false
if enemy.portal and is_instance_valid(enemy.portal):
var dist_to_portal: float = enemy.global_position.distance_to(enemy.portal.global_position)
if dist_to_portal > PORTAL_RADIUS:
outside_portal = true
seconds_outside += delta
else:
seconds_outside = 0.0
for player in aggro_table.keys():
aggro_table[player] -= AGGRO_DECAY * delta
var decay: float = AGGRO_DECAY * delta
if outside_portal:
var bonus_decay: float = aggro_table[player] * 0.01 * pow(2, seconds_outside) * delta
decay += bonus_decay
aggro_table[player] -= decay
if aggro_table[player] <= 0:
aggro_table.erase(player)
var top_target: Node = _get_top_target()
if top_target and top_target != enemy.target:
enemy.target = top_target
if enemy.state == enemy.State.IDLE or enemy.state == enemy.State.RETURN:
enemy.state = enemy.State.CHASE
elif not top_target and enemy.state != enemy.State.IDLE and enemy.state != enemy.State.RETURN:
enemy.target = null
enemy.state = enemy.State.RETURN
func _on_damage_dealt(attacker: Node, target: Node, amount: float) -> void:
if target != enemy:

View File

@@ -1,34 +0,0 @@
extends Sprite3D
@onready var viewport: SubViewport = $SubViewport
@onready var health_bar: ProgressBar = $SubViewport/HealthBar
@onready var shield_bar: ProgressBar = $SubViewport/ShieldBar
@onready var border: ColorRect = $SubViewport/Border
@onready var health: Node = get_parent().get_node("Health")
@onready var shield: Node = get_parent().get_node("Shield")
@onready var enemy: CharacterBody3D = get_parent()
var style_normal: StyleBoxFlat
var style_aggro: StyleBoxFlat
func _ready() -> void:
texture = viewport.get_texture()
health_bar.max_value = health.max_health
shield_bar.max_value = shield.max_shield
border.visible = false
style_normal = health_bar.get_theme_stylebox("fill").duplicate()
style_aggro = style_normal.duplicate()
style_aggro.bg_color = Color(0.2, 0.4, 0.9, 1)
EventBus.target_changed.connect(_on_target_changed)
func _process(_delta: float) -> void:
health_bar.value = health.current_health
shield_bar.value = shield.current_shield
var player: Node = get_tree().get_first_node_in_group("player")
if player and enemy.target == player:
health_bar.add_theme_stylebox_override("fill", style_aggro)
else:
health_bar.add_theme_stylebox_override("fill", style_normal)
func _on_target_changed(_player: Node, target: Node) -> void:
border.visible = (target == get_parent())

View File

@@ -1 +0,0 @@
uid://dwqx03nfypa7u

View File

@@ -1,13 +1,14 @@
extends Node
const SPEED := 3.0
const LEASH_RANGE := 15.0
const ATTACK_RANGE := 2.0
const REGEN_FAST := 0.10
const REGEN_SLOW := 0.01
@onready var enemy: CharacterBody3D = get_parent()
@onready var nav_agent: NavigationAgent3D = get_parent().get_node("NavigationAgent3D")
func _physics_process(_delta: float) -> void:
func _physics_process(delta: float) -> void:
match enemy.state:
enemy.State.IDLE:
enemy.velocity.x = 0
@@ -15,17 +16,12 @@ func _physics_process(_delta: float) -> void:
enemy.State.CHASE:
_chase()
enemy.State.RETURN:
_return_to_spawn()
_return_to_spawn(delta)
func _chase() -> void:
if not is_instance_valid(enemy.target):
enemy.state = enemy.State.RETURN
return
var dist_to_spawn := enemy.global_position.distance_to(enemy.spawn_position)
if dist_to_spawn > LEASH_RANGE:
enemy.state = enemy.State.RETURN
enemy.target = null
return
var dist_to_target := enemy.global_position.distance_to(enemy.target.global_position)
if dist_to_target <= ATTACK_RANGE:
enemy.state = enemy.State.ATTACK
@@ -37,7 +33,7 @@ func _chase() -> void:
enemy.velocity.x = direction.x * SPEED
enemy.velocity.z = direction.z * SPEED
func _return_to_spawn() -> void:
func _return_to_spawn(delta: float) -> void:
var dist := enemy.global_position.distance_to(enemy.spawn_position)
if dist < 1.0:
enemy.state = enemy.State.IDLE
@@ -50,3 +46,13 @@ func _return_to_spawn() -> void:
direction.y = 0
enemy.velocity.x = direction.x * SPEED
enemy.velocity.z = direction.z * SPEED
_regenerate(delta)
func _regenerate(delta: float) -> void:
var health: Node = enemy.get_node("Health")
if health.current_health < health.max_health:
var rate: float = REGEN_FAST if health.current_health < health.max_health else REGEN_SLOW
if health.current_health >= health.max_health * 0.99:
rate = REGEN_SLOW
health.current_health = min(health.current_health + health.max_health * rate * delta, health.max_health)
EventBus.health_changed.emit(enemy, health.current_health, health.max_health)