Add industrial metal soundtrack with seamless loop
- assets/audio/music/zombie_industrial_loop.ogg: 57.60 s Ogg Vorbis loop generated locally with YuE2-3B on the Tesla V100 (score written for this track; vocals removed with HTDemucs). The loop is spliced at the track's structural repeat with a 0.6 s crossfade: measured seam dip <= 1.6 dB. - scripts/main.gd: "Music" AudioStreamPlayer at -11 dB, started at boot on desktop and on the start click on Web (browser autoplay policy). It forces stream.loop at runtime because the Web staging step re-imports the OGG with loop=false. - tools/test_music.gd: soundtrack test (loop, length, volume, playback, still playing after player death). - docs/MUSIC.md: source, loop construction, verification, licence. - docs/WEB-DEPLOY.md: release ab6054111f5919a8 notes. Initial commit of the project.
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
extends SceneTree
|
||||
func _initialize() -> void:
|
||||
call_deferred("run_test")
|
||||
func run_test() -> void:
|
||||
var world := Node3D.new()
|
||||
root.add_child(world)
|
||||
var room := Node3D.new()
|
||||
room.set_script(load("res://scripts/room.gd"))
|
||||
world.add_child(room)
|
||||
var light := OmniLight3D.new()
|
||||
light.position = Vector3(0, 4, 0)
|
||||
light.omni_range = 24
|
||||
light.light_energy = 4
|
||||
world.add_child(light)
|
||||
var player := CharacterBody3D.new()
|
||||
player.set_script(load("res://scripts/player.gd"))
|
||||
player.position.y = 0.1
|
||||
world.add_child(player)
|
||||
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||
await create_timer(0.2).timeout
|
||||
player.camera.rotation.x = 0.12
|
||||
var aim: Vector3 = player.camera.rotation
|
||||
player.take_damage(12)
|
||||
assert(player.hp == 88)
|
||||
assert(player.damage_feedback.blood_left > 0)
|
||||
assert(player.damage_feedback.splats.size() == 7)
|
||||
await create_timer(0.06).timeout
|
||||
assert(player.damage_pivot.position.length() > 0.0001)
|
||||
assert(player.camera.rotation.is_equal_approx(aim))
|
||||
if DisplayServer.get_name() != "headless":
|
||||
await RenderingServer.frame_post_draw
|
||||
root.get_texture().get_image().save_png("/tmp/zombie-player-hit.png")
|
||||
# Multiple hits reuse a bounded pool; no camera offset accumulates.
|
||||
player.take_damage(12)
|
||||
player.take_damage(12)
|
||||
assert(player.damage_feedback.intensity <= 1)
|
||||
assert(player.damage_feedback.splats.size() == 7)
|
||||
await create_timer(1.35).timeout
|
||||
assert(player.damage_pivot.transform.is_equal_approx(Transform3D.IDENTITY))
|
||||
assert(player.camera.rotation.is_equal_approx(aim))
|
||||
assert(player.damage_feedback.blood_left == 0)
|
||||
player.take_damage(12)
|
||||
player.take_damage(1000)
|
||||
assert(not player.damage_feedback.active)
|
||||
assert(player.damage_pivot.transform.is_equal_approx(Transform3D.IDENTITY))
|
||||
await create_timer(3).timeout
|
||||
assert(player.camera.position.y < 0.25)
|
||||
assert(player.death_overlay.color.a > 0.99)
|
||||
print("PASS: damage shake, screen blood, aim preserved, repeated hits bounded, camera reset, death fade intact")
|
||||
world.queue_free()
|
||||
await process_frame
|
||||
quit()
|
||||
Reference in New Issue
Block a user