Trap explosions with damage and health bar depletion.

This commit is contained in:
2025-12-29 15:03:05 -05:00
parent e632e54cba
commit 84bf495d11
16 changed files with 149 additions and 30 deletions

Binary file not shown.

View File

@@ -0,0 +1,24 @@
[remap]
importer="wav"
type="AudioStreamWAV"
uid="uid://cw0mfvl76lpxq"
path="res://.godot/imported/explosion_large_01_n.wav-0f4fe3d8d9d02bb99f06e621d264e4e7.sample"
[deps]
source_file="res://audio/sounds/explosion_large_01_n.wav"
dest_files=["res://.godot/imported/explosion_large_01_n.wav-0f4fe3d8d9d02bb99f06e621d264e4e7.sample"]
[params]
force/8_bit=false
force/mono=false
force/max_rate=false
force/max_rate_hz=44100
edit/trim=false
edit/normalize=false
edit/loop_mode=0
edit/loop_begin=0
edit/loop_end=-1
compress/mode=2

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -47,9 +47,8 @@ var disarming : bool
var difficulty : int = 1 var difficulty : int = 1
func _process(delta: float) -> void: func _process(delta: float) -> void:
timer_label.text = "%02d.3" % timer.time_left timer_label.text = "%02f.3" % timer.time_left
func start_disarming() -> void: func start_disarming() -> void:
disarming = true disarming = true

15
scripts/healthbar.gd Normal file
View File

@@ -0,0 +1,15 @@
class_name HealthBar extends TextureProgressBar
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
pass
func _on_health_changed(current : int, max : int) -> void:
max_value = max
value = current

1
scripts/healthbar.gd.uid Normal file
View File

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

View File

@@ -1,11 +1,12 @@
class_name HUD extends Control class_name HUD extends Control
@onready var trap_display : TrapDisplay = %TrapDisplay @onready var trap_display : TrapDisplay = %TrapDisplay
@onready var p1_healthbar : HealthBar = %P1HealthBar
func _ready() -> void: func _ready() -> void:
Game.hud = self Game.hud = self
func register_player(player : Player) -> void: func register_player(player : Player) -> void:
player.health_changed.connect(p1_healthbar._on_health_changed)
trap_display._on_trap_list_changed(player.data.traps, player.data.active_trap) trap_display._on_trap_list_changed(player.data.traps, player.data.active_trap)
player.trap_cycled.connect(trap_display._on_trap_cycled) player.trap_cycled.connect(trap_display._on_trap_cycled)
player.trap_quantity_changed.connect(trap_display._on_trap_quantity_changed) player.trap_quantity_changed.connect(trap_display._on_trap_quantity_changed)

View File

@@ -9,6 +9,8 @@ const disarm_trap_modal = preload("res://templates/disarm_trap_modal.tscn")
@onready var data : PlayerData = $Data @onready var data : PlayerData = $Data
@onready var trap_sound : AudioStreamPlayer3D = $TrapSound @onready var trap_sound : AudioStreamPlayer3D = $TrapSound
var id : int = 1
var button_actions : Dictionary[int, String] var button_actions : Dictionary[int, String]
var current_square : Vector3i var current_square : Vector3i
var detecting : bool = false var detecting : bool = false
@@ -22,7 +24,7 @@ var modal = null
signal trap_cycled(trap_index) signal trap_cycled(trap_index)
signal trap_quantity_changed(trap_index, quantity) signal trap_quantity_changed(trap_index, quantity)
signal trap_list_changed(traps) signal trap_list_changed(traps)
signal health_changed(current : int, max : int)
func _physics_process(delta: float) -> void: func _physics_process(delta: float) -> void:
var dir = Input.get_vector("west", "east", "north", "south") var dir = Input.get_vector("west", "east", "north", "south")
@@ -156,6 +158,9 @@ func show_disarm_trap_modal() -> void:
modal = disarm_trap_modal.instantiate() modal = disarm_trap_modal.instantiate()
modal.difficulty = Game.level.difficulty modal.difficulty = Game.level.difficulty
modal.square = current_square modal.square = current_square
var trap = Game.level.traps[current_square]
trap.disarming = true
trap.disarm_id = Multiplayer.id
Game.level.add_child(modal) Game.level.add_child(modal)
func start_detecting() -> void: func start_detecting() -> void:
@@ -216,6 +221,10 @@ func cycle_active_trap(dir) -> void:
if prev != data.active_trap: if prev != data.active_trap:
trap_cycled.emit(data.active_trap) trap_cycled.emit(data.active_trap)
func hurt(damage : int) -> void:
data.life = max(0, data.life - damage)
health_changed.emit(data.life, data.max_life)
func _on_trap_disarmed(type : Trap.Type) -> void: func _on_trap_disarmed(type : Trap.Type) -> void:
for i in range(len(data.traps)): for i in range(len(data.traps)):
var d = data.traps[i] var d = data.traps[i]

