Corona Game Controller – game loop management

All games need a game loop. It is the guts of your game and where all of the action happens, so it is important that it is controlled well and that it doesn’t get out of hand. I like to keep things super organised and prefer to only have one game loop happening in my game. So for this, I always use a singleton class. So whilst developing my game with Lua & the Corona SDK I endeavored to maintain this architecture within my game. The GameController class that I created is used to control all of the timings and enterFrame animations. It needs to be callable from anywhere within my game and I need to be able to add callback functions to the game loop and remove them for that case. Using a singleton is perfect as it means that I know that only one GameController is in use and if I need to add an enterFrame loop within one of my levels – in fact I usually use them in all of them – I just make a call to the GameController’s addCallback method to add a method from my level to the GameController’s loop.

  1. GameController.getInstance().addCallback(levelOneLoop, 'levelOneLoop')

The two parameters for the addCallback method are the actual method to be added as a callback and a name for the method as a String. This string is used to add the method to a table with a reference value, it also helps when removing the game from the loop, by calling the removeCallbackByName method, which removes the method from the main game loop.

  1. GameController.getInstance().removeCallbackByName('levelOneLoop')

The GameController also contains a method called beginGame, which is called to begin the game, as well as pause, stop & resume methods to control the loop at anytime.

Anyway, here is the class in its entirity:

  1. local _instance, callbacks = nil, {}
  2.  
  3. function GameController.getInstance()
  4.     if not _instance then
  5.         _instance = GameController
  6.     end
  7.  
  8.     local function gameLoop()
  9.         for i, callback in pairs(callbacks) do
  10.             if callback ~= nil then
  11.                 callbacks[i]()
  12.             end
  13.         end
  14.     end
  15.  
  16.     _instance.getCallbacks = function()
  17.         return callbacks
  18.     end
  19.  
  20.     _instance.removeCallbackByName = function(name)
  21.         callbacks[name] = nil
  22.     end
  23.  
  24.     _instance.addCallback = function(callback, name)
  25.         callbacks[name] = callback
  26.     end
  27.  
  28.     _instance.clearAllCallbacks = function()
  29.         callbacks = {};
  30.     end
  31.  
  32.     _instance.stop = function()
  33.         Runtime:removeEventListener("enterFrame", gameLoop)
  34.     end
  35.  
  36.     _instance.pause = function()
  37.         _instance.stop();
  38.     end
  39.  
  40.     _instance.resume = function()
  41.         _instance.beginGame();
  42.     end
  43.  
  44.     _instance.beginGame = function()
  45.         Runtime:addEventListener("enterFrame", gameLoop)
  46.     end
  47.  
  48.     _instance.main = function()
  49.         _instance.beginGame()
  50.     end
  51.  
  52.     return _instance
  53. end
  54.  
  55. function GameController:new()
  56.     assert(nil, 'GameController is a singleton and cannot be instantiated - use getInstance() instead')
  57. end

Happy coding.

Posted in Games, Lua | Tagged , | Leave a comment

Corona SDK Screen manager class

