Going Object-Oriented with Corona SDK and Rolly Bear World

I have been working on Rolly Bear World now for almost two months and some of my lua files are getting very crowded with code blocks and repetition of similar code patterns. In this post, we will not add any additional functionality to Rolly Bear World; but we will be restructuring some of the code and creating some Object-Oriented patterns.

Start with creating a new lua file in your project and call it fixedScene.lua. In this lua file we will add all the static scene objects of the levels: the invisible walls, the 2 bushes, the background bush, the floor, the two wooden signs, the chest, and the rock. In fixedScene.lua create a function called createStaticBackgroundElements and copy/ paste all the static elements in this function. Next create a global group variable called: myStaticgroup = display.newGroup. We need to insert each background element in this group. So we can handle the removal of these objects between scenes later via our Storyboard implementation.

In fixedScene.lua:

myStaticgroup = display.newGroup()

function createStaticBackgroundElements()
-- create all fixed background elements
topWall = display.newRect( 0, 0, display.contentWidth, 0 )
bottomWall = display.newRect( 0, display.contentHeight - 10, display.contentWidth, 0 )
leftWall = display.newRect( 0, 0, 0, display.contentHeight )
rightWall = display.newRect( display.contentWidth - 10, 0, 0, display.contentHeight )
topWall.myName = "topwall"
bottomWall.myName = "bottomwall"
leftWall.myName = "leftwall"
rightWall.myName = "rightwall"
physics.addBody(topWall, "static", {density = 1.0, friction = 0, bounce = 1, isSensor = false})
physics.addBody(bottomWall, "static", {density = 1.0, friction = 0, bounce = 1, isSensor = false})
physics.addBody(leftWall, "static", {density = 1.0, friction = 0, bounce = 1, isSensor = false})
physics.addBody(rightWall, "static", {density = 1.0, friction = 0, bounce = 1, isSensor = false})

bush01 = display.newImageRect ("images/bush01.png", 384	, 145	 )
bush01.y = heightScrn - bush01.height 
bush01.x = display.screenOriginX + 128
bush01.alpha = 1.0

bush02 = display.newImageRect ("images/bush01.png", 384	, 145	 )
bush02.y = heightScrn - bush02.height 
bush02.x = display.screenOriginX + 370
bush02.alpha = 0.7

backgroundBush = display.newImageRect ("images/backgroundbush.png", 1428	, 128	 )
backgroundBush.y = heightScrn - backgroundBush.height /2
backgroundBush.x = centerX
backgroundBush.alpha = 0.7

floor = display.newImageRect ("images/floortitlescreen.png", 1425	, 156	 )
floor.x = centerX; floor.y = heightScrn
physics.addBody(floor, "static", {density = 1.0, friction = 0, bounce = 1, isSensor = false})
floor.myName = "floor"

rock = display.newImageRect ("images/rock100.png", 300, 96)
rock.x = display.screenOriginX + 160; rock.y = heightScrn	- floor.height / 1.5

woodSignStart = display.newImageRect ("images/woodsignleft.png", 100, 100)
woodSignStart.x = display.screenOriginX + 250; woodSignStart.y = heightScrn	- floor.height / 2
woodSignStart.rotation = 10

woodSignEnd = display.newImageRect ("images/woodsignright.png", 105, 105)
woodSignEnd.x = withScrn - 250; woodSignEnd.y = heightScrn + 200
woodSignEnd.rotation = -10
transition.to( woodSignEnd, { time=2000, x = withScrn - 250, y  =heightScrn	- floor.height / 3 })

chestClosed = display.newImageRect("images/chestclosed.png", 128 , 128)
chestClosed.x = withScrn - chestClosed.width 
chestClosed.y = floor.y - chestClosed.height

switchOff = display.newImageRect ("images/woodleverup.png", 64, 64)
switchOff.x = rock.x -10; switchOff.y = rock.y + 10