View File

@@ -59,6 +59,10 @@ func is_valid_trap_square(crd : Vector3i) -> bool:
return false return false
return true return true
func add_vfx(vfx, crd : Vector3i) -> void:
vfx.global_position = Vector3(crd) #+ Vector3(0.5, 0, 0.5)
add_child(vfx)
func activate_trap(crd : Vector3i) -> void: func activate_trap(crd : Vector3i) -> void:
var trap = traps[crd] var trap = traps[crd]
#if trap: #if trap:

View File

@@ -9,6 +9,14 @@ enum Type{
PITFALL PITFALL
} }
const range_shapes : Dictionary = {
Trap.Type.BOMB : Vector3(5,1,5),
Trap.Type.GAS : Vector3(1,1,1),
Trap.Type.PITFALL : Vector3(1,1,1),
Trap.Type.FORCE_PANEL : Vector3(1,1,1),
Trap.Type.SWITCH : Vector3(3,1,3),
Trap.Type.MINE : Vector3(5,1,5),
}
const trap_icons : Dictionary = { const trap_icons : Dictionary = {
Trap.Type.BOMB : preload("res://visuals/images/icons/t-bomb.png"), Trap.Type.BOMB : preload("res://visuals/images/icons/t-bomb.png"),
Trap.Type.GAS : preload("res://visuals/images/icons/t-gas.png"), Trap.Type.GAS : preload("res://visuals/images/icons/t-gas.png"),
@@ -18,6 +26,10 @@ const trap_icons : Dictionary = {
Trap.Type.MINE : preload("res://visuals/images/icons/t-mine.png"), Trap.Type.MINE : preload("res://visuals/images/icons/t-mine.png"),
} }
const explosion_template = preload("res://templates/explosion.tscn")
@onready var range_area : Area3D = %RangeArea
@onready var range_shape : BoxShape3D = %RangeShape.shape
@onready var model : MeshInstance3D = %Model @onready var model : MeshInstance3D = %Model
@onready var icon : Sprite3D = %Icon @onready var icon : Sprite3D = %Icon
@onready var material : StandardMaterial3D = model.get_surface_override_material(0) @onready var material : StandardMaterial3D = model.get_surface_override_material(0)
@@ -25,6 +37,12 @@ const trap_icons : Dictionary = {
var type : Type var type : Type
var square : Vector3i var square : Vector3i
var trap_owner : int var trap_owner : int
var disarming : bool
var disarm_id : int
var damage : int = 10
signal disarmed(type : Trap.Type) signal disarmed(type : Trap.Type)
@@ -51,4 +69,17 @@ func _ready() -> void:
icon.texture = trap_icons[type] icon.texture = trap_icons[type]
model.visible = owns_trap model.visible = owns_trap
icon.visible = owns_trap icon.visible = owns_trap
range_shape.size = range_shapes[type]
material.albedo_color = Color.YELLOW if owns_trap else Color.RED material.albedo_color = Color.YELLOW if owns_trap else Color.RED
func activate() -> void:
var exp = explosion_template.instantiate()
Game.level.add_vfx(exp, square)
for body in range_area.get_overlapping_bodies():
body.hurt(damage)
#match(type):
func _on_body_entered(body: Node3D) -> void:
if !disarming or body.id != disarm_id:
if !body.detecting:
activate()

View File

@@ -9,3 +9,12 @@ func _ready() -> void:
func _on_timer_timeout() -> void: func _on_timer_timeout() -> void:
print("Done") print("Done")
queue_free() queue_free()
func proximal_shake(distance : float) -> void:
print(Input.get_connected_joypads())
if !Game.player:
return
var d = global_position.distance_squared_to(Game.player.global_position)
if d <= distance * distance:
Input.start_joy_vibration(0, 1,1,1000)

View File

@@ -1,4 +1,4 @@
[gd_scene load_steps=30 format=3 uid="uid://bgocskbofewsr"] [gd_scene load_steps=31 format=3 uid="uid://bgocskbofewsr"]
[ext_resource type="Script" uid="uid://bm50jiya4s3ei" path="res://scripts/hud.gd" id="1_jiiqi"] [ext_resource type="Script" uid="uid://bm50jiya4s3ei" path="res://scripts/hud.gd" id="1_jiiqi"]
[ext_resource type="Texture2D" uid="uid://dri0a20l6kpbj" path="res://visuals/images/icon.svg" id="1_k5de2"] [ext_resource type="Texture2D" uid="uid://dri0a20l6kpbj" path="res://visuals/images/icon.svg" id="1_k5de2"]
@@ -11,6 +11,7 @@
[ext_resource type="Texture2D" uid="uid://btjn353r1qg1q" path="res://visuals/images/icons/player 2 tag.png" id="3_k0acs"] [ext_resource type="Texture2D" uid="uid://btjn353r1qg1q" path="res://visuals/images/icons/player 2 tag.png" id="3_k0acs"]
[ext_resource type="Texture2D" uid="uid://urh11huy67cs" path="res://visuals/materials/health gradient.tres" id="3_vhta5"] [ext_resource type="Texture2D" uid="uid://urh11huy67cs" path="res://visuals/materials/health gradient.tres" id="3_vhta5"]
[ext_resource type="PackedScene" uid="uid://xk323c0ta2b" path="res://templates/trap_icon.tscn" id="4_aopqe"] [ext_resource type="PackedScene" uid="uid://xk323c0ta2b" path="res://templates/trap_icon.tscn" id="4_aopqe"]
[ext_resource type="Script" uid="uid://bolw6n14ocxt3" path="res://scripts/healthbar.gd" id="4_iv5le"]
[ext_resource type="Texture2D" uid="uid://bcv3f38cib5xk" path="res://visuals/images/icons/mine.png" id="4_l86lr"] [ext_resource type="Texture2D" uid="uid://bcv3f38cib5xk" path="res://visuals/images/icons/mine.png" id="4_l86lr"]
[ext_resource type="Texture2D" uid="uid://cyuylbs0o72xk" path="res://visuals/images/icons/pitfall.png" id="5_aopqe"] [ext_resource type="Texture2D" uid="uid://cyuylbs0o72xk" path="res://visuals/images/icons/pitfall.png" id="5_aopqe"]
[ext_resource type="Texture2D" uid="uid://hiwrcar5fnyk" path="res://visuals/images/icons/switch.png" id="6_e7ody"] [ext_resource type="Texture2D" uid="uid://hiwrcar5fnyk" path="res://visuals/images/icons/switch.png" id="6_e7ody"]
@@ -79,12 +80,14 @@ theme_override_constants/separation = 2
layout_mode = 2 layout_mode = 2
texture = ExtResource("2_yda1o") texture = ExtResource("2_yda1o")
[node name="ProgressBar" type="TextureProgressBar" parent="Control/PanelContainer/HBoxContainer/VBoxContainer2/PanelContainer/VBoxContainer"] [node name="P1HealthBar" type="TextureProgressBar" parent="Control/PanelContainer/HBoxContainer/VBoxContainer2/PanelContainer/VBoxContainer"]
unique_name_in_owner = true
custom_minimum_size = Vector2(0, 50) custom_minimum_size = Vector2(0, 50)
layout_mode = 2 layout_mode = 2
value = 100.0 value = 100.0
nine_patch_stretch = true nine_patch_stretch = true
texture_over = ExtResource("3_vhta5") texture_progress = ExtResource("3_vhta5")
script = ExtResource("4_iv5le")
[node name="PanelContainer2" type="PanelContainer" parent="Control/PanelContainer/HBoxContainer/VBoxContainer2"] [node name="PanelContainer2" type="PanelContainer" parent="Control/PanelContainer/HBoxContainer/VBoxContainer2"]
custom_minimum_size = Vector2(250, 100) custom_minimum_size = Vector2(250, 100)
@@ -98,12 +101,12 @@ theme_override_constants/separation = 2
layout_mode = 2 layout_mode = 2
texture = ExtResource("3_k0acs") texture = ExtResource("3_k0acs")
[node name="ProgressBar" type="TextureProgressBar" parent="Control/PanelContainer/HBoxContainer/VBoxContainer2/PanelContainer2/VBoxContainer"] [node name="P2HealthBar" type="TextureProgressBar" parent="Control/PanelContainer/HBoxContainer/VBoxContainer2/PanelContainer2/VBoxContainer"]
custom_minimum_size = Vector2(0, 50) custom_minimum_size = Vector2(0, 50)
layout_mode = 2 layout_mode = 2
value = 100.0 value = 100.0
nine_patch_stretch = true nine_patch_stretch = true
texture_over = ExtResource("3_vhta5") texture_progress = ExtResource("3_vhta5")
[node name="VBoxContainer" type="VBoxContainer" parent="Control/PanelContainer/HBoxContainer"] [node name="VBoxContainer" type="VBoxContainer" parent="Control/PanelContainer/HBoxContainer"]
custom_minimum_size = Vector2(150, 0) custom_minimum_size = Vector2(150, 0)

View File

@@ -157,7 +157,6 @@ size = Vector2(0.25, 1)
center_offset = Vector3(0, 0.4, 0) center_offset = Vector3(0, 0.4, 0)
[sub_resource type="Animation" id="Animation_d5gho"] [sub_resource type="Animation" id="Animation_d5gho"]
length = 0.001
tracks/0/type = "value" tracks/0/type = "value"
tracks/0/imported = false tracks/0/imported = false
tracks/0/enabled = true tracks/0/enabled = true
@@ -168,7 +167,7 @@ tracks/0/keys = {
"times": PackedFloat32Array(0), "times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1), "transitions": PackedFloat32Array(1),
"update": 1, "update": 1,
"values": [false] "values": [true]
} }
tracks/1/type = "value" tracks/1/type = "value"
tracks/1/imported = false tracks/1/imported = false
@@ -177,10 +176,10 @@ tracks/1/path = NodePath("StreakFX:emitting")
tracks/1/interp = 1 tracks/1/interp = 1
tracks/1/loop_wrap = true tracks/1/loop_wrap = true
tracks/1/keys = { tracks/1/keys = {
"times": PackedFloat32Array(0), "times": PackedFloat32Array(0, 0.033333335),
"transitions": PackedFloat32Array(1), "transitions": PackedFloat32Array(1, 1),
"update": 1, "update": 1,
"values": [false] "values": [false, true]
} }
tracks/2/type = "value" tracks/2/type = "value"
tracks/2/imported = false tracks/2/imported = false
@@ -189,10 +188,10 @@ tracks/2/path = NodePath("OmniLight3D:light_energy")
tracks/2/interp = 1 tracks/2/interp = 1
tracks/2/loop_wrap = true tracks/2/loop_wrap = true
tracks/2/keys = { tracks/2/keys = {
"times": PackedFloat32Array(0), "times": PackedFloat32Array(0, 0.06666667),
"transitions": PackedFloat32Array(1), "transitions": PackedFloat32Array(1, 1),
"update": 0, "update": 0,
"values": [20.0] "values": [20.0, 0.0]
} }
[sub_resource type="Animation" id="Animation_gf6ds"] [sub_resource type="Animation" id="Animation_gf6ds"]
@@ -234,6 +233,20 @@ tracks/2/keys = {
"update": 0, "update": 0,
"values": [20.0, 0.0] "values": [20.0, 0.0]
} }
tracks/3/type = "method"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath(".")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"values": [{
"args": [3.0],
"method": &"proximal_shake"
}]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_p88g7"] [sub_resource type="AnimationLibrary" id="AnimationLibrary_p88g7"]
_data = { _data = {
@@ -258,7 +271,6 @@ draw_pass_1 = SubResource("SphereMesh_4y8np")
[node name="ParticleFX" type="GPUParticles3D" parent="."] [node name="ParticleFX" type="GPUParticles3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.4375714, 0, 0.5602956) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.4375714, 0, 0.5602956)
material_override = ExtResource("2_l2v4y") material_override = ExtResource("2_l2v4y")
emitting = false
amount = 10 amount = 10
lifetime = 0.6 lifetime = 0.6
one_shot = true one_shot = true

View File

@@ -16,6 +16,8 @@ height = 1.0
[node name="Player" type="CharacterBody3D"] [node name="Player" type="CharacterBody3D"]
physics_interpolation_mode = 1 physics_interpolation_mode = 1
collision_layer = 2
collision_mask = 5
floor_constant_speed = true floor_constant_speed = true
floor_max_angle = 0.93549645 floor_max_angle = 0.93549645
floor_snap_length = 1.0 floor_snap_length = 1.0

View File

@@ -1,4 +1,4 @@
[gd_scene load_steps=7 format=3 uid="uid://bk3yqawritfnj"] [gd_scene load_steps=8 format=3 uid="uid://bk3yqawritfnj"]
[ext_resource type="Script" uid="uid://yjsgte3x7jjw" path="res://scripts/trap.gd" id="1_6h4aj"] [ext_resource type="Script" uid="uid://yjsgte3x7jjw" path="res://scripts/trap.gd" id="1_6h4aj"]
[ext_resource type="ArrayMesh" uid="uid://bih57xe642hrc" path="res://models/trap.obj" id="2_oj6ox"] [ext_resource type="ArrayMesh" uid="uid://bih57xe642hrc" path="res://models/trap.obj" id="2_oj6ox"]
@@ -14,7 +14,12 @@ albedo_color = Color(1, 1, 0, 1)
[sub_resource type="BoxShape3D" id="BoxShape3D_dw7u0"] [sub_resource type="BoxShape3D" id="BoxShape3D_dw7u0"]
size = Vector3(0.8, 1, 0.8) size = Vector3(0.8, 1, 0.8)
[sub_resource type="BoxShape3D" id="BoxShape3D_6h4aj"]
resource_local_to_scene = true
[node name="Trap" type="Area3D"] [node name="Trap" type="Area3D"]
collision_layer = 4
collision_mask = 2
script = ExtResource("1_6h4aj") script = ExtResource("1_6h4aj")
[node name="Model" type="MeshInstance3D" parent="."] [node name="Model" type="MeshInstance3D" parent="."]
@@ -40,4 +45,14 @@ texture = ExtResource("3_mxvh5")
[node name="RevealTimer" type="Timer" parent="."] [node name="RevealTimer" type="Timer" parent="."]
unique_name_in_owner = true unique_name_in_owner = true
[node name="RangeArea" type="Area3D" parent="."]
unique_name_in_owner = true
collision_layer = 0
collision_mask = 2
[node name="RangeShape" type="CollisionShape3D" parent="RangeArea"]
unique_name_in_owner = true
shape = SubResource("BoxShape3D_6h4aj")
[connection signal="body_entered" from="." to="." method="_on_body_entered"]
[connection signal="timeout" from="RevealTimer" to="." method="_on_reveal_timeout"] [connection signal="timeout" from="RevealTimer" to="." method="_on_reveal_timeout"]