Tuesday, 22 April 2014

Corona Components Module Wrapper

I do like OOP stuff. Sometimes in Corona you feel like you are fighting a war with the API though. But after a fair bit of meddling, I managed to create an OOP library for Composer, that allows you to implement scenes as objects deriving from a subclass. It always struck me with Scenes that there is a lot of duplicate code about.

Unfortunately, there is no current way round Composer's number 1 limitation - I think - (without hacks anyway !) - that the only way you can create a new scene is by requiring a scene file.

A scene looks a bit like this (this is code from the demo)

local oopScene = require("oopscene")

local Scene2 = oopScene:new()

function Scene2:create(event) 
   self.textBox = display.newText( "Hello world Scene 2 !",160,100,native.systemFont,24)

function Scene2:showOnScreen(event)
   self.textBox:addEventListener( "tap", self )

function Scene2:tap(e)
   return true

function Scene2:hideOnScreen(event)

function Scene2:getEffect()
   return "flip"

return Scene2:new():getScene()

This is actually real code from the example files. It isn't really terribly complicated ; all the OOP wrapper really does is to add the event listeners and split the four events up into six methods. So here, we have create as normal, but we have showOnScreen and hideOnScreen which are sub-events of show and hide, which are called both before and after displaying (or destroying). There are also showOffScreen, hideOffScreen and destroy - the advantage of this approach is if you don't implement the methods the events are just ignored. (actually there are default handlers in the base class !)

The rest of the code is fairly straightforward. It creates a text object and inserts it into the view associated with the scene (there's a helper function insertView() which saves a call here). showOnScreen() inserts a listener, hideOnScreen() removes it.

the getEffect() method gets the transition for leaving this scene, though you can provide it as normal (gotoScene() you may note, does not have an options provided - it defaults to getEffect())

The only thing that isn't part of the wrapper is the tap() table listener which calls gotoScene().

The oddity is at the bottom. This is required because this is designed to be called via gotoScene(). gotoScene expects a real scene object to be returned, not this wrapped one. So the last line creates a new instance of class Scene2, then returns its scene, which is not ideal.

To help with these problems, there is a static method getCurrentSceneInstance() which gets the instance of the scene that is currently being delayed.

What else does it do ; well, this is the shorter of two scenes (the demo has two scenes and an overlay), and the other scene has a counter ; there is a system for persisting data (because scenes can be garbage collected by composer) which is used to persist this counter.  Data that does not exist beyond the life of the event can be used in the Scene as a member variable as normal.

There is also another method/event 'frameEvent' which is called on the enterFrame event, this does need to be programatically turned on. It also has another text item (a bit like the one above) except tapping this one opens an overlay rather than switches to another scene.


No comments:

Post a Comment