Does sound.play() start the sound the frame it was called, or the following frame?
I’m asking because I’m using a lua module to play the sounds, to make them play instantly. I’ve bumped into a problem where the instance that called the module to trigger the sound is destroyed before the sound has finished, which causes an error for callbacks.
The workaround would be to have a central game script deal with all sounds, instead of a lua module. To send a message to the script takes one frame, which would mean a two frames delay if sound.play already has a delay of one frame.
There is no such information in API reference, but I was always assuming that sound.play is invoking a method in that moment (in that frame), while msg.post("#sound", “play_sound”) is postponed to the messaging cycle.
In my solution I use a module, but it is required in a game object in a script in a main collection. This game objects owns all sounds. When I do want to animate gain or so (from other collection - aka level), the only option I have is to post a message to that script, but when I want to just play, I can do it from other collection with that module and in my solution the instance of the game object with sounds, script and module is in a collection that is persistent during life of the application, so there is no such problem - maybe this could just solve yours?
EDIT: yeah, so the workaround you came up with is the same
The sound.play()is a shorthand for msg.post(..., "play_sound").
Yes, the message will arrive the same engine frame.
However, you ask when it’s started, but describe a problem when the sound is ending?
I haven’t tried playing a sound that is shorter than one frame though, so I cannot be certain, but my guess is that the earliest the call back is invoked, is the next frame.
Correct, if you delete the script getting the callback, it’s not going to receive the callback.
I would use a Lua module and a central game object with the sounds. The Lua module:
local M = {}
function M.fire(play_properties, cb)
sound.play("sounds#bang", play_properties, cb)
end
return M
And sounds would be the game object that is always around and has all of the sounds you need in your game. Your module can also deal with gating, sound variants etc
This is what I am doing. The problem with this approach is that callbacks produce an error if the object sending the play command has been deleted.
In my case, I use the module to play a random sound out of a pool of sounds, for instance wall_slide1-5. I want to know whether the sound is playing, so I don’t play more than one of the same sound at a time. This is an issue, because the “player” game object might have been destroyed by the time the “wall_slide” sound has finished playing, resulting in the callback error I mentioned above. To avoid the error, I could use msg.post() to an always present .script, but this would mean a one frame delay to play the sound. My solution in the end was to have a separate variable in the player script that I set to true when the wall slide sound is played, and to false when I manually stop it. Maybe overkill to to save one frame of inaccuracy!