From 85a4fc73819a3e65a445121e90134be24c424e19 Mon Sep 17 00:00:00 2001 From: Ruslan Ignatov Date: Sat, 15 Nov 2025 03:52:16 +0300 Subject: [PATCH] Added health bar --- .../ships/enemies/abstract_enemy_ship.tscn | 6 +- .../ships/enemies/heavy/heavy_enemy_ship.tscn | 3 + .../enemies/medium/medium_enemy_ship.tscn | 5 +- .../ships/enemies/small/small_enemy_ship.tscn | 5 +- game/entities/ships/player/player_ship.tscn | 7 ++- game/health_system/health.gd | 18 ++++++ .../health_bar/health_bar_part.gd | 60 +++++++++++++++++++ .../health_bar/health_bar_part.gd.uid | 1 + .../health_bar/health_bar_part.tscn | 48 +++++++++++++++ game/health_system/health_bar/heath_bar.gd | 26 ++++++++ .../health_system/health_bar/heath_bar.gd.uid | 1 + game/health_system/health_bar/heath_bar.tscn | 44 ++++++++++++++ images/health.png | 4 +- images/health.png.import | 40 +++++++++++++ 14 files changed, 258 insertions(+), 10 deletions(-) create mode 100644 game/health_system/health_bar/health_bar_part.gd create mode 100644 game/health_system/health_bar/health_bar_part.gd.uid create mode 100644 game/health_system/health_bar/health_bar_part.tscn create mode 100644 game/health_system/health_bar/heath_bar.gd create mode 100644 game/health_system/health_bar/heath_bar.gd.uid create mode 100644 game/health_system/health_bar/heath_bar.tscn create mode 100644 images/health.png.import diff --git a/game/entities/ships/enemies/abstract_enemy_ship.tscn b/game/entities/ships/enemies/abstract_enemy_ship.tscn index c6dd927..aa58ed2 100644 --- a/game/entities/ships/enemies/abstract_enemy_ship.tscn +++ b/game/entities/ships/enemies/abstract_enemy_ship.tscn @@ -1,8 +1,9 @@ -[gd_scene load_steps=4 format=3 uid="uid://dwsn0lf1e3578"] +[gd_scene load_steps=5 format=3 uid="uid://dwsn0lf1e3578"] [ext_resource type="PackedScene" uid="uid://jvyagshykmgb" path="res://game/entities/ships/abstract_ship.tscn" id="1_28j6l"] [ext_resource type="Script" uid="uid://byicf1t0807pq" path="res://game/entities/ships/enemies/abstract_enemy_ship.gd" id="2_fwvrd"] [ext_resource type="Script" uid="uid://bs8qqj6yepfln" path="res://game/controllers/enemy_controller.gd" id="3_vfnhw"] +[ext_resource type="PackedScene" uid="uid://d2snum2pxc2ui" path="res://game/health_system/health_bar/heath_bar.tscn" id="4_l8c0n"] [node name="AbstractEnemyShip" groups=["enemies"] instance=ExtResource("1_28j6l")] collision_layer = 4 @@ -13,6 +14,9 @@ script = ExtResource("2_fwvrd") script = ExtResource("3_vfnhw") metadata/_custom_type_script = "uid://bs8qqj6yepfln" +[node name="HeathBar" parent="." index="4" node_paths=PackedStringArray("health") instance=ExtResource("4_l8c0n")] +health = NodePath("../Health") + [connection signal="accelerate" from="EnemyController" to="." method="accelerate"] [connection signal="reload" from="EnemyController" to="." method="reload"] [connection signal="shoot" from="EnemyController" to="." method="shoot"] diff --git a/game/entities/ships/enemies/heavy/heavy_enemy_ship.tscn b/game/entities/ships/enemies/heavy/heavy_enemy_ship.tscn index 9964cc1..bf398c1 100644 --- a/game/entities/ships/enemies/heavy/heavy_enemy_ship.tscn +++ b/game/entities/ships/enemies/heavy/heavy_enemy_ship.tscn @@ -26,3 +26,6 @@ shape = SubResource("CapsuleShape2D_cuapu") [node name="Health" parent="." index="2"] max_hull = 200 + +[node name="HeathBar" parent="." index="4"] +position = Vector2(0, 30) diff --git a/game/entities/ships/enemies/medium/medium_enemy_ship.tscn b/game/entities/ships/enemies/medium/medium_enemy_ship.tscn index cf45ce5..f49b701 100644 --- a/game/entities/ships/enemies/medium/medium_enemy_ship.tscn +++ b/game/entities/ships/enemies/medium/medium_enemy_ship.tscn @@ -26,6 +26,5 @@ shape = SubResource("CapsuleShape2D_4jmkv") [node name="Health" parent="." index="2"] max_hull = 100 -[connection signal="accelerate" from="EnemyController" to="." method="accelerate"] -[connection signal="reload" from="EnemyController" to="." method="reload"] -[connection signal="shoot" from="EnemyController" to="." method="shoot"] +[node name="HeathBar" parent="." index="4"] +position = Vector2(0, 30) diff --git a/game/entities/ships/enemies/small/small_enemy_ship.tscn b/game/entities/ships/enemies/small/small_enemy_ship.tscn index bd6c3be..56a360f 100644 --- a/game/entities/ships/enemies/small/small_enemy_ship.tscn +++ b/game/entities/ships/enemies/small/small_enemy_ship.tscn @@ -26,6 +26,5 @@ shape = SubResource("CapsuleShape2D_lopve") [node name="Health" parent="." index="2"] max_hull = 50 -[connection signal="accelerate" from="EnemyController" to="." method="accelerate"] -[connection signal="reload" from="EnemyController" to="." method="reload"] -[connection signal="shoot" from="EnemyController" to="." method="shoot"] +[node name="HeathBar" parent="." index="4"] +position = Vector2(0, 14) diff --git a/game/entities/ships/player/player_ship.tscn b/game/entities/ships/player/player_ship.tscn index b923ec0..43761ea 100644 --- a/game/entities/ships/player/player_ship.tscn +++ b/game/entities/ships/player/player_ship.tscn @@ -1,8 +1,9 @@ -[gd_scene load_steps=6 format=3 uid="uid://br074cqcnul3d"] +[gd_scene load_steps=7 format=3 uid="uid://br074cqcnul3d"] [ext_resource type="PackedScene" uid="uid://jvyagshykmgb" path="res://game/entities/ships/abstract_ship.tscn" id="1_6otxb"] [ext_resource type="Script" uid="uid://ruxw1n03iq4i" path="res://game/entities/ships/player/player_ship.gd" id="2_625ti"] [ext_resource type="Script" uid="uid://dgevigih7owxd" path="res://game/controllers/player_controller.gd" id="3_dj8f1"] +[ext_resource type="PackedScene" uid="uid://d2snum2pxc2ui" path="res://game/health_system/health_bar/heath_bar.tscn" id="4_4mjo1"] [sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_dj8f1"] size = Vector2(48, 32) @@ -33,6 +34,10 @@ max_hull = 1000 script = ExtResource("3_dj8f1") metadata/_custom_type_script = "uid://dgevigih7owxd" +[node name="HeathBar" parent="." index="4" node_paths=PackedStringArray("health") instance=ExtResource("4_4mjo1")] +position = Vector2(0, 22) +health = NodePath("../Health") + [connection signal="accelerate" from="PlayerController" to="." method="accelerate"] [connection signal="reload" from="PlayerController" to="." method="reload"] [connection signal="shoot" from="PlayerController" to="." method="shoot"] diff --git a/game/health_system/health.gd b/game/health_system/health.gd index 91ab727..80dba06 100644 --- a/game/health_system/health.gd +++ b/game/health_system/health.gd @@ -2,6 +2,10 @@ class_name Health extends Node +signal shield_updated(value: int) +signal armor_updated(value: int) +signal hull_updated(value: int) + signal depleted @@ -10,6 +14,17 @@ signal depleted @export_range(1, 5000) var max_hull: int = 1 +var shield: int: + get: return _shield + set(value): pass +var armor: int: + get: return _armor + set(value): pass +var hull: int: + get: return _hull + set(value): pass + + @onready var _shield := max_shield @onready var _armor := max_armor @onready var _hull := max_hull @@ -19,14 +34,17 @@ func apply_damage(damage: AbstractDamage) -> void: if _shield > 0: var damage_value := ceili(damage.value * damage.shield_damage_multiplier()) _shield = max(_shield - damage_value, 0) + shield_updated.emit(_shield) elif _armor > 0: var damage_value := ceili(damage.value * damage.armor_damage_multiplier()) _armor = max(_armor - damage_value, 0) + armor_updated.emit(_armor) else: if _hull == 0: return var damage_value := ceili(damage.value * damage.hull_damage_multiplier()) _hull = max(_hull - damage_value, 0) + hull_updated.emit(_hull) if _hull == 0: depleted.emit() diff --git a/game/health_system/health_bar/health_bar_part.gd b/game/health_system/health_bar/health_bar_part.gd new file mode 100644 index 0000000..d821e6a --- /dev/null +++ b/game/health_system/health_bar/health_bar_part.gd @@ -0,0 +1,60 @@ +class_name HealthBarPart +extends Node2D + +@export var texture_value : Texture2D +@export var texture_shade : Texture2D + + +@onready var value_bar : TextureProgressBar = $ValueBar +@onready var shade_bar : TextureProgressBar = $ShadeBar + +@onready var shade_reset_timer : Timer = $ShadeResetTimer +@onready var shade_tick_timer : Timer = $ShadeTickTimer + + +const TICK_COUNT = 5 + + +var _tick_size : int = 0 +var _target_value: int = 0 + + +func _ready() -> void: + value_bar.texture_progress = texture_value + shade_bar.texture_progress = texture_shade + + +func set_value(value: int) -> void: + if value_bar.value == value: return + + value_bar.value = value + if shade_bar.value < value_bar.value: + shade_bar.value = value_bar.value + else: + shade_reset_timer.start() + + +func set_max_value(max_value: int) -> void: + value_bar.max_value = max_value + shade_bar.max_value = max_value + + if max_value == 0: + value_bar.hide() + shade_bar.hide() + else: + value_bar.show() + shade_bar.show() + + +func _on_shade_reset_timer_timeout() -> void: + var value_delta := shade_bar.value - value_bar.value + _tick_size = ceil(value_delta / TICK_COUNT) + _target_value = value_bar.value + shade_tick_timer.start() + + +func _on_shade_tick_timer_timeout() -> void: + shade_bar.value -= _tick_size + if shade_bar.value <= _target_value: + shade_bar.value = _target_value + shade_tick_timer.stop() diff --git a/game/health_system/health_bar/health_bar_part.gd.uid b/game/health_system/health_bar/health_bar_part.gd.uid new file mode 100644 index 0000000..61dc3d1 --- /dev/null +++ b/game/health_system/health_bar/health_bar_part.gd.uid @@ -0,0 +1 @@ +uid://drwgq8fxaclvn diff --git a/game/health_system/health_bar/health_bar_part.tscn b/game/health_system/health_bar/health_bar_part.tscn new file mode 100644 index 0000000..d68072e --- /dev/null +++ b/game/health_system/health_bar/health_bar_part.tscn @@ -0,0 +1,48 @@ +[gd_scene load_steps=4 format=3 uid="uid://xbfxsiumbgkp"] + +[ext_resource type="Script" uid="uid://drwgq8fxaclvn" path="res://game/health_system/health_bar/health_bar_part.gd" id="1_nuv67"] +[ext_resource type="Texture2D" uid="uid://do586oblhwuc5" path="res://images/health.png" id="2_jlvn5"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_jlvn5"] +atlas = ExtResource("2_jlvn5") +region = Rect2(0, 48, 32, 16) + +[node name="HealthBarPart" type="Node2D"] +script = ExtResource("1_nuv67") + +[node name="ShadeBar" type="TextureProgressBar" parent="."] +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -16.0 +offset_top = -8.0 +offset_right = 16.0 +offset_bottom = 8.0 +grow_horizontal = 2 +grow_vertical = 2 +texture_under = SubResource("AtlasTexture_jlvn5") + +[node name="ValueBar" type="TextureProgressBar" parent="."] +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -16.0 +offset_top = -8.0 +offset_right = 16.0 +offset_bottom = 8.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="ShadeResetTimer" type="Timer" parent="."] +wait_time = 0.5 +one_shot = true + +[node name="ShadeTickTimer" type="Timer" parent="."] +wait_time = 0.1 + +[connection signal="timeout" from="ShadeResetTimer" to="." method="_on_shade_reset_timer_timeout"] +[connection signal="timeout" from="ShadeTickTimer" to="." method="_on_shade_tick_timer_timeout"] diff --git a/game/health_system/health_bar/heath_bar.gd b/game/health_system/health_bar/heath_bar.gd new file mode 100644 index 0000000..6ee7b4b --- /dev/null +++ b/game/health_system/health_bar/heath_bar.gd @@ -0,0 +1,26 @@ +class_name HealthBar +extends Node2D + + +@export var health: Health + + +@onready var shield_part : HealthBarPart = $ShieldPart +@onready var armor_part : HealthBarPart = $ArmorPart +@onready var hull_part : HealthBarPart = $HullPart + + +func _ready() -> void: + if health: + shield_part.set_max_value(health.max_shield) + shield_part.set_value(health.shield) + + armor_part.set_max_value(health.max_armor) + armor_part.set_value(health.armor) + + hull_part.set_max_value(health.max_hull) + hull_part.set_value(health.hull) + + health.shield_updated.connect(shield_part.set_value) + health.armor_updated.connect(armor_part.set_value) + health.hull_updated.connect(hull_part.set_value) diff --git a/game/health_system/health_bar/heath_bar.gd.uid b/game/health_system/health_bar/heath_bar.gd.uid new file mode 100644 index 0000000..bcb26dd --- /dev/null +++ b/game/health_system/health_bar/heath_bar.gd.uid @@ -0,0 +1 @@ +uid://be7k64p2kel8b diff --git a/game/health_system/health_bar/heath_bar.tscn b/game/health_system/health_bar/heath_bar.tscn new file mode 100644 index 0000000..6b41767 --- /dev/null +++ b/game/health_system/health_bar/heath_bar.tscn @@ -0,0 +1,44 @@ +[gd_scene load_steps=10 format=3 uid="uid://d2snum2pxc2ui"] + +[ext_resource type="Script" uid="uid://be7k64p2kel8b" path="res://game/health_system/health_bar/heath_bar.gd" id="1_bx561"] +[ext_resource type="PackedScene" uid="uid://xbfxsiumbgkp" path="res://game/health_system/health_bar/health_bar_part.tscn" id="2_wb6me"] +[ext_resource type="Texture2D" uid="uid://do586oblhwuc5" path="res://images/health.png" id="3_fogsl"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_wb6me"] +atlas = ExtResource("3_fogsl") +region = Rect2(0, 0, 32, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_fogsl"] +atlas = ExtResource("3_fogsl") +region = Rect2(32, 0, 32, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_b6cw0"] +atlas = ExtResource("3_fogsl") +region = Rect2(0, 16, 32, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_w8ken"] +atlas = ExtResource("3_fogsl") +region = Rect2(32, 16, 32, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_lfh3j"] +atlas = ExtResource("3_fogsl") +region = Rect2(0, 32, 32, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_lc4fa"] +atlas = ExtResource("3_fogsl") +region = Rect2(32, 32, 32, 16) + +[node name="HeathBar" type="Node2D"] +script = ExtResource("1_bx561") + +[node name="HullPart" parent="." instance=ExtResource("2_wb6me")] +texture_value = SubResource("AtlasTexture_wb6me") +texture_shade = SubResource("AtlasTexture_fogsl") + +[node name="ArmorPart" parent="." instance=ExtResource("2_wb6me")] +texture_value = SubResource("AtlasTexture_b6cw0") +texture_shade = SubResource("AtlasTexture_w8ken") + +[node name="ShieldPart" parent="." instance=ExtResource("2_wb6me")] +texture_value = SubResource("AtlasTexture_lfh3j") +texture_shade = SubResource("AtlasTexture_lc4fa") diff --git a/images/health.png b/images/health.png index 7863816..8d63d57 100644 --- a/images/health.png +++ b/images/health.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bc0d8941c1efc9bc1c5bdc7da440b79865be2d7714569aa1797a7923d531b57f -size 210 +oid sha256:4223d6a26db0dd345433e752f685b3d0974cceda015aae853bd3a71e50655c00 +size 231 diff --git a/images/health.png.import b/images/health.png.import new file mode 100644 index 0000000..f35201a --- /dev/null +++ b/images/health.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://do586oblhwuc5" +path="res://.godot/imported/health.png-825db86ed00488748bab7a5690a96891.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://images/health.png" +dest_files=["res://.godot/imported/health.png-825db86ed00488748bab7a5690a96891.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1