Throwing this out there in case anyone has perfected it. I don’t want to be re-inventing a wheel.
Playing sounds on collisions where an object is destroyed on collision is easy, since the object won’t be generating any more collisions.
When an object stays alive, I control unwanted fast replay of the sound by disabling the sound for a few milliseconds, like this:
if self.boingSound.enabled then self.boingSound.enabled = false Resources.playSound(self.boingSound.audio) timer.performWithDelay(self.boingSound.delay, function() self.boingSound.enabled = true end) end
The 2nd half of my post got clipped. Here it is.
For objects that are in constant contact with one another, and I have plenty as every scene in my game has dozens of stacked rocks, is another story. I use the same delay implemented above, but I also take into account object velocity and collision force. It’s getting better as I tweak, but it’s kind of painstaking.
Has anyone solved this problem?
function Resources.playRockCollisionSound(snd, force, velocity, threshold) local factor = force\*velocity print("CRASH = " .. tostring(math.floor(factor\*10)/10)) if factor \< threshold then print("CRASH NO SOUND") return end local volume = 0 local chan = 0 if factor \>= threshold\*3 then chan = LOUDEST\_ROCK\_CHANNEL print("CRASH LOUDEST") volume = 0.5 elseif factor \>= threshold\*2 then chan = LOUD\_ROCK\_CHANNEL print("CRASH LOUD") volume = 0.4 elseif factor \>= threshold\*1.5 then chan = NORMAL\_ROCK\_CHANNEL print("CRASH NORMAL") volume = 0.3 elseif factor \>= threshold\*1.25 then chan = QUIET\_ROCK\_CHANNEL print("CRASH QUIET") volume = 0.2 elseif factor \>= threshold then chan = QUIETEST\_ROCK\_CHANNEL print("CRASH QUIETEST") volume = 0.1 end local options = { channel = chan } audio.setVolume(volume, options) playSound(snd, options) end
Hi Dave,
You might consider setting your custom “enabled” property on the “began” phase of the collision, then use an audio complete listener to turn this flag to false… so the sound would play until its completion, and during its play, no additional sound would play on that object.
See here under “Audio Events”:
http://docs.coronalabs.com/guide/media/audioSystem/index.html
Best regards,
Brent
Thanks, Brent. Can I tie a collision event to a postCollision event? I’m playing the sounds on postCollision, because I need the force property of the event. I don’t see an event phase on postCollision.
Re: the audio complete listener, that sounds like the right way to do it. Thanks. I’m setting the delay to be a bit longer than the sound effect, so that sound won’t try to play again for that object while already playing, but that seems kind of hackish.
Hi Dave,
If I recall, you only get one postCollision event, so “began” wouldn’t be necessary. You can check this easily enough by just printing out what happens post-collsion (if you get one event, or multiple). I haven’t used a post-collision event in awhile, so I can’t remember if it reports multiple events like pre-collision does.
Brent
The 2nd half of my post got clipped. Here it is.
For objects that are in constant contact with one another, and I have plenty as every scene in my game has dozens of stacked rocks, is another story. I use the same delay implemented above, but I also take into account object velocity and collision force. It’s getting better as I tweak, but it’s kind of painstaking.
Has anyone solved this problem?
function Resources.playRockCollisionSound(snd, force, velocity, threshold) local factor = force\*velocity print("CRASH = " .. tostring(math.floor(factor\*10)/10)) if factor \< threshold then print("CRASH NO SOUND") return end local volume = 0 local chan = 0 if factor \>= threshold\*3 then chan = LOUDEST\_ROCK\_CHANNEL print("CRASH LOUDEST") volume = 0.5 elseif factor \>= threshold\*2 then chan = LOUD\_ROCK\_CHANNEL print("CRASH LOUD") volume = 0.4 elseif factor \>= threshold\*1.5 then chan = NORMAL\_ROCK\_CHANNEL print("CRASH NORMAL") volume = 0.3 elseif factor \>= threshold\*1.25 then chan = QUIET\_ROCK\_CHANNEL print("CRASH QUIET") volume = 0.2 elseif factor \>= threshold then chan = QUIETEST\_ROCK\_CHANNEL print("CRASH QUIETEST") volume = 0.1 end local options = { channel = chan } audio.setVolume(volume, options) playSound(snd, options) end
Hi Dave,
You might consider setting your custom “enabled” property on the “began” phase of the collision, then use an audio complete listener to turn this flag to false… so the sound would play until its completion, and during its play, no additional sound would play on that object.
See here under “Audio Events”:
http://docs.coronalabs.com/guide/media/audioSystem/index.html
Best regards,
Brent
Thanks, Brent. Can I tie a collision event to a postCollision event? I’m playing the sounds on postCollision, because I need the force property of the event. I don’t see an event phase on postCollision.
Re: the audio complete listener, that sounds like the right way to do it. Thanks. I’m setting the delay to be a bit longer than the sound effect, so that sound won’t try to play again for that object while already playing, but that seems kind of hackish.
Hi Dave,
If I recall, you only get one postCollision event, so “began” wouldn’t be necessary. You can check this easily enough by just printing out what happens post-collsion (if you get one event, or multiple). I haven’t used a post-collision event in awhile, so I can’t remember if it reports multiple events like pre-collision does.
Brent
what threshold are u using? i would like to use this code of yours but dont know how to get the force, velocity and threshold values.
Hello @thithous,
The postCollision properties are documented here:
http://docs.coronalabs.com/api/event/postCollision/index.html
Best regards,
Brent
what threshold are u using? i would like to use this code of yours but dont know how to get the force, velocity and threshold values.
Hello @thithous,
The postCollision properties are documented here:
http://docs.coronalabs.com/api/event/postCollision/index.html
Best regards,
Brent