[Updated August 7, 2020]
Unless you’re going to code the next Angry Birds and then just retire to a life of leisure, you’re going to be writing Lua and Solar2D code over and over again. And starting from scratch every time is nice if you’re looking for finger exercises, but if you want to speed up your development you need to write once, use everywhere.
As much as possible, anyway.
In order to do that it’s good idea to write generic rather than specific.
I’m basing the following example on code found on a blog post from Nexus Game Studio (the blog is no longer available as of this update.)
Sidebar: When writing sample code I don’t always write generically myself, so I’m not picking on the guys at Nexus Game Studio — they created a cool sample and with their permission I’m using it as a starting point for this example.
The code shown here is a way to toggle something off and on, like with a light switch. In the example a red block is seen on the screen and when you click it, a yellow ball is toggled off and on. Very simple and easy to use.
Our Starting Point
The code below is very close to what was posted on the Nexus site — I’ve gone ahead and tweaked things a little just to save space.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
--SIMPLE LUA SWITCH FUNCTION by Nexus Game Studio (09/30/11) W = display.contentWidth; H = display.contentHeight --Displays a red square in the center of the screen. This is a light switch. button = display.newRect (50,50,50,50) button:setFillColor(255,0,0) button.x = W / 2; button.y = H / 2 --Displays a yellow circle above the button. This is a light. light = display.newCircle (50,50,50) light:setFillColor(255,255,0) light.x = W / 2; light.y = H / 4 light.isVisible = false --if you want it to be on initially, delete this line local power = true --Tap function that detects when the user has touched the red switch. function button:tap(event) if (power == false) then light.isVisible = false power = true else light.isVisible = true power = false end end --Event listener that calls the button function when the red box is touched. button:addEventListener( 'tap', button) |
The first thing I’m going to do is slim down the function and “unfasten” it from the button so it looks like this:
1 2 3 |
function toggle(event) light.isVisible = not light.isVisible end |
The cool thing about this change is that it’s much shorter — the downside is that unless you really look at it, it’s not immediately apparent what’s happening. 🙂 But if you try the original version and then the “mini” version you’ll see they do the same thing.
Since we’re just toggling the object based on the current value of isVisible, we could safely jettison the power variable since it became redundant using this method.
Also, since we don’t use button:tap() we can call it from anywhere, which means we can have multiple light switches and they can all use the same function. Of course, they all control the same light, so let’s fix that.
When we create the button we can add a property that holds the light object we want that button to toggle. Very simply we do this:
1 |
button.switchit = light |
To make that work correctly we need to create the light object before the button object — I’ll take care of that in the sample code later.
We also need to make this change to the function:
1 2 3 |
function toggle(event) event.target.switchit.isVisible = not event.target.switchit.isVisible end |
Now when the toggle function is called it will grab whatever is in the switchit property of the object that was tapped and toggle it.
Let’s put it all together with two switches and two light bulbs — but both switches will use the same toggle function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
--Based on SIMPLE LUA SWITCH FUNCTION by Nexus Game Studio (09/30/11) W = display.contentWidth; H = display.contentHeight --Displays a yellow circle above the button. This is a light. local light1 = display.newCircle (50,50,50) light1:setFillColor(255,255,0) light1.x = W / 2 - 50; light1.y = H / 4 light1.isVisible = false --if you want it to be on initially, delete this line local light2 = display.newCircle (50,50,50) light2:setFillColor(255,255,0) light2.x = W / 2 + 50; light2.y = H / 4 light2.isVisible = true --Tap function that detects when the user has touched the red switch. local function toggle(event) event.target.switchit.isVisible = not event.target.switchit.isVisible end --Displays a red square in the center of the screen. This is a light switch. local button1 = display.newRect (50,50,50,50) button1:setFillColor(255,0,0) button1.x = W / 2 - 50; button1.y = H / 2 button1.switchit = light1 button1:addEventListener( 'tap', toggle) local button2 = display.newRect (50,50,50,50) button2:setFillColor(255,0,255) button2.x = W / 2 + 50; button2.y = H / 2 button2.switchit = light2 button2:addEventListener( 'tap', toggle) |
Run that code and click the red and purple switches — the lights above each will toggle on and off.
Conclusion
Two things to take away from this.
1. If at all possible, try to make your code work for multiple uses with few (if any) changes. But honestly, sometimes just getting the code done takes precedence over “cleverness” so keep that in mind.
2. Determine whether readability or conciseness is more important. If you’re programming all by yourself, do whatever you want — but if you’re part of a team, it could be that something a little less “optimal” might actually be better just so there’s no confusion about what’s going on.
It’s all a balancing act and while some people will loudly defend one far side or the other, somewhere in the middle is often a good spot for which to aim.
PS – Not sure if “genericity” is a real word, but it should be.
(Originally written for Corona SDK, which is now called Solar2D. But no matter the name, it’s still the best way to get started with 2D game development.)
Not sure I agree that “it’s not immediately apparent what’s happening” with the new toggle function – but only coz you’ve called it ‘toggle’. Good function/variable naming is key. As you know there’s xReference/yReference properties on CoronaSDK display objects. I spent far too much time puzzling over some sample code that used a function called ‘ResetReferences’ which turned out not to touch the x/yReferences at all. This is the worst sort of naming as it appears to be aiding clarity but is actually doing the opposite! 🙂