feat: add projectile Animmantion & SFX handling

This commit is contained in:
Varylios 2025-09-21 13:08:20 +02:00
parent ee46149287
commit f8d904c87e
20 changed files with 178 additions and 163 deletions

Binary file not shown.

View file

@ -0,0 +1,19 @@
[remap]
importer="oggvorbisstr"
type="AudioStreamOggVorbis"
uid="uid://c0qfynrgoynwr"
path="res://.godot/imported/BadHitSound_coin.ogg-e5c14b8c943c5f7bcce7bd971f08b7d5.oggvorbisstr"
[deps]
source_file="res://Assets/Audio/SFX/Test/BadHitSound_coin.ogg"
dest_files=["res://.godot/imported/BadHitSound_coin.ogg-e5c14b8c943c5f7bcce7bd971f08b7d5.oggvorbisstr"]
[params]
loop=false
loop_offset=0
bpm=0
beat_count=0
bar_beats=4

Binary file not shown.

View file

@ -0,0 +1,19 @@
[remap]
importer="oggvorbisstr"
type="AudioStreamOggVorbis"
uid="uid://bf50ah0ktnriu"
path="res://.godot/imported/BadHitSound_ktoung.ogg-d80938d9e44d3d634fa88c3cc16891ef.oggvorbisstr"
[deps]
source_file="res://Assets/Audio/SFX/Test/BadHitSound_ktoung.ogg"
dest_files=["res://.godot/imported/BadHitSound_ktoung.ogg-d80938d9e44d3d634fa88c3cc16891ef.oggvorbisstr"]
[params]
loop=false
loop_offset=0
bpm=0
beat_count=0
bar_beats=4

View file

@ -1 +1,12 @@
extends Node
func playSFX3D(stream: AudioStream, position: Vector3) -> void:
var sfx : AudioStreamPlayer3D = AudioStreamPlayer3D.new()
sfx.stream = stream
sfx.bus = "SFX"
add_child(sfx)
sfx.global_position = position
sfx.play()
await sfx.finished
sfx.queue_free()

View file

