88 lines
3.6 KiB
GDScript
88 lines
3.6 KiB
GDScript
extends Node3D
|
||
class_name EnemyHealthBar
|
||
|
||
# Скрипт для отображения полоски здоровья над врагом
|
||
|
||
@onready var background_bar: MeshInstance3D = $BackgroundBar
|
||
@onready var health_bar: MeshInstance3D = $HealthBar
|
||
|
||
var unit: Unit = null
|
||
var bar_width: float = 3.0
|
||
var bar_height: float = 0.2
|
||
|
||
func _ready():
|
||
# Находим родительский Unit (враг)
|
||
unit = get_parent() as Unit
|
||
if unit:
|
||
# Подключаемся к сигналу изменения здоровья
|
||
unit.health_changed.connect(_on_health_changed)
|
||
# Изначально скрываем полоску (если здоровье 100%)
|
||
update_visibility()
|
||
update_health_bar()
|
||
else:
|
||
print("EnemyHealthBar: Не найден Unit!")
|
||
|
||
# Убеждаемся, что узлы найдены
|
||
if not background_bar:
|
||
print("EnemyHealthBar: Не найден BackgroundBar!")
|
||
if not health_bar:
|
||
print("EnemyHealthBar: Не найден HealthBar!")
|
||
|
||
func _process(_delta):
|
||
# Поворачиваем полоску к камере
|
||
var camera = get_viewport().get_camera_3d()
|
||
if camera and visible:
|
||
# BoxMesh по умолчанию ориентирован правильно
|
||
# Поворачиваем полоску так, чтобы она была обращена к камере
|
||
# Используем только горизонтальный поворот (по оси Y), чтобы полоска оставалась горизонтальной
|
||
var direction_to_camera = (camera.global_position - global_position).normalized()
|
||
if direction_to_camera.length() > 0.01:
|
||
var horizontal_direction = direction_to_camera
|
||
horizontal_direction.y = 0
|
||
horizontal_direction = horizontal_direction.normalized()
|
||
if horizontal_direction.length() > 0.01:
|
||
# Поворачиваем только по оси Y
|
||
var angle = atan2(horizontal_direction.x, horizontal_direction.z)
|
||
rotation.y = angle
|
||
|
||
# Обновляем полоску после поворота (чтобы позиция была правильной)
|
||
if unit:
|
||
update_health_bar()
|
||
|
||
func _on_health_changed(new_health: float):
|
||
update_health_bar()
|
||
update_visibility()
|
||
|
||
func update_health_bar():
|
||
if not unit or not health_bar:
|
||
return
|
||
|
||
var health_percent = clamp(unit.health / unit.max_health, 0.0, 1.0)
|
||
|
||
# Масштабируем полоску здоровья в зависимости от процента
|
||
# Убеждаемся, что масштаб всегда положительный и достаточно большой для видимости
|
||
var scale_x = max(health_percent, 0.05) # Минимум 0.05 для лучшей видимости
|
||
health_bar.scale.x = scale_x
|
||
|
||
# Смещаем полоску влево, чтобы она уменьшалась справа налево
|
||
# Используем локальные координаты относительно центра
|
||
# Центр полоски должен быть в центре, поэтому смещаем на половину разницы
|
||
var offset = -(bar_width * (1.0 - health_percent)) / 2.0
|
||
health_bar.position.x = offset
|
||
# Убеждаемся, что зеленая полоска немного впереди красной для правильного отображения
|
||
health_bar.position.z = 0.01
|
||
|
||
func update_visibility():
|
||
if not unit:
|
||
visible = false
|
||
return
|
||
|
||
# Показываем полоску только если здоровье меньше 100%
|
||
var should_show = unit.health < unit.max_health
|
||
visible = should_show
|
||
if background_bar:
|
||
background_bar.visible = should_show
|
||
if health_bar:
|
||
health_bar.visible = should_show
|
||
|