Advice on saving game option data between screens

I am using the director class to structure my game and need to add the functionality to one of my screens to let the player choose a team colour. Now I need this team colour selection available in other screens and not sure what the best way to go about this is.

Someone has kindly informed me this is possible without globals by using an option.lua file that includes a getter/setter function for the team colour. However I am not sure how this option.lua file fits in with all the other files i.e does each of my screen files (screen1.lua, screen2.lua, screen3.lua etc) need to “include” the option.lua file or do I only need to “include” it in the main.lua?

And apart from the getter and setter function, what other code is required in option.lua assuming just one option variable for now. Here is a simple getter/setter function with the variable set as a local variable. Is this what is required in the option.lua file?

  
local strPlayerTeamColour  
local function setPlayerTeamColour (strColour)  
  
 strPlayerTeamColour = strColour  
  
end  
local function getPlayerTeamColour ()  
  
 return strPlayerTeamColour  
  
end  

Thanks

Paul

[import]uid: 7863 topic_id: 4253 reply_id: 304253[/import]

In your main.lua have this…

local option = require(“option”)

Then in your sub screens do this:

local optionTeamColour = option:getPlayerTeamColour()

You could make this ‘better’ by passing in the option you want to a generic set/get function like this:

[blockcode]
function options:getOption(option)

– print("options.lua, options:getOption, option = "…option)

if (option == “sounds”) then
return opt_sounds
elseif (option == “difficulty”) then
return opt_difficulty
elseif (option == “crossbar”) then
return opt_crossbar
elseif (option == “showfps”) then
return opt_showfps
elseif (option == “precisecols”) then
return opt_precisecols
elseif (option == “cloudsballoons”) then
return opt_cloudsballoons
end
end
[/blockcode]
and

[blockcode]

function options:setOption(option, value)

if (option == “sounds”) then
opt_sounds = value
elseif (option == “difficulty”) then
opt_difficulty = value
elseif (option == “crossbar”) then
opt_crossbar = value
elseif (option == “showfps”) then
opt_showfps = value
elseif (option == “precisecols”) then
opt_precisecols = value
elseif (option == “cloudsballoons”) then
opt_cloudsballoons = value
end

– print("options.lua, options:setOption, option = “…option…” value = "…value)
end

[/blockcode]
[import]uid: 9371 topic_id: 4253 reply_id: 13203[/import]

Nice one - thank you so much for the super fast and very helpful reply. I will implement this now and see how I get on.

Many thanks

Paul [import]uid: 7863 topic_id: 4253 reply_id: 13206[/import]

I am running into some errors with this.

Here is my code for option.lua (note it is option singular)

One error is

attempt to index global ‘options’ (a nil value)

  
function options:getOption(option)  
  
 if (option == "playerBallColour") then  
  
 return opt\_playerBallColour  
  
 elseif (option == "computerBallColour") then  
  
 return opt\_computerBallColour  
  
 end  
  
end  
function options:setOption(option, value)  
  
 if (option == "playerBallColour") then  
  
 opt\_playerBallColour = value  
  
 elseif (option == "computerBallColour") then  
  
 opt\_computerBallColour = value  
 end  
  
end  

My code at the top of main.lua is

  
local director = require("director")  
  
local option = require("option")  

Can you spot anything wrong here?

Should option.lua have module(…, package.seeall) at the start? I did try that but still got errors [import]uid: 7863 topic_id: 4253 reply_id: 13209[/import]

Change

function options:getOption(option)

to

function option:getOption(option)

and

function options:setOption(option, value)

to

function option:setOption(option, value)
[import]uid: 9371 topic_id: 4253 reply_id: 13211[/import]

Unfortunately that just changes the error to

  
attempt to index global 'option' (a nil value)  
  

Any ideas?

Thanks

Paul [import]uid: 7863 topic_id: 4253 reply_id: 13212[/import]

Adding in module(…, package.seeall) seems to remove that error

However in screen2.lua I get the following error

screen2.lua:235: attempt to call method ‘getPlayerBallColour’ (a nil value)

[code]

local playerBallColour = option:getPlayerBallColour()

[/code] [import]uid: 7863 topic_id: 4253 reply_id: 13214[/import]

