Corona SDK: Adding Music and SoundEffects to Rolly Bear

In this post and tutorial we will add audio to the Rolly Bear World Project. Personally, I think this changes a lot of how the game feels. So i’m glad I reached this point.

In this post we will add
- Sound effects
- Background Music
- Via Pause Menu the user can change the settings for both

In my last post I mentioned our visit to Angkor Wat, in Cambodia. In this post I will share some extra photos we took during our visit. Angkor Wat is now operated (maintained) by a corporation from Vietnam, which I found out during some of my talks with the local folks, it shouldn’t be a surprise, but the Cambodians are quite bitter about this, as it is one of Siem Reaps, main source of income these days. In case you ever visit Angkor Wat, I recommend to hire a tuk tuk driver for a whole day (about 15 USD), as the complete temple complex is huge and almost impossible to walk.

To keep overview I have programmed all audio related functions in a separate .lua file called “soundsfile.lua”.

We need functions for:
- Play SoundEffects
- Play Background Music
- Reset Background Mysic
- Pause Music
- Resume Music.

After you have created a separate .lua file called “soundsfile.lua”, we first start to load all audio files with the help of the Corona SDK API audio.loadSound (for the sound effects) and audio.loadStream for the background music.

audiolaunchbear = audio.loadSound ("audio/wee.mp3")
audiowinsound = audio.loadSound ("audio/winsound.wav")
audioclick = audio.loadSound ("audio/click.mp3")
audiolever = audio.loadSound ("audio/soundlever.mp3")
gamebgmusic = audio.loadStream ("audio/gamebgmonomusic.mp3")

We need two variables which hold a boolean (true or false) checking if the game is allowed to play the music and/or sound effects, based on the settings of the user.

soundisOn = true 
musicisOn = true 

Corona SDK has 32 audio channels available to handle the music and sound effects. To be sure that the background music can always be played you can tell Corona SDK to reserve a channel. You can do this via:

audio.reserveChannels (1) -- one audio channel we need to reserve for the background music 

In the next lines of code when we create the play music functions we will tell Corona SDK to always play the background music via the reserved audio channel 1.

Let’s start with the function to play the sound effects, the function takes to parameters: first the soundfile, which is the sound object (the actual variable holding one of the MP3 files) and second the volumeLevel, this way we can lower or increase the sound effects. To pass it as a parameter we can decide to use this per sound file . In the function we check first if the soundisOn variable is set to true, with other words, should we play the sound file or not (based on user preferences)? Default this is set to true. Next, the volumelevel which is passed on is stored in a local variable volumelevel, note that when no parameter for volumelevel is passed the default is set to 1.0

function playSFX (soundfile, volumelevel)

 	if soundisOn == true then 
local volumelevel = volumelevel or 1.0
audio.play(soundfile)
audio.setVolume(volumelevel, {soundfile} )
end 
end 

The next function is to play music, again we check if we are allowed to play the music with the if-statement. Note that the audio.play is set with a -1 for the loop, meaning it will replay again when the music file is ended (endless loop), we also use a fadein of the music over 2,5 seconds.

function playgameMusic (soundfile)
 
if musicisOn == true then 
audio.play (soundfile, {channel = 1, loops = -1 , fadein=2500})
end

end

The next functions are used to reset, pause or resume the music.

function resetMusic (soundfile)

if musicisOn == true then 
audio.stop(1)
audio.rewind (gamebgmusic)
end

end

function pauseMusic (soundfile)
if musicisOn == true then 
audio.pause()
end
end

function resumeMusic (channel)
if musicisOn == true then 
audio.resume(channel)
end
end

So the complete soundsfile.lua should look like this:

-- Rolly Bear World Project by Christian Peeters
-- See all tutorial @christian.peeters.com


--soundeffects 
audiolaunchbear = audio.loadSound ("audio/wee.mp3")
audiowinsound = audio.loadSound ("audio/winsound.wav")
audioclick = audio.loadSound ("audio/click.mp3")
audiolever = audio.loadSound ("audio/soundlever.mp3")
gamebgmusic = audio.loadStream ("audio/gamebgmonomusic.mp3")


