Best Code structure - Locals schmocals

Hi there,

My god, I’m loving Corona so far! I’ve only been using it for 5 days (my girlfriend has seen or heard little from me the past few nights :wink: but I’m already well under-way to my first game - a scrolling platform game of sorts. Loads of fun!

I’m having good results with smooth scrolling on an iPhone 3G so far, so I’m happy about that, but I do have some questions that I need help with, so all advise is more the welcome and much appreciated.

Mostly, I’m a bit in the dark on how to structure my code to get the best performance. I read everywhere to make things local as much as possible, but the things is that there are a lot of variables that I just want available throughout the whole application, and call nearly every frame for a whole lot of functions/objects. A good example of this is the Camera position, and the Tilemap-Array. Almost everything needs to know where the camera is at all time, so I can shut down a lot of routines and processing for things that are outside of the camera view. Likewise, I’m constantly checking the contents of an Array that holds the tiletypes (e.g. 1 = solid, 2 = air, 3 = cloud etc.) to calculate movement and collision for enemies, the Hero and more.

(Note: I’m new to Lua. I worked with Adobe Director for a long time, did some Flex work before so I’m used to scripting, but I’ve never really done OOP programming - which, I guess, makes Lua great for me!)

I have a couple of specific questions, right of the bat:
0) The big all-encompassing question is ‘how do I structure my data to be available FAST to a lot of functions’. One obvious way is to not use any modules and do everything in the main.lua file, and setting every local at the start of that file, but of course that’s impossible to manage.

  1. Which is fastest to read out my map of tiletype numbers, an Array or a Table? I’m using an array now, with the Array[#Array+1] fill method, because reputedly that’s faster than a table, but is that faster for writing or reading? Writing may be slow, I don’t care. But readout needs to be fast.
  2. Quick question: a local value is faster than a global to retrieve, I gather, and that’s why you would cache a global as a local first, for many functions or loops/branches. Am I right in assuming that if you ‘only need to use a variable once’ then a global is just fine, because caching it as a local first also needs to read the global value first?
  3. Why don’t my external modules see global values from other modules?
    I thought that declaring a variable without the prefix ‘local’ would make the values global, and thus visible everywhere in my program, but apparently some functions (mostly in different modules) don’t see these variables. As a consequence I’m passing a lot of variables in between functions, and returning 'em as well, with seems like overkill to me.

O great master of Corona and Lua, please enlighten me :slight_smile:

Thanks a million!
Thomas (Belgium-based, by the way!) [import]uid: 70134 topic_id: 12933 reply_id: 312933[/import]

I’ll answer #1 and at least part of #3:slight_smile:

#1 - Should you use Arrays or Tables for best speed? You should use Tables, because Arrays don’t exist in Lua. What you think of as an array, MyData[1], is a table. You can use them like arrays, but they are still tables.

What’s cool is that you can do things like this (it’s in a loop using i as the index):
[lua] horses[i] = {}
horses[i].name = horse_info[1].name
horses[i].picname = horse_info[1].picname
horses[i].breed = horse_info[1].breed
horses[horse_info[1].breed] = horses[i][/lua]
The first line sets that “array element” (but it’s really a table) as another table. The next several lines just add properties to that new table, and then that last line sets a table key equal to one of the pieces of data, and the value of that key to the table itself.

It’s kind of a recursive-feeling thing. But it allows me to grab the data from the table like this:

[lua] horses[“Friesian”].name[/lua]
…instead of…
[lua] horses[1].name[/lua]
…which makes it easier to remember where your data is.

Long-winded way to say, there are no arrays in Lua. Just tables that can act (mostly) like arrays.

#3 - Why don’t external modules see your globals? Try putting _G. on the front of the variables. So over in mycoolcode.lua, when you want to access the highScore variable you set up in main.lua, do this:
[lua]if _G.highScore < 1 then[/lua]

Jay

[import]uid: 9440 topic_id: 12933 reply_id: 47433[/import]

Hi Jay, and first of all thanks for your fast and helpful response!

I get point 1) and basically I guess that speedwise my using arrays is okay (since arrays and tables are the same), unless you mean that there’s some overhead in casting the table to array (or the other way around). In that case I’d better just a table.