@ -7,10 +7,7 @@
[sub_resource type="Resource" id="Resource_87wss"]
script = ExtResource("3_ub8wd")
enemy = "res://Enemies/Scenes/enemy-a.tscn"
number_to_spawn = 1
lane_to_spawn = 0
spawn_delay = 2.0
pack_delay = 0.15
metadata/_custom_type_script = "uid://blxx3vs2wnfet"
[sub_resource type="Resource" id="Resource_457yt"]
@ -22,23 +19,17 @@ metadata/_custom_type_script = "uid://chu8s12rtdeqx"
script = ExtResource("3_ub8wd")
enemy = "uid://1kwye5yjf40d"
number_to_spawn = 2
lane_to_spawn = 0
spawn_delay = 1.0
pack_delay = 0.15
[sub_resource type="Resource" id="Resource_ftl6b"]
script = ExtResource("3_ub8wd")
enemy = "uid://1kwye5yjf40d"
number_to_spawn = 2
lane_to_spawn = 0
spawn_delay = 2.0
pack_delay = 0.15
[sub_resource type="Resource" id="Resource_e6yyc"]
script = ExtResource("3_ub8wd")
enemy = "uid://1kwye5yjf40d"
number_to_spawn = 5
lane_to_spawn = 0
spawn_delay = 10.0
pack_delay = 0.5
@ -49,10 +40,6 @@ troops = Array[ExtResource("3_ub8wd")]([SubResource("Resource_qfjse"), SubResour
[sub_resource type="Resource" id="Resource_fhv1k"]
script = ExtResource("3_ub8wd")
enemy = "uid://r6tj7jprdqib"
number_to_spawn = 1
lane_to_spawn = 0
spawn_delay = 1.0
pack_delay = 0.15
[sub_resource type="Resource" id="Resource_46oi2"]
script = ExtResource("2_457yt")
@ -61,16 +48,11 @@ troops = Array[ExtResource("3_ub8wd")]([SubResource("Resource_fhv1k"), SubResour
[sub_resource type="Resource" id="Resource_7vcps"]
script = ExtResource("3_ub8wd")
enemy = "uid://koikfh03qv7"
number_to_spawn = 1
lane_to_spawn = 0
spawn_delay = 1.0
pack_delay = 0.15
[sub_resource type="Resource" id="Resource_3kmde"]
script = ExtResource("3_ub8wd")
enemy = "uid://koikfh03qv7"
number_to_spawn = 3
lane_to_spawn = 0
spawn_delay = 5.0
pack_delay = 0.3
@ -78,7 +60,6 @@ pack_delay = 0.3
script = ExtResource("3_ub8wd")
enemy = "uid://1kwye5yjf40d"
number_to_spawn = 5
lane_to_spawn = 0
spawn_delay = 10.0
pack_delay = 0.4
@ -86,15 +67,11 @@ pack_delay = 0.4
script = ExtResource("3_ub8wd")
enemy = "uid://r6tj7jprdqib"
number_to_spawn = 3
lane_to_spawn = 0
spawn_delay = 1.0
pack_delay = 0.15
[sub_resource type="Resource" id="Resource_q3d8d"]
script = ExtResource("3_ub8wd")
enemy = "uid://1kwye5yjf40d"
number_to_spawn = 10
lane_to_spawn = 0
spawn_delay = 2.0
pack_delay = 0.3
@ -102,8 +79,6 @@ pack_delay = 0.3
script = ExtResource("3_ub8wd")
enemy = "uid://koikfh03qv7"
number_to_spawn = 4
lane_to_spawn = 0
spawn_delay = 1.0
pack_delay = 0.5
[sub_resource type="Resource" id="Resource_p2jl5"]
@ -113,10 +88,6 @@ troops = Array[ExtResource("3_ub8wd")]([SubResource("Resource_7vcps"), SubResour
[sub_resource type="Resource" id="Resource_1nx3f"]
script = ExtResource("3_ub8wd")
enemy = "uid://dyl4wiga2goi"
number_to_spawn = 1
lane_to_spawn = 0
spawn_delay = 1.0
pack_delay = 0.15
[sub_resource type="Resource" id="Resource_0nx55"]
script = ExtResource("2_457yt")
@ -124,11 +95,7 @@ troops = Array[ExtResource("3_ub8wd")]([SubResource("Resource_1nx3f")])
[resource]
script = ExtResource("1_ftl6b")
auto_start = false
auto_launch_wave = false
tier_max = 1
allowedTowers = Array[int]([1, 2, 3])
laneCount = 1
startingMoney = 110
waves = Array[ExtResource("2_457yt")]([SubResource("Resource_457yt"), SubResource("Resource_qeljc"), SubResource("Resource_46oi2"), SubResource("Resource_p2jl5"), SubResource("Resource_0nx55")])
metadata/_custom_type_script = "uid://cuhq6u67cbbqm"

View file

@ -1,7 +1,6 @@
[gd_scene load_steps=10 format=3 uid="uid://c5rx5scnkh3fb"]
[gd_scene load_steps=9 format=3 uid="uid://c5rx5scnkh3fb"]
[ext_resource type="Texture2D" uid="uid://dqyhhvxpwtpsy" path="res://Assets/Emotes/emote_star.png" id="1_3pqxv"]
[ext_resource type="Script" uid="uid://6xiqssgmiurt" path="res://Projectiles/Draft/impact_pierre.gd" id="2_ymm3v"]
[sub_resource type="Curve" id="Curve_ymm3v"]
_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(0.499044, 1), 0.0, 0.0, 0, 0, Vector2(0.745698, 0.50142), -0.0206361, -0.0206361, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0]
@ -43,9 +42,3 @@ one_shot = true
explosiveness = 1.0
process_material = SubResource("ParticleProcessMaterial_jk26u")
draw_pass_1 = SubResource("QuadMesh_qw7ty")
script = ExtResource("2_ymm3v")
[node name="SFXImpact" type="AudioStreamPlayer3D" parent="."]
bus = &"SFX"
[connection signal="finished" from="." to="." method="_on_finished"]

View file

@ -1,58 +0,0 @@
[gd_scene load_steps=8 format=3 uid="uid://dsv2untvmg8q"]
[ext_resource type="Texture2D" uid="uid://dqyhhvxpwtpsy" path="res://Assets/Emotes/emote_star.png" id="1_lcll5"]
[ext_resource type="Script" uid="uid://bpy86kcsjgx0e" path="res://Projectiles/Draft/projectile_pierre.gd" id="2_i2vf7"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_qaid5"]
transparency = 1
shading_mode = 0
vertex_color_use_as_albedo = true
albedo_texture = ExtResource("1_lcll5")
billboard_mode = 3
particles_anim_h_frames = 1
particles_anim_v_frames = 1
particles_anim_loop = false
[sub_resource type="QuadMesh" id="QuadMesh_nkvug"]
material = SubResource("StandardMaterial3D_qaid5")
size = Vector2(0.2, 0.2)
[sub_resource type="Curve" id="Curve_lcll5"]
_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.509769, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0]
point_count = 3
[sub_resource type="Gradient" id="Gradient_i2vf7"]
offsets = PackedFloat32Array(0, 0.379888, 1)
colors = PackedColorArray(0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0)
[sub_resource type="Gradient" id="Gradient_nlum7"]
colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 1)
[node name="ProjectilePierre" type="Sprite3D"]
billboard = 2
texture = ExtResource("1_lcll5")
script = ExtResource("2_i2vf7")
[node name="CPUParticles3D" type="CPUParticles3D" parent="."]
amount = 16
lifetime = 0.5
explosiveness = 0.2
mesh = SubResource("QuadMesh_nkvug")
emission_shape = 6
emission_ring_axis = Vector3(0, 0, 1)
emission_ring_height = 0.0
emission_ring_radius = 0.3
emission_ring_inner_radius = 0.0
emission_ring_cone_angle = 90.0
direction = Vector3(0, 0, 0)
spread = 0.0
gravity = Vector3(0, 0, 0)
angular_velocity_min = 180.0
angular_velocity_max = 360.0
scale_amount_min = 0.0
scale_amount_curve = SubResource("Curve_lcll5")
color_ramp = SubResource("Gradient_i2vf7")
color_initial_ramp = SubResource("Gradient_nlum7")
[node name="SFXCreate" type="AudioStreamPlayer3D" parent="."]
bus = &"SFX"

View file

@ -1,7 +0,0 @@
extends GPUParticles3D
func _ready() -> void:
$SFXImpact.play()
func _on_finished() -> void:
queue_free()

View file

@ -1 +0,0 @@
uid://6xiqssgmiurt

View file

@ -1,10 +0,0 @@
extends Sprite3D
var impact : GPUParticles3D = preload("uid://c5rx5scnkh3fb").instantiate()
func _ready() -> void:
$SFXCreate.play()
func on_impact() -> void:
get_tree().root.add_child(impact)
queue_free()

View file

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

View file

@ -2,8 +2,7 @@ extends CharacterBody3D
class_name Projectile
enum State { INIT, TRAVEL, EFFECT, DESPAWN }
enum State { INIT, TRAVEL, IMPACT, EFFECT, DESPAWN }
enum Mode {
FOLLOW, ## Follow target
@ -12,7 +11,6 @@ enum Mode {
HITSCAN, ## Spawn on target location
}
enum Effect {
ONE_HIT, ## Make damage on hit
## Make damage every tick for specified duration[br]
@ -42,6 +40,11 @@ enum Type { ## Types of projectiles
@export var dotTicks : int
@export var tickInterval : float ##
@export_group("Sounds - Animations")
@export var impactScene : PackedScene
@export var shootSFX : AudioStream
@export var impactSFX : AudioStream
var state : State = State.INIT
var amount : float
var target : PhysicsBody3D
@ -60,33 +63,33 @@ func _ready() -> void:
func _physics_process(_delta: float) -> void:
if state == State.INIT:
if shootSFX:
AudioManager.playSFX3D(shootSFX, global_position)
state = State.TRAVEL
return
match state:
State.TRAVEL when isOnTarget():
state = State.EFFECT
applyEffects()
state = State.IMPACT
return
State.TRAVEL:
if mode == Mode.FOLLOW:
var globalPos : Vector3 = target.global_position
globalPos.y += Helper.getHitBoxLocation(target, Helper.POSITION.CENTER)
look_at(globalPos)
velocity = global_position.direction_to(globalPos) * speed
move_and_slide()
State.IMPACT:
state = State.EFFECT
impactAnimations()
applyEffects()
State.EFFECT: return
State.DESPAWN:
queue_free.call_deferred()
return
if shouldQueueFree():
state = State.DESPAWN
if state != State.TRAVEL:
return
if mode == Mode.FOLLOW:
var globalPos : Vector3 = target.global_position
globalPos.y += Helper.getHitBoxLocation(target, Helper.POSITION.CENTER)
look_at(globalPos)
velocity = global_position.direction_to(globalPos) * speed
move_and_slide()
func shouldQueueFree() -> bool:
if !is_instance_valid(target):
@ -97,6 +100,18 @@ func shouldQueueFree() -> bool:
return maxTargets == 0
func impactAnimations() -> void:
if impactSFX:
AudioManager.playSFX3D(impactSFX, global_position)
if impactScene:
var impact : GPUParticles3D = impactScene.instantiate()
impact.finished.connect(impact.queue_free)
get_tree().root.add_child(impact)
impact.emitting = false
impact.one_shot = true
impact.emitting = true
func isOnTarget() -> bool:
match mode:
Mode.LOCATION: return vectorTarget.distance_squared_to(global_position) < .4
@ -109,9 +124,10 @@ func applyEffects() -> void:
if not collidingBodies.is_empty() && isOnTarget():
resolveContacts()
if state != State.TRAVEL:
state = State.DESPAWN
if effect == Effect.DAMAGE_OVER_TIME:
dotTicks -= 1
state = State.DESPAWN
if dotTicks > 0:
state = State.EFFECT
await get_tree().create_timer(tickInterval).timeout
@ -144,7 +160,7 @@ func chooseNextTarget() -> Node3D:
return bodies[0]
func resolveEffect(body : Node3D) -> void:
func resolveEffect(body: Node3D) -> void:
if body is GameTile || maxTargets == 0:
return
@ -154,15 +170,14 @@ func resolveEffect(body : Node3D) -> void:
body.take_damage(amount)
if effect == Effect.POISON:
dotTicks -= 1
while dotTicks > 0 && is_instance_valid(body):
dotTicks -= 1
var poisonTicks : int = dotTicks - 1
while poisonTicks > 0 && is_instance_valid(body):
poisonTicks -= 1
await get_tree().create_timer(tickInterval).timeout
body.take_damage(amount)
affectedTarget.append(body)
maxTargets -= 1
state = State.DESPAWN
func shoot(_target: Node3D, globalPos: Vector3) -> void:

View file

@ -1,6 +1,7 @@
[gd_scene load_steps=3 format=3 uid="uid://dcnm6rjht0rew"]
[gd_scene load_steps=4 format=3 uid="uid://dcnm6rjht0rew"]
[ext_resource type="PackedScene" uid="uid://oykrff3g74eo" path="res://Projectiles/projectile.tscn" id="1_4tmpc"]
[ext_resource type="Texture2D" uid="uid://dqyhhvxpwtpsy" path="res://Assets/Emotes/emote_star.png" id="2_dl8a6"]
[sub_resource type="SphereShape3D" id="SphereShape3D_2ioqj"]
radius = 0.3
@ -11,11 +12,13 @@ type = 1
speed = 3
maxTargets = -1
[node name="HitBox" parent="." index="2"]
[node name="HitBox" parent="." index="1"]
collision_mask = 2
[node name="ProjectileSize" parent="HitBox" index="0"]
shape = SubResource("SphereShape3D_2ioqj")
[node name="DamageArea" parent="." index="3"]
collision_mask = 2
[node name="Sprite3D" type="Sprite3D" parent="." index="3"]
transform = Transform3D(2.5, 0, 0, 0, 2.5, 0, 0, 0, 2.5, 0, 0, 0)
billboard = 2
texture = ExtResource("2_dl8a6")

View file

@ -7,12 +7,13 @@
type = 3
speed = 2
[node name="Sprite3D" parent="." index="1"]
[node name="HitBox" parent="." index="1"]
collision_mask = 4
[node name="Sprite3D" type="Sprite3D" parent="." index="3"]
transform = Transform3D(1.3, 0, 0, 0, 1.3, 0, 0, 0, 1.3, 0, 0, 0)
billboard = 2
texture = ExtResource("2_ckawd")
hframes = 6
vframes = 2
frame = 11
[node name="HitBox" parent="." index="2"]
collision_mask = 4

View file

@ -1,9 +1,66 @@
[gd_scene load_steps=2 format=3 uid="uid://dy755v20lqu7q"]
[gd_scene load_steps=11 format=3 uid="uid://dy755v20lqu7q"]
[ext_resource type="PackedScene" uid="uid://oykrff3g74eo" path="res://Projectiles/projectile.tscn" id="1_d01p1"]
[ext_resource type="Texture2D" uid="uid://dqyhhvxpwtpsy" path="res://Assets/Emotes/emote_star.png" id="2_5lxlg"]
[ext_resource type="PackedScene" uid="uid://c5rx5scnkh3fb" path="res://Projectiles/Draft/ImpactPierre.tscn" id="2_s3rfh"]
[ext_resource type="AudioStream" uid="uid://c0qfynrgoynwr" path="res://Assets/Audio/SFX/Test/BadHitSound_coin.ogg" id="4_r8d72"]
[ext_resource type="AudioStream" uid="uid://bf50ah0ktnriu" path="res://Assets/Audio/SFX/Test/BadHitSound_ktoung.ogg" id="4_s3rfh"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_qaid5"]
transparency = 1
shading_mode = 0
vertex_color_use_as_albedo = true
albedo_texture = ExtResource("2_5lxlg")
billboard_mode = 3
particles_anim_h_frames = 1
particles_anim_v_frames = 1
particles_anim_loop = false
[sub_resource type="QuadMesh" id="QuadMesh_nkvug"]
material = SubResource("StandardMaterial3D_qaid5")
size = Vector2(0.2, 0.2)
[sub_resource type="Curve" id="Curve_lcll5"]
_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.509769, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0]
point_count = 3
[sub_resource type="Gradient" id="Gradient_i2vf7"]
offsets = PackedFloat32Array(0, 0.379888, 1)
colors = PackedColorArray(0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0)
[sub_resource type="Gradient" id="Gradient_nlum7"]
colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 1)
[node name="Projectile" instance=ExtResource("1_d01p1")]
speed = 15
impactScene = ExtResource("2_s3rfh")
shootSFX = ExtResource("4_r8d72")
impactSFX = ExtResource("4_s3rfh")
[node name="HitBox" parent="." index="2"]
[node name="HitBox" parent="." index="1"]
collision_mask = 2
[node name="ProjectilePierre" type="Sprite3D" parent="." index="3"]
billboard = 2
texture = ExtResource("2_5lxlg")
[node name="CPUParticles3D" type="CPUParticles3D" parent="ProjectilePierre" index="0"]
amount = 16
lifetime = 0.5
explosiveness = 0.2
mesh = SubResource("QuadMesh_nkvug")
emission_shape = 6
emission_ring_axis = Vector3(0, 0, 1)
emission_ring_height = 0.0
emission_ring_radius = 0.3
emission_ring_inner_radius = 0.0
emission_ring_cone_angle = 90.0
direction = Vector3(0, 0, 0)
spread = 0.0
gravity = Vector3(0, 0, 0)
angular_velocity_min = 180.0
angular_velocity_max = 360.0
scale_amount_min = 0.0
scale_amount_curve = SubResource("Curve_lcll5")
color_ramp = SubResource("Gradient_i2vf7")
color_initial_ramp = SubResource("Gradient_nlum7")

View file

@ -1,6 +1,7 @@
[gd_scene load_steps=3 format=3 uid="uid://df8u7dogl4wi0"]
[gd_scene load_steps=4 format=3 uid="uid://df8u7dogl4wi0"]
[ext_resource type="PackedScene" uid="uid://oykrff3g74eo" path="res://Projectiles/projectile.tscn" id="1_suva6"]
[ext_resource type="Texture2D" uid="uid://dqyhhvxpwtpsy" path="res://Assets/Emotes/emote_star.png" id="2_4juxc"]
[sub_resource type="SphereShape3D" id="SphereShape3D_878kj"]
@ -9,11 +10,16 @@ type = 2
speed = 5
maxTargets = 3
[node name="HitBox" parent="." index="2"]
[node name="HitBox" parent="." index="1"]
collision_mask = 2
[node name="EffectArea" parent="." index="3"]
[node name="EffectArea" parent="." index="2"]
collision_mask = 2
[node name="CollisionShape3D" type="CollisionShape3D" parent="EffectArea" index="0"]
shape = SubResource("SphereShape3D_878kj")
[node name="Sprite3D" type="Sprite3D" parent="." index="3"]
transform = Transform3D(2.5, 0, 0, 0, 2.5, 0, 0, 0, 2.5, 0, 0, 0)
billboard = 2
texture = ExtResource("2_4juxc")

View file

@ -1,6 +1,7 @@
[gd_scene load_steps=3 format=3 uid="uid://baixm8pfsdo3t"]
[gd_scene load_steps=4 format=3 uid="uid://baixm8pfsdo3t"]
[ext_resource type="PackedScene" uid="uid://oykrff3g74eo" path="res://Projectiles/projectile.tscn" id="1_a1h27"]
[ext_resource type="Texture2D" uid="uid://dqyhhvxpwtpsy" path="res://Assets/Emotes/emote_star.png" id="2_lwnvl"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_a1h27"]
radius = 0.1
@ -11,9 +12,14 @@ mode = 3
type = 1
maxTargets = 5
[node name="HitBox" parent="." index="2"]
[node name="HitBox" parent="." index="1"]
collision_mask = 2
[node name="ProjectileSize" parent="HitBox" index="0"]
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 0, 0, -5)
shape = SubResource("CapsuleShape3D_a1h27")
[node name="Sprite3D" type="Sprite3D" parent="." index="3"]
transform = Transform3D(2.5, 0, 0, 0, 2.5, 0, 0, 0, 2.5, 0, 0, 0)
billboard = 2
texture = ExtResource("2_lwnvl")

View file

@ -1,7 +1,6 @@
[gd_scene load_steps=5 format=3 uid="uid://oykrff3g74eo"]
[gd_scene load_steps=4 format=3 uid="uid://oykrff3g74eo"]
[ext_resource type="Script" uid="uid://b788twwo1o6l2" path="res://Projectiles/Projectile.gd" id="1_ggq0q"]
[ext_resource type="Texture2D" uid="uid://dqyhhvxpwtpsy" path="res://Assets/Emotes/emote_star.png" id="2_08w86"]
[sub_resource type="SphereShape3D" id="SphereShape3D_r5o86"]
radius = 0.1
@ -17,11 +16,6 @@ script = ExtResource("1_ggq0q")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("SphereShape3D_r5o86")
[node name="Sprite3D" type="Sprite3D" parent="."]
transform = Transform3D(2.5, 0, 0, 0, 2.5, 0, 0, 0, 2.5, 0, 0, 0)
billboard = 2
texture = ExtResource("2_08w86")
[node name="HitBox" type="Area3D" parent="."]
collision_layer = 0
collision_mask = 0

View file

@ -4,6 +4,7 @@
[ext_resource type="Theme" uid="uid://bbp4qcbwkeg7x" path="res://default_theme.tres" id="1_x7bkm"]
[node name="Panel" type="PanelContainer"]
process_mode = 3
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5