Colours and practise dummy
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
extends BaseUnit
|
||||
class_name BaseEnemy
|
||||
|
||||
## Base class for all enemies in the game
|
||||
## Provides common enemy functionality like AI, pathfinding, and targeting
|
||||
|
||||
signal target_changed(new_target: Node)
|
||||
|
||||
## Current target (usually a player)
|
||||
var current_target: Node = null
|
||||
## Enemy detection/aggro range
|
||||
@export var detection_range: float = 10.0
|
||||
## Whether this enemy is aggressive (will attack players)
|
||||
@export var is_aggressive: bool = true
|
||||
|
||||
func _ready():
|
||||
super._ready()
|
||||
|
||||
# Enemies should respawn by default
|
||||
can_respawn = true
|
||||
|
||||
# Connect to health signals for AI reactions
|
||||
health_changed.connect(_on_enemy_health_changed)
|
||||
died.connect(_on_enemy_died)
|
||||
respawned.connect(_on_enemy_respawned)
|
||||
|
||||
func _physics_process(delta):
|
||||
# Only server handles enemy AI
|
||||
if not multiplayer.is_server():
|
||||
return
|
||||
|
||||
if is_dead:
|
||||
return
|
||||
|
||||
# Update target if needed
|
||||
_update_target()
|
||||
|
||||
## Find and update current target
|
||||
func _update_target():
|
||||
# Subclasses can override this to implement custom targeting logic
|
||||
pass
|
||||
|
||||
## Get all players in range
|
||||
func get_players_in_range(range_dist: float) -> Array[Node]:
|
||||
var players_in_range: Array[Node] = []
|
||||
|
||||
# Find the players container
|
||||
var level = get_tree().get_current_scene()
|
||||
if not level or not level.has_node("PlayersContainer"):
|
||||
return players_in_range
|
||||
|
||||
var players_container = level.get_node("PlayersContainer")
|
||||
|
||||
for player in players_container.get_children():
|
||||
if player is Character and not player.is_dead:
|
||||
var distance = global_position.distance_to(player.global_position)
|
||||
if distance <= range_dist:
|
||||
players_in_range.append(player)
|
||||
|
||||
return players_in_range
|
||||
|
||||
## Get nearest player
|
||||
func get_nearest_player() -> Node:
|
||||
var players = get_players_in_range(detection_range)
|
||||
|
||||
if players.is_empty():
|
||||
return null
|
||||
|
||||
var nearest_player = null
|
||||
var nearest_distance = INF
|
||||
|
||||
for player in players:
|
||||
var distance = global_position.distance_to(player.global_position)
|
||||
if distance < nearest_distance:
|
||||
nearest_distance = distance
|
||||
nearest_player = player
|
||||
|
||||
return nearest_player
|
||||
|
||||
## Health changed callback
|
||||
func _on_enemy_health_changed(old_health: float, new_health: float):
|
||||
# Subclasses can override to react to damage
|
||||
pass
|
||||
|
||||
## Death callback
|
||||
func _on_enemy_died(killer_id: int):
|
||||
print("[Enemy ", name, "] died. Killer ID: ", killer_id)
|
||||
|
||||
# Subclasses can override for death effects
|
||||
pass
|
||||
|
||||
## Respawn callback
|
||||
func _on_enemy_respawned():
|
||||
print("[Enemy ", name, "] respawned at ", global_position)
|
||||
|
||||
# Clear target on respawn
|
||||
current_target = null
|
||||
target_changed.emit(null)
|
||||
|
||||
# Subclasses can override for respawn effects
|
||||
pass
|
||||
|
||||
## Override hurt animation
|
||||
@rpc("any_peer", "call_local", "reliable")
|
||||
func _play_hurt_animation():
|
||||
# Flash red or play hurt animation
|
||||
# Subclasses should implement this with their specific animations
|
||||
pass
|
||||
Reference in New Issue
Block a user