myStaticgroup:insert(bush01)
myStaticgroup:insert(backgroundBush)
myStaticgroup:insert(bush02)
myStaticgroup:insert (floor)
myStaticgroup:insert (rock)
myStaticgroup:insert (woodSignEnd)
myStaticgroup:insert (woodSignStart)
myStaticgroup:insert (chestClosed)
myStaticgroup:insert (switchOff)

end

Now open your level01.lua file and load this newly fixedScene.lua file.

local fixedscene = require("fixedScene")

Add in scene:createScene, scene:enterScene, scene:exitScene, and scene:destroyScene your new group, so storyboard handles them correctly.

myStaticgroup = self.view 

Now put in your scene:createScene the function we just created to load all background elements

createStaticBackgroundElements()

This is all to add all the fixed background elements to a level. We just need to call createStaticBackgroundElements() in our level files. Pretty cool :)

Open now again your fixedScene.lua and we will add also the green pipe and rolly bear to the levels via fixedScene.lua. Create two new functions. I made this separate from createStaticBackgroundElements() as they are not static background object but have some functionality which might change per level. This is just for myself to find these code blocks quickly, you could add these as well to the createStaticBackgroundElements function.

function createPipe ()
pipe = display.newImageRect ("images/pipe.png", 144, 224)
pipe.rotation = 90
physics.addBody(pipe, "static", {density = 1, friction = 0, bounce = 1, isSensor = true  })
myStaticgroup:insert (pipe)
end

function createRolly ()
rollybear = display.newImage ("images/rollybear40.png")
rollybear.myName = "rollybear"
physics.addBody(rollybear, "dynamic", {density = 1, friction = 0, bounce = 1, isSensor = false, radius = 0})
rollybear.isBullet = true
myStaticgroup:insert (rollybear)
rollybear:toBack()
end

Now, we create a constructors to set the coordinates of Rolly Bear and the Green Pipe, I created a constructor for this as they will change on a level basis. This way I call the setCoordinates function where I want from the Rolly Bear Word project, pass the object and coordinates and the constructor takes care of it. (I think this is Really Cool :) ).

function setCoordinates(object, x, y)    
-- constructor for set Coordinates of a display Object
object.x = x    object.y = y 
end

The constructor takes 3 variables: the object (e.g. RollyBear), and two coordinates the X and Y.

Now open your level01.lua file and add the following functions.

createPipe ()
setCoordinates (pipe, leftScrn, display.screenOriginY + pipe.height/2 )


createRolly()
setCoordinates ( rollybear, leftScrn+10, pipe.y )

As you can see we create the pipe (createPipe()) and Rolly Bear (createRolly()). In addition we set the position of each by calling setCoordinates and passing in the object and the X and Y coordinates.

So we are done, we add some object-orientation to our Rolly Bear World Project and made our working files better to read.

The complete fixedScene.lua file should now look like this:

-- Rolly Bear World Project by Christian Peeters
-- See all tutorial @christian.peeters.com
-- All fixed scene elements of levels and a contructor for the location of the Pipe and RollyBear
myStaticgroup = display.newGroup()

function createStaticBackgroundElements()
-- create all fixed background elements
topWall = display.newRect( 0, 0, display.contentWidth, 0 )
bottomWall = display.newRect( 0, display.contentHeight - 10, display.contentWidth, 0 )
leftWall = display.newRect( 0, 0, 0, display.contentHeight )
rightWall = display.newRect( display.contentWidth - 10, 0, 0, display.contentHeight )
topWall.myName = "topwall"
bottomWall.myName = "bottomwall"
leftWall.myName = "leftwall"
rightWall.myName = "rightwall"
physics.addBody(topWall, "static", {density = 1.0, friction = 0, bounce = 1, isSensor = false})
physics.addBody(bottomWall, "static", {density = 1.0, friction = 0, bounce = 1, isSensor = false})
physics.addBody(leftWall, "static", {density = 1.0, friction = 0, bounce = 1, isSensor = false})
physics.addBody(rightWall, "static", {density = 1.0, friction = 0, bounce = 1, isSensor = false})

