Alright, the title might be a bit over the top… what we are about to do is look at some of the most popular 2D game engines powered by Lua. First there will be a matrix of features, to give you an “at a glance” view of what each engine offers. Then we will follow up with a simple Hello World example for each, so you can see what the code would look like. Hopefully this will help you decide which engine is right for you.
Engine Features Matrix
Corona |
Gideros |
LÖVE
|
Moai |
|
Site Link
|
Link | Link | Link | Link |
Price |
199$ /year iOS 199$ /year Android 349$ /year Both Free trial available |
149$ /year Indie 449$ /year Pro 0$ /year Community |
Free | Free |
Free Limitations |
Cannot publish to app store with free version | Mandatory splash screen Pro required if income greater than 100K$ |
N/A | N/A |
Target Platforms |
iOS Android |
iOS Android (Mac and Windows under development) |
Windows Mac Linux |
iOS Android Windows Mac Linux (in late stage development) Chrome NacL |
Dev Platforms |
Windows Mac |
Windows Mac |
Windows Mac Linux |
Windows Mac Linux |
Support Available |
Forum Paid support |
Forum | Forum | Forum Paid Support |
Open Source |
No | No | Yes | Yes |
Books |
Corona SDK Mobile Game Development | N/A | N/A | N/A |
Other Details |
Builds occur on Corona Labs servers, internet connection required 3rd party tools available Enterprise version available |
Includes it’s own IDE Gideros Studio | Paid cloud computing offering for back-end services | |
Example Published Games |
Go Ninja The Lorax (Movie Game) |
Joustin Beaver Cerberus: The Puppy |
N/A? Unpublished list |
Crimson Steam Pirates Strikefleet Omega |
* Note, I gave iTunes link only, although many of those games are also available on Google Play.
Now we are going to look at a simple Hello World app written with each suite. I do not pretend mastery of any of these suites, or Lua in general, so take the code for what it’s worth. If you wish to submit a better rendition, please do so!
In this sample we are going to create a window at a resolution of 1280×800, then we are going to start a background song looping ( Richard Wagners – Ride of the Valkyrie taken from here ). Then we are going to create a Hello World text/graphic centered to the screen, and position it where ever the user clicks/touches. Some files handle window creation in a different file, some handle it in a single file. That is why some versions have two lua files, while others have only one.
Corona SDK Hello World
config.lua
-- config.lua application = { content = { width = 1280, height = 800, scale = "letterbox" }, }
main.lua
-- HelloWorld sample -- Load audio file local song = audio.loadSound("../../Media/Ride_of_the_Valkyries.mp3") -- set volume to 50% audio.setVolume(0.5) -- play audio file, looping forever audio.play(song,{ channel=1,loops=-1}) -- create text to display on screen in 72point font local helloText = display.newText("Hello World!",0,0,native.systemFont,72) -- center to screen helloText.x = display.contentWidth/2 helloText.y = display.contentHeight/2 -- red helloText:setTextColor(255,0,0) -- function to handle touch event, move helloText to the touch location function onTouchHandler(event) helloText.x = event.x helloText.y = event.y end -- register touch function to respond to global touch events Runtime:addEventListener("touch",onTouchHandler)
Gideros
main.lua
-- Helloworld sample -- setup our window to our 1280x800 resolution application:setLogicalDimensions(1280,800) application:setOrientation(Application.LANDSCAPE_LEFT) -- Load song, cannot use relative path to parent directory since file needs to be added to project local song = Sound.new("Ride_of_the_Valkyries.mp3") -- play audio file, looping forever local soundChannel = song:play(0,math.huge) -- Set song volume to 50%, not set globally soundChannel:setVolume(0.5) -- need to load a ttf font, size cannot specify character size in TextField local font = TTFont.new("arial.ttf",72,false) -- create text to display on screen local helloText = TextField.new(font,"Hello World!") -- center to screen helloText:setPosition( application:getLogicalWidth()/2 - helloText:getWidth()/2, application:getLogicalHeight()/2 + helloText:getHeight()/2) -- set text to red, color is hex encoding helloText:setTextColor(0xff0000) -- display text stage:addChild(helloText) -- function to handle touch event, move helloText to the touch location function onTouchHandler(event) helloText:setPosition(event.x - helloText:getWidth()/2,event.y + helloText:getHeight()/2) end -- register touch function to respond to global touch events stage:addEventListener(Event.TOUCHES_BEGIN,onTouchHandler) -- The above doesn't work in the simulator, so handle mouse too stage:addEventListener(Event.MOUSE_DOWN,onTouchHandler)
LÖVE
love.conf
function love.conf(t) t.screen.width = 1280 t.screen.height = 800 end
main.lua
-- love2d works slightly different, expecting users to implement methods that will be called within the game loop -- such as love.draw() and love.update() -- create a 72 point font using the system default font = love.graphics.newFont(72) -- set the font active love.graphics.setFont(font) -- set red as the active color love.graphics.setColor(255,0,0,255) -- load audio file local song = love.audio.newSource("Ride_of_the_Valkyries.ogg") -- we want to loop, we want to loop, we want to loop, we want t^Z song:setLooping(true) -- set volume to 50% love.audio.setVolume(0.5) -- play song love.audio.play(song) -- create a variable for print coordinates to update on touch, default to screen center -- LOVE does not have a positionable text object, so we call print each frame local x = love.graphics.getWidth()/2 local y = love.graphics.getHeight()/2 local stringWidth = font:getWidth("Hello World!") local stringHeight = font:getHeight("Hello World!") -- This function is called once per frame to draw the screen function love.draw() love.graphics.print("Hello World!",x - stringWidth/2,y-stringHeight/2) end -- called on click, move our print x,y to the click location -- no touch handler because LOVE is desktop only function love.mousepressed(mouse_x,mouse_y,button) x = mouse_x y = mouse_y end
Moai
main.lua
-- create the window, viewport and layer MOAISim.openWindow("Window", 1280, 800) local viewport = MOAIViewport.new() viewport:setSize(1280,800) viewport:setScale(1280,800) local layer = MOAILayer2D.new() layer:setViewport(viewport) -- Let Moai know we want this layer rendered MOAIRenderMgr.pushRenderPass(layer) -- Initialize the audio system MOAIUntzSystem.initialize() -- set volume to 50% MOAIUntzSystem.setVolume(0.5) -- load the song song1 = MOAIUntzSound.new() song1:load("../Media/Ride_of_the_Valkyries.ogg") -- play audio file, looping forever song1:setLooping(true) song1:play() -- save memory by only rendering the chars we need chars = 'Helo Wrd!' -- create a font local font = MOAIFont.new() font:loadFromTTF('../Media/arial.ttf',chars,72) -- create and position text centered local helloText = MOAITextBox.new() helloText:setString('Hello World!') helloText:setFont(font) helloText:setYFlip(true) helloText:setRect(-640,-400,640,400) helloText:setAlignment(MOAITextBox.CENTER_JUSTIFY,MOAITextBox.CENTER_JUSTIFY) layer:insertProp(helloText) -- handle mouse/touch click events function handleClickOrTouch(x,y) helloText:setLoc(layer:wndToWorld(x,y)) end if MOAIInputMgr.device.pointer then -- Mouse based device MOAIInputMgr.device.mouseLeft:setCallback( function(isButtonDown) if(isButtonDown) then handleClickOrTouch(MOAIInputMgr.device.pointer:getLoc()) end end ) else -- Touch based device MOAIInputMgr.device.touch:setCallback( function(eventType,idx, x, y, tapCount) if eventType == MOAITouchSenser.TOUCH_DOWN then handleClickOrTouch(x,y) end end ) end
My Opinions
First off, take these with a grain of salt, these are just my initial impressions and nothing more. Obviously it is all very subjective. It is also stupid to say X is best, they are all good libraries, each with their own strengths and weaknesses. I think that is perhaps the greatest surprise, not one of these four options is bad.
Love: Not a big fan of the abstraction and it forces a design on you, but this isn’t necessarily a bad thing, especially for a beginner. Good for beginners, so-so to slight levels of documentation but absolutely wonderful reference materials. Only library in this group with no mobile support, which is a big deal. Open source and free, targeted to hobbyist. Few ( none? ) commercial games. All told, it reminded me a lot of the Python based PyGame, which is frankly a great beginners library. Also the name “Love” proved a gigantic handicap, as it made Googling for anything beyond the Love2D website very difficult. This is the downside to using a very generic name for your library ( cough… GamePlay, I’m looking at you! ). The generic name really did prove to be a pain in the butt at times. Love is certainly a good library, but probably not for professional use, at least, as is.
Corona: Most polished of the four. Best documentation, good API. Only library with published books available and good tooling support. Also most expensive and closed. If it isn’t part of Corona, you are hosed. Have to pay more for native access. Great developer backing, lots of successful companies using Corona. Corona is certainly a great library, although thanks to the price tag, it wont appropriate for all developers. The lack of freedom ( no source, paying for native access ) are definitely the biggest drawbacks.
Gideros: Ok-good documentation, good reference but other material is a bit too scattered. IDE is a HUGE boon for newer developers, especially with auto-completion. That said, the IDE got a bit flaky at times too. API itself a bit less intuitive ( to me ). Licensing terms reasonable ( better than Corona, worse than Love and Moai ), same for price. Good choice for beginner who wants to support mobile, lack of major published games a bit of a deterrent for professional developers, as is the lack of source code.
Moai: Moai is certainly the most difficult of the four, and the documentation is in heavy need of updating. The reference itself is actually very good, where it exists. In some cases there is none and in others, it is lacking or out-dated. The developers are aware and this is a priority for them to fix. On the other hand, Moai is also the most flexible by a mile. The code ( as you can see from the example above ), is a bit more verbose, but that is because the library makes less decisions for you. This is a double edged sword of flexibility vs ease, and Moai slants heavily towards flexibility. Supports the most targets of all the libraries, has complete source code, and more importantly, the source code is very well written and very easy to read. Like Corona, there are some very good shipped games.
Final verdict:
For a commercial product for iOS/Android, I would select Moai. The API is a natural fit to my coding style ( I prefer flexibility over accessibility for time critical code ) and the C++ source code is a great boon to me, but to a non-C++ programmer, this would obviously be less important. Also of course, the price is nice. Most importantly, the open nature means I know I will never encounter a problem that I can’t code my way out of, the biggest downside to Corona. If it wasn’t for the open source nature of Moai, I would probably go with Corona for the sake of it’s excellent documentation and clean API.
If I was just starting out, I would be torn between Gideros and LOVE. LOVE is certainly the most beginner friendly, but the turn-key all in one nature of Gideros… you literally install, load the studio, write some code and hit play… with full autocomplete code editing. This really is a huge deal! In it’s favour over LOVE is also the support for mobile platforms. That said, if the API isn’t to your liking, or you struggle with it, Love is easily the most accessible code wise. I will be looking a bit closer at Gideros in the future. Ran into a few annoyances during my brief exposure, like the inability to set anchor points for TextField values ( http://bugs.giderosmobile.com/issues/41 ), forcing me to wait for the feature to be added by someone else.
This isn’t to say Corona is bad, it obviously isn’t. It is polished, has the best documentation and a very solid/natural API. For me though, the lack of flexibility and access to source code provides outweigh it’s advantages. If the source isn’t a big deal to you, or you do not have access to C++ resources and are willing to pay 200$ a year or more, Corona is a very good option with a ton of developers using it. Also, Corona is the only option with a paid support option, which can be a huge advantage.
TL;DR verdict:
For a Pro developer: Go Moai, unless you have no in-house C++ talent, in which case, go Corona.
For a new developer: Go Gideros, especially if you want to do mobile development. If you don’t like it, Love is always a great option.
Programming Design General