Sound effects on collisions

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) &nbsp;&nbsp;&nbsp;&nbsp;local factor = force\*velocity &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;print("CRASH = " .. tostring(math.floor(factor\*10)/10)) &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;if factor \< threshold then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("CRASH NO SOUND") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;local volume = 0 &nbsp;&nbsp;&nbsp;&nbsp;local chan = 0 &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;if factor \>= threshold\*3 then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chan = LOUDEST\_ROCK\_CHANNEL &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("CRASH LOUDEST") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;volume = 0.5 &nbsp;&nbsp;&nbsp;&nbsp;elseif factor&nbsp;&nbsp;&nbsp;&nbsp;\>= threshold\*2 then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chan = LOUD\_ROCK\_CHANNEL &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("CRASH LOUD") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;volume = 0.4 &nbsp;&nbsp;&nbsp;&nbsp;elseif factor&nbsp;&nbsp;&nbsp;&nbsp;\>= threshold\*1.5 then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chan = NORMAL\_ROCK\_CHANNEL &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("CRASH NORMAL") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;volume = 0.3 &nbsp;&nbsp;&nbsp;&nbsp;elseif factor \>= threshold\*1.25 then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chan = QUIET\_ROCK\_CHANNEL &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("CRASH QUIET") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;volume = 0.2 &nbsp;&nbsp;&nbsp;&nbsp;elseif factor \>= threshold then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chan = QUIETEST\_ROCK\_CHANNEL &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("CRASH QUIETEST") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;volume = 0.1 &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;local options = { channel = chan } &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;audio.setVolume(volume, options) &nbsp;&nbsp;&nbsp;&nbsp;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) &nbsp;&nbsp;&nbsp;&nbsp;local factor = force\*velocity &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;print("CRASH = " .. tostring(math.floor(factor\*10)/10)) &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;if factor \< threshold then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("CRASH NO SOUND") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;local volume = 0 &nbsp;&nbsp;&nbsp;&nbsp;local chan = 0 &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;if factor \>= threshold\*3 then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chan = LOUDEST\_ROCK\_CHANNEL &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("CRASH LOUDEST") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;volume = 0.5 &nbsp;&nbsp;&nbsp;&nbsp;elseif factor&nbsp;&nbsp;&nbsp;&nbsp;\>= threshold\*2 then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chan = LOUD\_ROCK\_CHANNEL &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("CRASH LOUD") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;volume = 0.4 &nbsp;&nbsp;&nbsp;&nbsp;elseif factor&nbsp;&nbsp;&nbsp;&nbsp;\>= threshold\*1.5 then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chan = NORMAL\_ROCK\_CHANNEL &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("CRASH NORMAL") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;volume = 0.3 &nbsp;&nbsp;&nbsp;&nbsp;elseif factor \>= threshold\*1.25 then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chan = QUIET\_ROCK\_CHANNEL &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("CRASH QUIET") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;volume = 0.2 &nbsp;&nbsp;&nbsp;&nbsp;elseif factor \>= threshold then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chan = QUIETEST\_ROCK\_CHANNEL &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("CRASH QUIETEST") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;volume = 0.1 &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;local options = { channel = chan } &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;audio.setVolume(volume, options) &nbsp;&nbsp;&nbsp;&nbsp;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