bush01 = display.newImageRect ("images/bush01.png", 384	, 145	 )
bush01.y = heightScrn - bush01.height 
bush01.x = display.screenOriginX + 128
bush01.alpha = 1.0

bush02 = display.newImageRect ("images/bush01.png", 384	, 145	 )
bush02.y = heightScrn - bush02.height 
bush02.x = display.screenOriginX + 370
bush02.alpha = 0.7

backgroundBush = display.newImageRect ("images/backgroundbush.png", 1428	, 128	 )
backgroundBush.y = heightScrn - backgroundBush.height /2
backgroundBush.x = centerX
backgroundBush.alpha = 0.7

floor = display.newImageRect ("images/floortitlescreen.png", 1425	, 156	 )
floor.x = centerX; floor.y = heightScrn
physics.addBody(floor, "static", {density = 1.0, friction = 0, bounce = 1, isSensor = false})
floor.myName = "floor"

rock = display.newImageRect ("images/rock100.png", 300, 96)
rock.x = display.screenOriginX + 160; rock.y = heightScrn	- floor.height / 1.5

woodSignStart = display.newImageRect ("images/woodsignleft.png", 100, 100)
woodSignStart.x = display.screenOriginX + 250; woodSignStart.y = heightScrn	- floor.height / 2
woodSignStart.rotation = 10

woodSignEnd = display.newImageRect ("images/woodsignright.png", 105, 105)
woodSignEnd.x = withScrn - 250; woodSignEnd.y = heightScrn + 200
woodSignEnd.rotation = -10
transition.to( woodSignEnd, { time=2000, x = withScrn - 250, y  =heightScrn	- floor.height / 3 })

chestClosed = display.newImageRect("images/chestclosed.png", 128 , 128)
chestClosed.x = withScrn - chestClosed.width 
chestClosed.y = floor.y - chestClosed.height

switchOff = display.newImageRect ("images/woodleverup.png", 64, 64)
switchOff.x = rock.x -10; switchOff.y = rock.y + 10

myStaticgroup:insert(bush01)
myStaticgroup:insert(backgroundBush)
myStaticgroup:insert(bush02)
myStaticgroup:insert (floor)
myStaticgroup:insert (rock)
myStaticgroup:insert (woodSignEnd)
myStaticgroup:insert (woodSignStart)
myStaticgroup:insert (chestClosed)
myStaticgroup:insert (switchOff)

end

function createPipe ()
pipe = display.newImageRect ("images/pipe.png", 144, 224)
pipe.rotation = 90
physics.addBody(pipe, "static", {density = 1, friction = 0, bounce = 1, isSensor = true  })
myStaticgroup:insert (pipe)
end

function createRolly ()
rollybear = display.newImage ("images/rollybear40.png")
rollybear.myName = "rollybear"
physics.addBody(rollybear, "dynamic", {density = 1, friction = 0, bounce = 1, isSensor = false, radius = 0})
rollybear.isBullet = true
myStaticgroup:insert (rollybear)
rollybear:toBack()
end


function setCoordinates(object, x, y)    
-- constructor for set Coordinates of a display Object
object.x = x    object.y = y 
end

And our new levels01.lua file should now look like this:

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

-- external Moduals & libraries --

local storyboard = require( "storyboard" )
local scene = storyboard.newScene()
local fixedscene = require("fixedScene")


-- TexturePacker --

local sheetInfo = require("platformSheet")
local myPlatformSheet = graphics.newImageSheet( "platformsheet.png", sheetInfo:getSheet() )

-- Physics --

local physics = require("physics")
local physicsData = (require "platformshapes").physicsData(1.0)
physics.start()
physics.setGravity(0, 0)
--physics.setDrawMode( "hybrid" )

-- GLobal Variables --

local onCollision
local audiolaunchBear
local platform




local function btnTap(event)
storyboard.gotoScene (  event.target.destination, {effect = "fade"} )
return true
end


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