Following on from my previous post and my experiences with Lua & the Corona SDK, in the development of my current game I have created a simple manager class for transitioning screens when user input defines a screen change resulting in a needed transition. The class is very simple and implements the Singleton pattern I outlined in my previous post, the details are as below and as I have said it is very simple and does one thing only as all classes should – manages the transition of screens.

  1. --
  2. -- User: Shane Johnson
  3. -- ScreenManager class to handle screen transitions
  4. --
  5.  
  6. ScreenManager = {}
  7.  
  8. local _instance = {}
  9.  
  10. function ScreenManager:getInstance()
  11.     if not _instance then
  12.         _instance = ScreenManager
  13.     end
  14.  
  15.     function removeScreen(screen)
  16.         if screen ~= nil then
  17.             screen:removeSelf()
  18.         end
  19.     end
  20.  
  21.     _instance.changeScreenLeft = function(screenOne, screenTwo, clearScreen)
  22.             screenTwo.x = -screenTwo.width
  23.             screenTwo.alpha = 0
  24.             if clearScreen == true then
  25.                 transition.to(screenOne, {
  26.                     time = 300,
  27.                     x = display.contentWidth,
  28.                     alpha = 0,
  29.                     onComplete = function()
  30.                         removeScreen(screenOne)
  31.                     end
  32.                 })
  33.             else
  34.                 transition.to(screenOne, { time = 300, alpha = 0, x = display.contentWidth })
  35.             end
  36.             transition.to(screenTwo, { time = 300, x = 0, alpha = 1 })
  37.     end
  38.  
  39.     _instance.changeScreenRight = function(screenOne, screenTwo, clearScreen)
  40.             screenTwo.x = screenTwo.width
  41.             screenTwo.alpha = 0
  42.             if clearScreen == true then
  43.                 transition.to(screenOne, {
  44.                     time = 300,
  45.                     x = display.contentWidth,
  46.                     alpha = 0,
  47.                     onComplete = function()
  48.                         removeScreen(screenOne)
  49.                     end
  50.                 })
  51.             else
  52.                 transition.to(screenOne, { time = 300, alpha = 0, x = -display.contentWidth })
  53.             end
  54.             transition.to(screenTwo, { time = 300, x = 0, alpha = 1 })
  55.         end
  56.  
  57.     return _instance
  58. end
  59.  
  60. function ScreenManager:new()
  61.     assert(nil, 'ScreenManager is a singleton and cannot be instantiated - use getInstance() instead')
  62. end

In order to use it you would need to would need to handle the instatiation yourself and the tell the ScreenManager to handle the transition, so:

[lua]
gameView = GameView:new()
ScreenManager:getInstance().changeScreenLeft(menuView, gameView)
[/lua]

The two change functions changeScreenLeft and changeScreenRight both do as the function name defines and also allow for a flag to be passed in to define whether the transitioning screen should be removed once the transition is finished.

Happy coding.

Posted in Games, Lua | Tagged , | Leave a comment

Singletons in Lua

Since learning Lua and playing around with Corona and as it is not a very OOP language and is very script based, even more so that javascript, I felt like having a go at trying to see if it was possible to:

  • Structure my projects in a class based way to make them seem more familiar and cleanly organised
  • Mimic some design patterns to find out some of the strength / weaknesses of the language

My first task was structuring the projects I was creating to mimic a more OOP structure, this at first wasn’t easy as most of the examples I could find were very much scripts full of procedural code. Then I stumbled upon Jesse Warden’s Robotlegs for Corona. Written by a fellow actionscripter it was structured in a manner that was very familiar to me and helped a lot in figuring out the best methods for structuring my own code. So after a little playing I decided to see if I could easily create a singleton class in Lua. Now the simplest method of creating a singleton in Lua would be to create a name space with static methods using the ‘:’ operator, which makes your method calls static. This can also be done in actionscript, but multiple instances within a project can still be created if called within different contexts, so the only sure fire way is with the ‘getInstance()’ call. So after a little playing I managed to structure a very simple Lua singleton, which I found to be a lot simpler than I expected:

  1. Singleton = {};
  2.  
  3. local _instance;
  4.  
  5. function Singleton.getInstance()
  6.     if not _instance then
  7.         _instance = Singleton;
  8.     end
  9.  
  10.     --'any new methods would be added to the _instance object like this'
  11.     _instance.getType = function()
  12.         return 'singleton';
  13.     end
  14.  
  15.     return _instance
  16. end
  17.  
  18. function Singleton:new()
  19.     print('Singleton cannot be instantiated - use getInstance() instead');
  20. end

Now my only gripe about this class is that the ‘Singleton’ object can still be access globally and altered from outside of the class, but I guess this is just something you have to get used to with dynamic languages. This may not be the best way to do things but during my tests the object created and returned was always the same object, so if you think this is wrong and could be done better please do let me know.

Posted in Games, Lua | Tagged , | Leave a comment