But shouldn’t that be…

local playerBallColour = option:getOption(“playerBallColour”)

[import]uid: 9371 topic_id: 4253 reply_id: 13215[/import]

Doh! Yes of course. Sorry, brain not in gear today as have stinking cold.

All working sweetly now. Thank you - I am sure this functionality will be most useful for other stuff in this game as well as future games. Thanks for your patience. [import]uid: 7863 topic_id: 4253 reply_id: 13217[/import]

@dweezil

Are variables such as “opt_sounds” saved as global variables or are they local? Just curious as I want to use this code to save 28 locally saved achievements and if global it may not be so wise to do it this way [import]uid: 7863 topic_id: 4253 reply_id: 13614[/import]

Sorry, but I can’t get my head around this thing.

So in main.lua file main.lua I have this…

local option = require(“option”)

in option.lua file I have:

[lua]module(…, package.seeall)

function option:getOption(option)
– print("option.lua, option:getOption, option = "…option)
if (option == “sounds”) then
return opt_sounds
end
end

function option:setOption(option, value)
if (option == “sounds”) then
opt_sounds = value
end
– print("option.lua, option:setOption, option = “…option…” value = "…value)
end[/lua]

Now, I don’t know how the process works from here.

And how could I use these in my code?:
[lua]local sounds = option:setOption(“sounds”,“on”)
local sounds = option:getOption(“sounds”)[/lua]
[import]uid: 10426 topic_id: 4253 reply_id: 19355[/import]

Isn’t setOption declaring global vars inside the function, and getOption returning a global var to a local variable?

Wouldn’t you just be able to use this in your main.lua file?

[lua]function setOption(option, val)
if not _options then _options = {} end
_options[option] = val

end

function getOption(option)
if _options then
return _options[option]
end
end

setOption( “Colour”, “Red”)
print( getOption( “Colour”) )[/lua]

[import]uid: 11393 topic_id: 4253 reply_id: 19369[/import]

Thanks bedhouin for the fast response.
But, wouldn’t this make it non-modular? I’m using the Director class.
Edit: I figured I just put your initial code in main.lua and the setOption, getOption works in every other scene.

Everything in my code seems to work, I get things to print, like: option.lua, option:getOption, option = sounds. But I really don’t how to implement this setOption-getOption in my code. Where am I allowed to ask for the values and when I’m not.

Does anyone have a project they could share showing, for example, how to turn sound off and on?

I don’t know if I’m making any sense :S (2:50 for me) [import]uid: 10426 topic_id: 4253 reply_id: 19372[/import]

From what I can tell (and I could be wrong). There is nothing modular about that implementation if it is declaring and returning global variables.

All it seems to do is protect against naming conflicts by using a “_” prefix. You could for convenience put it into a .lua module, but it wouldn’t be worth having a module all by itself.

This has piqued my interest, and I have found some use for the idea in my apps when I have a need to call a variable so I’ve expanded the above code to create a container to manage global persistent variables without having to worry about nilling them individually.

This will now allow you to do the following:

  • Declare app wide variables
  • Declare screen variables for the current screen
  • Delete all screen variables for your onExit function for screen
  • Delete all screen and app variables

[lua]function setOption(option, val, scope) – Sets an option variable
– option: name of option
– val: value of option
– [scope]: “screen” variable for the current screen or “app” for appwide. Not required and defaults to “app”
if not scope then scope = “app” end
if not _options then _options = { screen={}, app={} } end
_options[scope][option] = val

end

function getOption(option, scope) – Returns the requested screen or app variable
– option: name of option
– [scope]: “screen” variable for the current screen or “app” for appwide. Not required and defaults to “app”

if _options then
if not scope then scope = “app” end
if _options[scope] then
return _options[scope][option]
else
return nil
end
else return nil
end
end

function clearOption( scope ) – Clears “app”, “screen”, or all variables
– [scope]: “screen” variable for the current screen or “app” for appwide. Not required and defaults to “all”
if scope then
_options[scope] = nil
else
_options.app = nil
_options.screen = nil
_options = nil
end
end

–SET VARIABLES
setOption( “Colour”, “Red”, “screen” ) – Set a screen variable
setOption( “Score”, 666 ) – Set an app variable

