Sound; with or without Autoloader?

Godot Version

4.2.2

Question

I’m adding audio to my game; more specifically, ambient audio, so I’m using AudioStreamPlayers with Surround mix.

What I want to do is give the engine 7, maybe 8 vaguely sinister wind-like sounds, and let it randomly play one out of them based on a random chance roll once every 12 seconds (random chance is currently 1 in 5)

Problem: Currently, the code that does this is connected to the Level Node, because I don’t know how to get the autoloader to wait for a new scene to load and finish loading before it begins its sound shenanigans. I don’t like the fact that I’m attaching it to the level node.

Here’s the code, the script is named AmbientManager.gd:

extends Node2D

var ambient_nodes:Array[Node]
var randomizer:RandomNumberGenerator = RandomNumberGenerator.new()
var ambience_timer:Timer = Timer.new()

func _ready():
	ambient_nodes = get_tree().get_nodes_in_group("Ambience")
	add_child(ambience_timer)
	ambience_timer.wait_time = 12.0
	ambience_timer.one_shot = false
	ambience_timer.timeout.connect(play_ambiance)
	ambience_timer.start()

func play_ambiance() -> void:
	if randomizer.randi_range(1, 5) == 5:
		ambient_nodes[0].play()

Here is the scene hierarchy:

To rephrase: Where do I put this code and the ASP Nodes, so that I don’t have to do this hack-y solution?

Maybe your AmbientManager just needs to listen to the signal of when a new scene is loaded.
Also I am not quite sure what to make of your scene hierarchy because my mindset might be different.

Once the level is loaded, it should demand the music to play. Because you have the AmientManager as an autoload, it should be accessible everywhere in your code.

# your_scene.gd
func _ready() -> void:
   self.ready.emit(func(): AmbientManager.play_ambiance())

I assume your SceneTree is like this

  • Root
    • LevelContainer
      • Player
      • Tilemap
    • AudioManager
      • BGMPlayer
      • AmbientPlayer
    • UI_Menus

Feel free to correct me if I am wrong. I will try my utmost to adjust my solution to fit your current situation/use case

The SceneTree you described isn’t correct, my current setup is:

Root

  • an Unrelated Autoloaded script
  • Current Level (+ Ambientmanager script)
    • Player
    • Tilemap
    • Unrelated Gameplay Stuff
    • HUD

Also, by self.ready.emit(func(): AmbientManager.play_ambiance()), did you mean to use connect() instead?

Also, by self.ready.emit(func(): AmbientManager.play_ambiance()), did you mean to use connect() instead?

Every node should have a ready signal that is published when all resources are loaded. We can make use of that to call the method of the AmbientManager. It may also be enough to write the AmbientManager.play_ambiance() directly into the _ready() method of the scene.

The SceneTree you described isn’t correct, my current setup is:

I see, thank you for the correction. So your AmbientManager is not actually its own Node but instead it’s the SceneScript (which is also alright). You can then disregard my statement above.

Due to the fact that your AmbientPlayers are direct children of the Scene, then your approach should be functional. The only downside is that the audio cuts abruptly if you want to change the scene. If your game is played purely in one scene, this shouldnt be an issue.

1 Like

Ah, well I don’t plan on making the whole game be in one scene, so your assumption of my SceneTree is probably better.

Besides, up until now, I never knew a ready signal existed! Thank you kindly!

I would suggest having a main scene that has

  • a container for your loaded level
  • your audio players for bgm and ambient

additionally, creating an autoload for your Audioplayer so it can be accessed by your scenes. Your level can then communicate with the audioplayers and the user interface menus which exit outside of your level.

Feel free to test things about and find a system that works out for you, there are many ways to achieve this. There may be even better systems than the one i propose.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.