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.