Regarding the use of _G. I just did a test but with no luck.

I have two very simple lua files (that I will write here, but alas I have no idea how to put stuff in those nice looking colored code blocks use).

main.lua:
require(“globaltest”)
_G.myglobal = “Booyaa”
globaltest.Check()

and globaltest.lua
module(…, package.seeall)
function Check()
print(#_G)
end

This prints ‘0’. Any idea why this doesn’t work?

Thanks!
Thomas [import]uid: 70134 topic_id: 12933 reply_id: 47445[/import]

try this

  
--main.lua  
  
local globTest = require("globalTest")  
\_G.myglobal = "Booyaa"  
globTest.Check()  
  
--globalTest.lua  
  
module(..., package.seeall)  
  
function Check()  
print(myglobal)  
end  
  

to put your code in corrrect formatting use the < code > tags (no spaces) [import]uid: 43961 topic_id: 12933 reply_id: 47447[/import]

and to get number of globals you would need to do something like the following:

[code]
–main.lua
local globTest = require(“globalTest”)

local myglobals = {}
myglobals[1]= “Booyaaa”
myglobals[2]= “Boo”

local globs
_G.globs = myglobals

globTest.Check()
–globalTest.lua
module(…, package.seeall)

function Check()
print(#_G.globs)
end

[/code] [import]uid: 43961 topic_id: 12933 reply_id: 47450[/import]

Thanks Brett!

That did the trick. The big problem was actually the print(#_G) part, apparently, as just changing this line to print(myglobal) did the trick (which is weird because I thought I’d tried that!)

Are there any tricks to where to use _G.myglobal and myglobal without the prefix? Is it always _G. when declaring, and myglobal after that (across main.lua and modules), or is it _G. in the main block and without prefix in modules, or can I just use _G.myglobal everywhere, for consistency?

Thx,
Thomas [import]uid: 70134 topic_id: 12933 reply_id: 47489[/import]

ok when you put a hash sign before a variable lua attempts to count the length of that table.

The _G class makes the global variable truly global between modules, it does not directly contain any values itself.

By creating a local variable called myglobal, and then telling it to be global (using _G), that variable is then avaialable throughout each module.

To set the value as global use _G.
To rerieve the value, you do not need to use _G just the name of the variable (myglobal or whatever). [import]uid: 43961 topic_id: 12933 reply_id: 47494[/import]

Aha! Excellent explanation, Brett, thanks.

I’ve been seeing the phrase ‘in Lua everything is a table’ so much lately, that I sort of thought that _G was a table that held the names and values of all global variables, hence the hash-sign to see how many globals there were.

Okay, tonight I’m re-writing my game engine! I’ll keep you posted on any speed increases or other results!

Thanks again - the Corona forum seems to be a nice place :slight_smile:

Thomas [import]uid: 70134 topic_id: 12933 reply_id: 47497[/import]

Also keep in mind that any Lua chunk can only have 200 local variables (including “local function …”).

I did what you suggested for my first game and had everything in main.lua and I keep hitting this limit. I ended up putting most of my local variables into tables to get around this.

instead of:

local hasShieldPowerUp = false  
local hasBlasterPowerUp = false  
local shieldTimer = nil  
local shieldTween = nil  
local blasterTimer = nil  
local blasterTween = nil  

I converted it to:

local powerUp = {}  
powreUp.hasShieldPowerUp = false  
powreUp.hasBlasterPowerUp = false  
powreUp.shieldTimer = nil  
powreUp.shieldTween = nil  
powreUp.blasterTimer = nil  
powreUp.blasterTween = nil  
  

I’ve asked on here a couple of times if this is a good idea or not and I’ve not heard back, but I’ve not seen any performance hits doing it.

My first game really wasn’t thought out to be modular or very object oriented and with out being able to easily pass parameters to event handler call backs, “globals” seem to be the only way to have all this data available.
[import]uid: 19626 topic_id: 12933 reply_id: 47501[/import]

Haha Rob, ‘BlasterPowerUp’, I like the sound of that :wink:

Any place we can see your game?

Cheers,
Thomas

p.s. I’m using your technique of grouping multiple variables in a table as well, because I can only return a single argument. Returning a table allows me to sort of return many variables from a function. [import]uid: 70134 topic_id: 12933 reply_id: 47507[/import]

http://bit.ly/omniblaster 1.2 Full game
http://bit.ly/oblasterlite 1.1 Lite version
http://omniblaster.omnigeekmedia.com/ Game Website

Game play trailer: http://www.youtube.com/watch?v=pC4gUzH-Vp8

Source code? I’m not ready to make it publicly available yet, mostly because it isn’t pretty… and I’m a better programmer than my code is :slight_smile:

Rob
[import]uid: 19626 topic_id: 12933 reply_id: 47511[/import]

Hey Jay,

Lua tables actually have an array and a hash part. If you google “lua performance pdf” you’ll find a pdf by Roberto Ierusalimschy, one of the creators of Lua, that talks about lua performance and how globals/locals and tables work.

Basically as long as your have elements in your table that start off at 1 and are contiguous your table is using the array part. Break that continuity and you use the hash part of the table. [import]uid: 27183 topic_id: 12933 reply_id: 47535[/import]

Hi Thomas,
Good to hear you’re enjoying Lua and Corona! It just gets better as you move forward. :slight_smile:

Here are a few “must-read” pages regarding optimization:

  1. Blog post on “deep localization” by Jonathan Beebe, long-time Corona advocate and one of the more early success stories (Tilt Monster, etc.):
    http://blog.anscamobile.com/2011/07/local-variables-lua/

  2. Speed tests regarding different Lua coding practices. This is immensely useful!
    http://trac.caspring.org/wiki/LuaPerformance

  3. Another related page from Ansca’s site:
    http://developer.anscamobile.com/content/performance-and-optimization


In regards to global variables, my vote is “never use them*”. The asterisk (*) is there because, on very rare occasions, you almost don’t have a choice… but using them should still be among the last considerations. In most instances, you can make all variables local and consider them as “global” by pre-declaring them at the top of your main.lua file. Functions below will reference these via the up-value method, which is superior in performance to anything global (and using the deep localization techniques, you can make it even faster within a heavy function or loop-oriented function).

Anyway, study these pages well, you won’t regret it. It’s good that your current game is performing quite well, but trust me, if you continue to use global variables you’ll see a performance hit soon, and it might be ugly. :slight_smile:

Brent Sorrentino
Ignis Design
[import]uid: 9747 topic_id: 12933 reply_id: 47536[/import]

Don,

I was answering the question, “arrays or tables?” – if you’re using arrays then you’re automatically using tables. But it would have been better if I’d included your answer, “Lua tables have an array part and a hash part” as well.

I looked up that PDF and it’s VERY cool! Should be required reading for anyone who wants to get more out of Lua.

http://www.lua.org/gems/sample.pdf

Thanks for the heads-up!

Jay
[import]uid: 9440 topic_id: 12933 reply_id: 47582[/import]

I do it a little different. The values I need to use in other modules or scenes like score, game settings, unlocked levels etc I have saved to a file. Then when I load a scene or use another module I load the values from the files into locals.

I’m going thru the same problem that robmiracle went thru. I’m writing my first game and I now have to start putting my locals into tables to avoid Lua from complaining about too many local variables.

The latest version of Director has a way to transfer variables from scene to scene but I have not tried that version yet. [import]uid: 38820 topic_id: 12933 reply_id: 47592[/import]