-- Creation of background elements based on fixedScene.lua --- 

createStaticBackgroundElements()


createPipe ()
setCoordinates (pipe, leftScrn, display.screenOriginY + pipe.height/2 )


createRolly()
setCoordinates ( rollybear, leftScrn+10, pipe.y )


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


local function movePlatform(event)
local platformTouched = event.target
   
        if (event.phase == "began") then
                display.getCurrentStage():setFocus( platformTouched )
 
 	 -- here the first position is stored in x and y         
                platformTouched.startMoveX = platformTouched.x
platformTouched.startMoveY = platformTouched.y

             
        elseif (event.phase == "moved") then
                
                -- here the distance is calculated between the start of the movement and its current position of the drag	 
                platformTouched.x = (event.x - event.xStart) + platformTouched.startMoveX
platformTouched.y = (event.y - event.yStart) + platformTouched.startMoveY
                elseif event.phase == "ended" or event.phase == "cancelled"  then
             
              -- here the focus is removed from the last position
                    display.getCurrentStage():setFocus( nil )

                end
                 return true
        end



platformNames = {"platform-brown128", "platform-brownbrick128", "platform-green64", "platform-rock128", "crate64"};

for x =1, #platformNames do
local platformNum = platformNames[x]
platform = display.newSprite( myPlatformSheet , {frames={sheetInfo:getFrameIndex(platformNum)}} )
platform.x = display.screenOriginX + 100
platform.y = 150 + 75 * x 
physics.addBody( platform, physicsData:get(platformNum))
platform.bodyType = "static"  
local function enableRotation()
if (objectRotation == false) then
objectRotation = true 
else
objectRotation = false 
end
end
platform:addEventListener("touch", movePlatform)
group:insert(platform)

end


local function launchRollyBear (event)
display.remove( switchOff)
audio.play(audioaunchBear)
audio.setVolume(0.01, {audioaunchBear} ) 
local switchOn = display.newImageRect ("images/woodleverdown.png", 64, 64)
switchOn.x = rock.x -10; switchOn.y = rock.y + 10
group:insert(switchOn)
rollybear:applyForce(800, 30)
rollybear:toFront()
local function setPipeNormal()
pipe.xScale = 1.0
pipe.yScale = 1.0
end
transition.to( pipe, {time=100, xScale = 1.2, yScale = 1.2, onComplete=setPipeNormal}  )
end
switchOff:addEventListener ("tap",launchRollyBear)



local backbtn = display.newImageRect ("images/reloadbutton.png", 112, 117)
backbtn.y = centerY 
backbtn.x = centerX
backbtn.destination = "levels" 
backbtn:addEventListener("tap", btnTap)
group:insert(backbtn)
end


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


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

--soundeffects 
audioaunchBear = audio.loadSound ("audio/wee.mp3")


 function onCollision(event)
if(event.object1.myName=="rightwall" and event.object2.myName=="rollybear")
or
(event.object1.myName=="leftwall" and event.object2.myName=="rollybear")
or 
(event.object1.myName=="topwall" and event.object2.myName=="rollybear")
or 
(event.object1.myName=="bottomwall" and event.object2.myName=="rollybear")
or
(event.object1.myName=="floor" and event.object2.myName=="rollybear")
then
-- temp solution for gameover
  print("yeah collision works, I hit the "..event.object1.myName)
  gameoverbtn = display.newText(  "GameOver", 0, 0, "Helvetica", 50)
  gameoverbtn.x = centerX
  gameoverbtn.y = centerY
  display.remove( rollybear)
  gameoverbtn.destination = "levels" 
  gameoverbtn:addEventListener ("touch", btnTap)
  group:insert(gameoverbtn)
 
  end
end




Runtime:addEventListener("collision", onCollision)


end



-- Called when scene is about to move offscreen:
function scene:exitScene( event )
local group = self.view
myStaticgroup = 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
myStaticgroup = 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

Check my Github for the updates files.

See you next time when we get into rotation of platforms.

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>

*