soundisOn = true 
musicisOn = true 

audio.reserveChannels (1) -- one audio channel we need to reserve for the background music 


function playSFX (soundfile, volumelevel)

 	if soundisOn == true then 
local volumelevel = volumelevel or 1.0
audio.play(soundfile)
audio.setVolume(volumelevel, {soundfile} )
end 
end 

function playgameMusic (soundfile)
 
if musicisOn == true then 
audio.play (soundfile, {channel = 1, loops = -1 , fadein=2500})
end

end

function resetMusic (soundfile)

if musicisOn == true then 
audio.stop(1)
audio.rewind (gamebgmusic)
end

end

function pauseMusic (soundfile)
if musicisOn == true then 
audio.pause()
end
end

function resumeMusic (channel)
if musicisOn == true then 
audio.resume(channel)
end
end

Now we have everything in place to start integrating the sound effects in our game. We want sound effects when:
- Rollybear is launched, we want Rolly Bear to make a sound
- When the user switch the launch lever
- When a user clicks on one of the buttons (like level selection or pause button)
- When the user wins a level.

Use the github files to see the complete implementation because I show only how to call and use the functions we just created.

For example when the user clicks a button use this function:

playSFX(audioclick)

For example when Rolly Bear is launched use this function, and note that here we pass a volumelevel as well into the function to overrule the default which was set to 1.0

 playSFX(audiolaunchbear, 0.01) 

And to play the background music, set the following function in your enterScene of level01.lua

playgameMusic(gamebgmusic)

Now what we are still missing is the opportunity for the player to switch on and off the music. I implemented this behind the pause button of the game. Of course I will extend this later to the overall options menu of the game, but in essence the implementation and functionality are the same. So open you pauseoverlay.lua file.

We need to create two checkboxes which are default checked (see screenshot on top of this post), checked, means the music and sound effects are on (or playing). Remember we created two variables for this in the soundsfile.lua called:

soundisOn = true 
musicisOn = true 

When these variables are set to false, both the soundeffects (soundisOn) or the background music (musicisOn) are not active anymore.

Each checkbox has an onpress function, which defines what needs to happen when a user checks (or unchecks) the checkbox. This function is called switchPressed. I added and “id” to each checkbox to check which one of the two were clicked. In the if-statement we simple set the soundisOn or musicisOn (depending which one was clicked) to either false or true. Its not that complex :).

The complete pauseoverlay.lua file:

-- Rolly Bear World Project by Christian Peeters
-- See all tutorial @christian.peeters.com

local storyboard = require( "storyboard" )
local scene = storyboard.newScene()
local physics = require("physics")
local level01 = require("level01")
local sounds = require ("soundsfile")
local widget = require ("widget")
local params
local overlay


-- local forward references should go here --

local function btnTap(event)
playSFX(audioclick)
resetMusic(gamebgmusic)
event.target.xScale = 0.95
event.target.yScale = 0.95
storyboard.gotoScene (  event.target.destination, {params ={curLevel = params.curLevel}, time=800, effect = "fade"} )
return true
end

 function catchBackgroundOverlay(event)
return true 
end

-- Called when the scene's view does not exist:
function scene:createScene( event )
local group = self.view

local backgroundOverlay = display.newRect (group, leftScrn-1000, topScrn-1000, withScrn+1000, heightScrn+1000)
backgroundOverlay:setFillColor( black )
backgroundOverlay.alpha = 0.6
backgroundOverlay.isHitTestable = true
backgroundOverlay:addEventListener ("tap", catchBackgroundOverlay)
backgroundOverlay:addEventListener ("touch", catchBackgroundOverlay)

overlay = display.newImage ("images/overlayv2.png", 900 , 500)
overlay.x = centerX
overlay.y = centerY
group:insert (overlay)

local levelBtn = display.newImageRect ("images/levelBtn.png", 112, 116 )
levelBtn.x = centerX
levelBtn.y = centerY + overlay.height/2.2
levelBtn.destination = "levels" 
levelBtn:addEventListener("tap", btnTap)
group:insert(levelBtn)