print( "Screen: " … getOption( “Colour”, “screen” ) ) – Returns Screen Variable
print( "App: " … getOption( “Score” ) ) – Returns App Variable

– DELETE VARIABLES
clearOption( “screen” ) – Removes all Screen Variables. Can be called on screenExit
print( getOption( “Colour”, “screen” )) – Returns nil as all Screen variables are gone
print( "App: " … getOption( “Score” ) ) – Returns App variable

clearOption() – Removes all variables. Can be called if you want to reset the application
print( getOption( “Score” ) ) – Returns nil

– Variables can be deleted directly by calling setOption( option, nil, scope ). Scope will be required[/lua] [import]uid: 11393 topic_id: 4253 reply_id: 19374[/import]

I was having a hard time not knowing how to call the values.
This worked(just for trying)
Yes I don’t like having to predefine variables and then have to go back and manage a bunch if/then/else statements when my app changes. [import]uid: 11393 topic_id: 4253 reply_id: 19375[/import]

Yay, thanks bedhouin, it worked!

I was having a hard time not knowing how to call the values.
This worked(just for trying):
[lua] setOption( “whatpage”, “Page1”)
setOption( “howmoves”, “moveFromRight”)

local function btNEXTt()
director:changeScene(getOption( “whatpage”),getOption( “howmoves”))
end[/lua]

UPDATE2: It does work between scenes. (3.30 I need some sleep) [import]uid: 10426 topic_id: 4253 reply_id: 19373[/import]

Ok, in hindsight perhaps detailed code posts isn’t ideal for new users especially if they don’t understand local/global and how lua modules work. So here is a cleaned up version that you can use.

Create a file called options.lua and place the following inside:

[lua]module(…, package.seeall)

function set(option, val, scope)
if not scope then scope = “app” end
if not _options then _options = { screen={}, app={} } end
_options[scope][option] = val
end

function get(option, scope)
if _options then
if not scope then scope = “app” end
if _options[scope] then
return _options[scope][option]
else
return nil
end
else return nil
end
end

function clear( scope )
if scope then
_options[scope] = nil
else
_options.app = nil
_options.screen = nil
_options = nil
end
end[/lua]

Inside your main.lua file place this at the top:
[lua]options = require( “options” )[/lua]

Now you can call the option functions from anywhere inside your application:

options.set - Set a variable
options.get - Get a variable
options.clear - Remove the variables

Here are some examples:

To create a screen variable which can be deallocated when you exit the screen:
[lua]options.set( “Colour”, “Red”, “screen” ) – Set a screen variable called Colour to “Red”[/lua]

This variable can be accessed from inside your screen via:
[lua]options.get( “Colour”, “screen” ) – Gets SCREEN variable Colour[/lua]

To create an app variable which will be persistent across your entire app:
[lua]options.set( “Score”, 666, “app” ) – Set an app variable called Score to “666”[/lua]

To retrieve this app variable:
[lua]options.get( “Score”, “app” ) – Gets APP wide variable Score[/lua]

To delete all screen variables which should be done inside the onExit function of whichever director/view/game class you are using:
[lua]options.clear( “screen” ) – Removes all SCREEN variables. Should be called on screenExit[/lua]

To delete all app variables if you want to reset the application:
[lua]options.clear( “app” ) – Removes all APP variables[/lua]

To delete both app and screen applications if you want to reset the application:
[lua]options.clear() – Removes all variables. Can be called if you want to reset the application[/lua]

Remember this isn’t creating some magical local storage for your variables. These variables are all GLOBAL. This method just segments between the variables you want available app wide, and just for a particular screen. You must call options.clear( “screen” ) before you switch to the next screen if you want a clean state. If you don’t call the clear function when you exit the screen the variables will just sit there in memory. [import]uid: 11393 topic_id: 4253 reply_id: 19376[/import]

Wow, that looks great. I’ll try this, thanks for all the help. [import]uid: 10426 topic_id: 4253 reply_id: 19405[/import]

Wow, that looks great. I’ll try this, thanks for all the help.
EDIT: iPad double post [import]uid: 10426 topic_id: 4253 reply_id: 19406[/import]