feat: added rocket noises and smoke trails and adjusted AoE of rockets and damage falloff on AoE
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -433,4 +433,36 @@ for i in range(int(sample_rate * mortar_duration)):
|
||||
mortar_samples.append(thunk + ring)
|
||||
write_wav('assets/sounds/mortar_fire.wav', mortar_samples)
|
||||
|
||||
# 21. Rocket Flight (Deep continuous looping whoosh/rumble)
|
||||
flight_duration = 1.0 # 1 second loop
|
||||
flight_samples = []
|
||||
prev_f = 0.0
|
||||
for i in range(int(sample_rate * flight_duration)):
|
||||
t = i / sample_rate
|
||||
noise = random.uniform(-1.0, 1.0)
|
||||
alpha = 0.15 # Higher cutoff for more whoosh
|
||||
filtered = prev_f + alpha * (noise - prev_f)
|
||||
prev_f = filtered
|
||||
rumble = math.sin(t * 70.0 * 2 * math.pi) * 1.5
|
||||
raw = (filtered * 2.5 + rumble)
|
||||
# Heavy soft clipping to make it sound intensely loud
|
||||
flight_samples.append(math.tanh(raw * 2.0))
|
||||
write_wav('assets/sounds/rocket_flight.wav', flight_samples)
|
||||
|
||||
# 22. Swarm Flight (Higher pitched continuous hiss)
|
||||
swarm_flight_samples = []
|
||||
prev_sf = 0.0
|
||||
for i in range(int(sample_rate * flight_duration)):
|
||||
t = i / sample_rate
|
||||
noise = random.uniform(-1.0, 1.0)
|
||||
alpha = 0.4 # Higher cutoff for hiss
|
||||
filtered = prev_sf + alpha * (noise - prev_sf)
|
||||
prev_sf = filtered
|
||||
# Aggressive screaming tone
|
||||
whine = math.sin(t * 800.0 * 2 * math.pi) * 1.5
|
||||
raw = (filtered * 2.0 + whine)
|
||||
# Heavy soft clipping
|
||||
swarm_flight_samples.append(math.tanh(raw * 2.0))
|
||||
write_wav('assets/sounds/swarm_flight.wav', swarm_flight_samples)
|
||||
|
||||
print("Generated all sounds!")
|
||||
|
||||
@@ -77,7 +77,7 @@ class_name MovementParams
|
||||
@export var rocket_jump_falloff: float = 1.5
|
||||
|
||||
# ── Shotgun Jump ──────────────────────────────────────────────────────────────
|
||||
@export var shotgun_jump_impulse: float = 10.0
|
||||
@export var shotgun_jump_impulse: float = 15.0
|
||||
|
||||
# ── Double Jump ───────────────────────────────────────────────────────────────
|
||||
@export var double_jump_velocity: float = 8.0
|
||||
|
||||
@@ -14,7 +14,7 @@ func _physics_process(delta: float) -> void:
|
||||
fuse_time -= delta
|
||||
if fuse_time <= 0.0:
|
||||
_explode(global_position)
|
||||
queue_free()
|
||||
destroy()
|
||||
return
|
||||
|
||||
# Apply gravity drop if any
|
||||
|
||||
@@ -1,16 +1,141 @@
|
||||
extends Projectile
|
||||
class_name ExplosiveProjectile
|
||||
|
||||
var explosion_radius: float = 5.0
|
||||
var explosion_radius: float = 2.5
|
||||
var explosion_knockback: float = 20.0
|
||||
var can_self_damage: bool = false
|
||||
var falloff_curve: float = 1.0 # 1.0 is linear, 2.0 is quadratic (steep drop)
|
||||
var flight_sound: AudioStreamPlayer3D
|
||||
var smoke_sys: GPUParticles3D
|
||||
var jet_sys: GPUParticles3D
|
||||
|
||||
static var _smoke_tex: GradientTexture2D
|
||||
|
||||
static func get_smoke_texture() -> GradientTexture2D:
|
||||
if _smoke_tex: return _smoke_tex
|
||||
_smoke_tex = GradientTexture2D.new()
|
||||
_smoke_tex.fill = GradientTexture2D.FILL_RADIAL
|
||||
_smoke_tex.fill_from = Vector2(0.5, 0.5)
|
||||
_smoke_tex.fill_to = Vector2(1.0, 1.0)
|
||||
|
||||
var g = Gradient.new()
|
||||
g.add_point(0.0, Color(1, 1, 1, 1))
|
||||
g.add_point(0.5, Color(1, 1, 1, 0.5))
|
||||
g.add_point(1.0, Color(1, 1, 1, 0))
|
||||
_smoke_tex.gradient = g
|
||||
_smoke_tex.width = 64
|
||||
_smoke_tex.height = 64
|
||||
return _smoke_tex
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
_setup_effects()
|
||||
|
||||
func destroy() -> void:
|
||||
if is_instance_valid(smoke_sys):
|
||||
smoke_sys.emitting = false
|
||||
var p = smoke_sys.get_parent()
|
||||
if p:
|
||||
var trans = smoke_sys.global_transform
|
||||
p.remove_child(smoke_sys)
|
||||
get_tree().current_scene.add_child(smoke_sys)
|
||||
smoke_sys.global_transform = trans
|
||||
var timer = smoke_sys.get_tree().create_timer(smoke_sys.lifetime)
|
||||
timer.timeout.connect(smoke_sys.queue_free)
|
||||
|
||||
if is_instance_valid(jet_sys):
|
||||
jet_sys.emitting = false
|
||||
var p = jet_sys.get_parent()
|
||||
if p:
|
||||
var trans = jet_sys.global_transform
|
||||
p.remove_child(jet_sys)
|
||||
get_tree().current_scene.add_child(jet_sys)
|
||||
jet_sys.global_transform = trans
|
||||
var timer = jet_sys.get_tree().create_timer(jet_sys.lifetime)
|
||||
timer.timeout.connect(jet_sys.queue_free)
|
||||
|
||||
super.destroy()
|
||||
|
||||
func _setup_effects() -> void:
|
||||
# Audio
|
||||
flight_sound = AudioStreamPlayer3D.new()
|
||||
flight_sound.stream = load("res://assets/sounds/rocket_flight.wav")
|
||||
flight_sound.autoplay = true
|
||||
if flight_sound.stream is AudioStreamWAV:
|
||||
flight_sound.stream.loop_mode = AudioStreamWAV.LOOP_FORWARD
|
||||
flight_sound.unit_size = 50.0
|
||||
flight_sound.max_db = 6.0
|
||||
flight_sound.volume_db = 6.0
|
||||
add_child(flight_sound)
|
||||
flight_sound.play()
|
||||
|
||||
# Jet Fire Particles
|
||||
jet_sys = GPUParticles3D.new()
|
||||
var jet_mat = ParticleProcessMaterial.new()
|
||||
jet_mat.direction = Vector3(0, 0, 1) # Backwards (since model looks at -Z)
|
||||
jet_mat.spread = 10.0
|
||||
jet_mat.initial_velocity_min = 1.0
|
||||
jet_mat.initial_velocity_max = 2.0
|
||||
jet_mat.gravity = Vector3.ZERO
|
||||
|
||||
var jet_mesh = BoxMesh.new()
|
||||
jet_mesh.size = Vector3(0.05, 0.05, 0.05)
|
||||
var mat = StandardMaterial3D.new()
|
||||
mat.albedo_color = Color(1.0, 0.6, 0.0)
|
||||
mat.emission_enabled = true
|
||||
mat.emission = Color(1.0, 0.5, 0.0)
|
||||
jet_mesh.material = mat
|
||||
jet_sys.draw_pass_1 = jet_mesh
|
||||
jet_sys.process_material = jet_mat
|
||||
jet_sys.amount = 16
|
||||
jet_sys.lifetime = 0.2
|
||||
jet_sys.position = Vector3(0, 0, 0.1)
|
||||
add_child(jet_sys)
|
||||
|
||||
# Smoke Trail
|
||||
smoke_sys = GPUParticles3D.new()
|
||||
var smoke_mat = ParticleProcessMaterial.new()
|
||||
smoke_mat.direction = Vector3(0, 0, 1)
|
||||
smoke_mat.spread = 5.0
|
||||
smoke_mat.initial_velocity_min = 0.0
|
||||
smoke_mat.initial_velocity_max = 0.5
|
||||
smoke_mat.gravity = Vector3(0, 0.5, 0)
|
||||
|
||||
var grad = Gradient.new()
|
||||
grad.add_point(0.0, Color(0.5, 0.5, 0.5, 0.8))
|
||||
grad.add_point(1.0, Color(0.8, 0.8, 0.8, 0.0))
|
||||
var grad_tex = GradientTexture1D.new()
|
||||
grad_tex.gradient = grad
|
||||
smoke_mat.color_ramp = grad_tex
|
||||
|
||||
var curve = Curve.new()
|
||||
curve.add_point(Vector2(0.0, 1.0))
|
||||
curve.add_point(Vector2(1.0, 3.0))
|
||||
var curve_tex = CurveTexture.new()
|
||||
curve_tex.curve = curve
|
||||
smoke_mat.scale_curve = curve_tex
|
||||
|
||||
var smoke_mesh = QuadMesh.new()
|
||||
smoke_mesh.size = Vector2(0.2, 0.2)
|
||||
var s_mat = StandardMaterial3D.new()
|
||||
s_mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
||||
s_mat.vertex_color_use_as_albedo = true
|
||||
s_mat.albedo_texture = get_smoke_texture()
|
||||
s_mat.billboard_mode = BaseMaterial3D.BILLBOARD_PARTICLES
|
||||
s_mat.billboard_keep_scale = true
|
||||
smoke_mesh.material = s_mat
|
||||
smoke_sys.draw_pass_1 = smoke_mesh
|
||||
smoke_sys.process_material = smoke_mat
|
||||
smoke_sys.amount = 32
|
||||
smoke_sys.lifetime = 1.5
|
||||
smoke_sys.position = Vector3(0, 0, 0.15)
|
||||
add_child(smoke_sys)
|
||||
|
||||
func _on_hit(result: Dictionary) -> void:
|
||||
if not result.collider.has_method("take_damage"):
|
||||
ImpactSpawner.spawn(get_tree(), "crater", result.position, result.normal, explosion_radius * 1.5)
|
||||
_explode(result.position)
|
||||
queue_free()
|
||||
destroy()
|
||||
|
||||
func _explode(pos: Vector3) -> void:
|
||||
var space_state = get_world_3d().direct_space_state
|
||||
@@ -49,10 +174,12 @@ func _explode(pos: Vector3) -> void:
|
||||
|
||||
# Normalised distance (0 = epicenter, 1 = edge)
|
||||
var ndist = dist / explosion_radius
|
||||
var intensity = clampf(1.0 - pow(ndist, falloff_curve), 0.0, 1.0)
|
||||
var falloff = clampf(pow(ndist, falloff_curve), 0.0, 1.0)
|
||||
var damage_intensity = lerpf(1.0, 0.33, falloff)
|
||||
var knockback_intensity = 1.0 - falloff
|
||||
|
||||
var final_damage = damage * intensity
|
||||
var final_knockback = explosion_knockback * intensity
|
||||
var final_damage = damage * damage_intensity
|
||||
var final_knockback = explosion_knockback * knockback_intensity
|
||||
|
||||
# Knockback direction: from explosion pos to target
|
||||
var dir = (target_pos - pos).normalized()
|
||||
|
||||
@@ -8,6 +8,88 @@ var initial_aim_dir: Vector3 = Vector3.ZERO
|
||||
var cruise_speed: float = 60.0
|
||||
var ignition_timer: float = 0.5
|
||||
var ignited: bool = false
|
||||
var effects_started: bool = false
|
||||
|
||||
func _setup_effects() -> void:
|
||||
pass # Wait until ignited
|
||||
|
||||
func _start_homing_effects() -> void:
|
||||
if effects_started: return
|
||||
effects_started = true
|
||||
|
||||
# Audio
|
||||
flight_sound = AudioStreamPlayer3D.new()
|
||||
flight_sound.stream = load("res://assets/sounds/swarm_flight.wav")
|
||||
flight_sound.autoplay = true
|
||||
if flight_sound.stream is AudioStreamWAV:
|
||||
flight_sound.stream.loop_mode = AudioStreamWAV.LOOP_FORWARD
|
||||
flight_sound.unit_size = 50.0
|
||||
flight_sound.max_db = 6.0
|
||||
flight_sound.volume_db = 6.0
|
||||
add_child(flight_sound)
|
||||
flight_sound.play()
|
||||
|
||||
# Jet Fire Particles
|
||||
jet_sys = GPUParticles3D.new()
|
||||
var jet_mat = ParticleProcessMaterial.new()
|
||||
jet_mat.direction = Vector3(0, 0, 1)
|
||||
jet_mat.spread = 10.0
|
||||
jet_mat.initial_velocity_min = 0.5
|
||||
jet_mat.initial_velocity_max = 1.0
|
||||
jet_mat.gravity = Vector3.ZERO
|
||||
|
||||
var jet_mesh = BoxMesh.new()
|
||||
jet_mesh.size = Vector3(0.02, 0.02, 0.02)
|
||||
var mat = StandardMaterial3D.new()
|
||||
mat.albedo_color = Color(1.0, 0.6, 0.0)
|
||||
mat.emission_enabled = true
|
||||
mat.emission = Color(1.0, 0.5, 0.0)
|
||||
jet_mesh.material = mat
|
||||
jet_sys.draw_pass_1 = jet_mesh
|
||||
jet_sys.process_material = jet_mat
|
||||
jet_sys.amount = 16
|
||||
jet_sys.lifetime = 0.15
|
||||
jet_sys.position = Vector3(0, 0, 0.05)
|
||||
add_child(jet_sys)
|
||||
|
||||
# Smoke Trail
|
||||
smoke_sys = GPUParticles3D.new()
|
||||
var smoke_mat = ParticleProcessMaterial.new()
|
||||
smoke_mat.direction = Vector3(0, 0, 1)
|
||||
smoke_mat.spread = 5.0
|
||||
smoke_mat.initial_velocity_min = 0.0
|
||||
smoke_mat.initial_velocity_max = 0.2
|
||||
smoke_mat.gravity = Vector3(0, 0.5, 0)
|
||||
|
||||
var grad = Gradient.new()
|
||||
grad.add_point(0.0, Color(0.5, 0.5, 0.5, 0.8))
|
||||
grad.add_point(1.0, Color(0.8, 0.8, 0.8, 0.0))
|
||||
var grad_tex = GradientTexture1D.new()
|
||||
grad_tex.gradient = grad
|
||||
smoke_mat.color_ramp = grad_tex
|
||||
|
||||
var curve = Curve.new()
|
||||
curve.add_point(Vector2(0.0, 1.0))
|
||||
curve.add_point(Vector2(1.0, 3.0))
|
||||
var curve_tex = CurveTexture.new()
|
||||
curve_tex.curve = curve
|
||||
smoke_mat.scale_curve = curve_tex
|
||||
|
||||
var smoke_mesh = QuadMesh.new()
|
||||
smoke_mesh.size = Vector2(0.08, 0.08)
|
||||
var s_mat = StandardMaterial3D.new()
|
||||
s_mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
||||
s_mat.vertex_color_use_as_albedo = true
|
||||
s_mat.albedo_texture = ExplosiveProjectile.get_smoke_texture()
|
||||
s_mat.billboard_mode = BaseMaterial3D.BILLBOARD_PARTICLES
|
||||
s_mat.billboard_keep_scale = true
|
||||
smoke_mesh.material = s_mat
|
||||
smoke_sys.draw_pass_1 = smoke_mesh
|
||||
smoke_sys.process_material = smoke_mat
|
||||
smoke_sys.amount = 32
|
||||
smoke_sys.lifetime = 1.0
|
||||
smoke_sys.position = Vector3(0, 0, 0.05)
|
||||
add_child(smoke_sys)
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if not ignited:
|
||||
@@ -15,6 +97,7 @@ func _physics_process(delta: float) -> void:
|
||||
if ignition_timer <= 0.0:
|
||||
ignited = true
|
||||
drop_gravity = 0.0
|
||||
_start_homing_effects()
|
||||
|
||||
if ignited and is_instance_valid(weapon_source):
|
||||
var target_dir: Vector3 = initial_aim_dir
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ func _spawn_custom_projectile(origin: Vector3, fire_dir: Vector3) -> void:
|
||||
proj.bounciness = 0.4 # Heavy, loses momentum on bounce
|
||||
|
||||
# Explosive stats
|
||||
proj.explosion_radius = 12.0 # Very large AoE
|
||||
proj.explosion_radius = 10.0 # Very large AoE
|
||||
proj.explosion_knockback = 60.0 # Massive knockback
|
||||
proj.falloff_curve = 2.0 # Steep dropoff: "Should be an instant kill in closest 50%"
|
||||
# (0-50% = dist<6. 6/12 = 0.5. 1.0 - 0.5^2 = 0.75 multiplier. 200 * 0.75 = 150 damage -> 1 shot kill)
|
||||
|
||||
@@ -21,7 +21,7 @@ func _ready() -> void:
|
||||
_previous_position = global_position
|
||||
# Automatically destroy after 5 seconds to prevent leaks
|
||||
var t = get_tree().create_timer(5.0)
|
||||
t.timeout.connect(queue_free)
|
||||
t.timeout.connect(destroy)
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
# Apply gravity drop if any
|
||||
@@ -33,7 +33,7 @@ func _physics_process(delta: float) -> void:
|
||||
distance_traveled += movement.length()
|
||||
|
||||
if distance_traveled > max_range:
|
||||
queue_free()
|
||||
destroy()
|
||||
return
|
||||
|
||||
_check_collision()
|
||||
@@ -63,4 +63,7 @@ func _on_hit(result: Dictionary) -> void:
|
||||
var size = 0.4 if impact_type == "plasma" else 0.15
|
||||
ImpactSpawner.spawn(get_tree(), impact_type, result.position, result.normal, size)
|
||||
|
||||
destroy()
|
||||
|
||||
func destroy() -> void:
|
||||
queue_free()
|
||||
|
||||
@@ -98,7 +98,7 @@ func _spawn_custom_projectile(origin: Vector3, fire_dir: Vector3) -> void:
|
||||
proj.owner_player = player
|
||||
|
||||
# Explosive stats
|
||||
proj.explosion_radius = 8.0 # Moderate AoE
|
||||
proj.explosion_radius = 4.0 # Moderate AoE
|
||||
proj.explosion_knockback = 45.0 # Strong knockback!
|
||||
proj.can_self_damage = false # As requested
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ func _fire() -> void:
|
||||
var tween = create_tween()
|
||||
tween.tween_property(muzzle_flash, "light_energy", 0.0, 0.1)
|
||||
|
||||
var origin = camera.global_position + camera.global_transform.basis * Vector3(0.4, -0.2, -0.6)
|
||||
var _origin = camera.global_position + camera.global_transform.basis * Vector3(0.4, -0.2, -0.6)
|
||||
var base_dir = -camera.global_transform.basis.z
|
||||
|
||||
_current_aim_dir = base_dir
|
||||
@@ -162,7 +162,7 @@ func _spawn_custom_projectile(origin: Vector3, fire_dir: Vector3) -> void:
|
||||
|
||||
# Logic
|
||||
proj.weapon_source = self
|
||||
proj.turn_speed = 4.0 # Slower turn radius so they sweep nicely
|
||||
proj.turn_speed = 6.5 # Slower turn radius so they sweep nicely
|
||||
|
||||
proj.position = origin # Start at origin to spread outward around camera
|
||||
proj.logical_source = origin
|
||||
@@ -184,7 +184,7 @@ func _spawn_custom_projectile(origin: Vector3, fire_dir: Vector3) -> void:
|
||||
proj.owner_player = player
|
||||
|
||||
# Explosive stats
|
||||
proj.explosion_radius = 3.0 # Tiny AoE effect
|
||||
proj.explosion_radius = 1.5 # Tiny AoE effect
|
||||
proj.explosion_knockback = 5.0
|
||||
proj.can_self_damage = false
|
||||
|
||||
|
||||
Reference in New Issue
Block a user