local playBtn = display.newImageRect ("images/playBtn.png", 112, 116)
playBtn.x = centerX - overlay.width / 3
playBtn.y = centerY + overlay.height/2.2
local function hideOverlay(event)
playSFX(audioclick)
storyboard.hideOverlay("fade", 800)
resumeMusic(1)
end 
playBtn:addEventListener ("tap", hideOverlay)
group:insert(playBtn)

local reloadBtn = display.newImageRect ("images/reloadbutton.png" ,112, 116)
reloadBtn.x = centerX + overlay.width / 3 
reloadBtn.y = centerY + overlay.height/2.2
params = event.params
reloadBtn.destination = "reloading"
reloadBtn:addEventListener ("tap", btnTap)
group:insert (reloadBtn)
end



-- Called immediately after scene has moved onscreen:
function scene:enterScene( event )
local group = self.view

-- INSERT code here (e.g. start timers, load audio, start listeners, etc.)
--pauseMusic(gamebgmusic)



local function switchPressed (event)

local id = event.target.id
if id == "soundMusic" then 
if musicisOn == true then 
musicisOn = false
audio.stop(1)
else 
musicisOn = true 
playgameMusic (gamebgmusic)
end 
end

if id == "soundSFX" then 
if soundisOn == true then 
soundisOn = false
else 
soundisOn = true 
end 
end
end 

 
checkboxMusic = widget.newSwitch( { id = "soundMusic" , style = "checkbox", initialSwitchState = musicisOn , onPress = switchPressed} )
checkboxMusic.x = overlay.width/ 1.8
checkboxMusic.y = overlay.height/ 1.4
checkboxMusic.xScale = 2.0
checkboxMusic.yScale = 2.0 
group:insert(checkboxMusic)

local musicText = display.newText ("Switch on/off music", 0, 0, "Helvetica", 36)
musicText:setReferencePoint (display.CenterLeftReferencePoint)
musicText.x = overlay.width/ 1.8 + 50
musicText.y = overlay.height/ 1.4
group:insert(musicText)

checkboxSFX = widget.newSwitch( {id = "soundSFX" , style = "checkbox", initialSwitchState = soundisOn , onPress = switchPressed} )
checkboxSFX.x = overlay.width/ 1.8
checkboxSFX.y = overlay.height/ 1.1
checkboxSFX.xScale = 2.0
checkboxSFX.yScale = 2.0 
group:insert(checkboxSFX)

local soundText = display.newText ("Switch on/off sound effects", 0, 0, "Helvetica", 36)
soundText:setReferencePoint (display.CenterLeftReferencePoint)
soundText.x = overlay.width/ 1.8 + 50
soundText.y = overlay.height/ 1.1
group:insert(soundText)

end


-- Called when scene is about to move offscreen:
function scene:exitScene( event )
local group = self.view

-- INSERT code here (e.g. stop timers, remove listeners, unload sounds, etc.)
-- Remove listeners attached to the Runtime, timers, transitions, audio tracks

end


-- Called prior to the removal of scene's "view" (display group)
function scene:destroyScene( event )
local group = self.view


-- INSERT code here (e.g. remove listeners, widgets, save state, etc.)
-- Remove listeners attached to the Runtime, timers, transitions, audio tracks

end


---------------------------------------------------------------------------------
-- END OF YOUR IMPLEMENTATION
---------------------------------------------------------------------------------

-- "createScene" event is dispatched if scene's view does not exist
scene:addEventListener( "createScene", scene )

-- "enterScene" event is dispatched whenever scene transition has finished
scene:addEventListener( "enterScene", scene )

-- "exitScene" event is dispatched before next scene's transition begins
scene:addEventListener( "exitScene", scene )

-- "destroyScene" event is dispatched before view is unloaded, which can be
-- automatically unloaded in low memory situations, or explicitly via a call to
-- storyboard.purgeScene() or storyboard.removeScene().
scene:addEventListener( "destroyScene", scene )


---------------------------------------------------------------------------------

return scene

Here is the new pauseoverlay.lua file. I hope this post was useful. You can find the updated files in my GitHub.

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

*