How can i easily implement a save and load system

Hi

I posted this over on the game development forum, but i think it might be better placed here as im using director

My game currently has a main menu and multiple levels. Each level is on a new screen.

After each level is completed i would like it to save (either auto save or maybe user saves manually once level is complete with a pop up save button).

I would then like the user to be able to load this from the main menu.

I have tried looking at all the samples and older forum post but its getting really confusing.

From what i can gather from these examples is that i need to create a database, have each level write to this database and have a load from database function in my main menu.

Please could someone help by making a really easy to use guide for implementing this.

Just a bit more detail on what i would like to be saved and loaded.

Once the level is complete, save this. When user chooses load from main menu The next level (screen) will be loaded.

I have read that using screens for levels isn’t the best way to go about creating games, however i feel comfortable using them at the moment as a beginner

All help is appreciated.
[import]uid: 24981 topic_id: 5884 reply_id: 305884[/import]

Actually this is not a Director’s issue but I’ll try to help you.

I have a file called settings.lua where I have functions to get and set global variables and load and save functions to use the SQLite database. You can use the save and load for what you want:

[code]
module(…, package.seeall)


– DATABASE

require “sqlite3”

local dbPath = system.pathForFile(“settings.db”, system.DocumentsDirectory)
local db = sqlite3.open( dbPath )

db:exec [[CREATE TABLE IF NOT EXISTS tb_settings (
name VARCHAR(50) PRIMARY KEY,
type VARCHAR(1),
value_string TEXT,
value_number NUMBER);]]

local function onSystemEvent( event )
if( event.type == “applicationExit” ) then
db:close()
end
end


– VARIABLES

local tabVars = {}

tabVars[“numPlayers”] = 2


– FUNCTIONS

– GET
function settings:getVar ( pVarName )
return tabVars[pVarName]
end

– SET
function settings:setVar ( pVarName, pVarValue )
tabVars[pVarName] = pVarValue
end

– LOAD
function settings:loadVar( pVarName )
for row in db:nrows(“SELECT * FROM tb_settings WHERE name = '” … string.upper(pVarName) … “’”) do
if row.type == “N” then
return tonumber(row.value_number)
else
return tostring(row.value_string)
end
end
return nil
end

– SAVE
function settings:saveVar( pVarName, pVarValue )

if type(pVarValue) == “nil” then
pVarValue = tabVars[pVarName]
else
settings:setVar ( pVarName, pVarValue )
end

local vVarType

if type(pVarValue) == “number” then
vVarType = ‘N’
elseif type(pVarValue) == “string” then
vVarType = ‘C’
else
return true
end

for row in db:nrows(“SELECT count(*) as cont FROM tb_settings WHERE name = '” … string.upper(pVarName) … “’”) do
if row.cont > 0 then
if vVarType == “N” then
db:exec (“UPDATE tb_settings SET type = ‘N’, value_number = " … pVarValue … " WHERE name = '” … string.upper(pVarName) … “’;”)
else
db:exec (“UPDATE tb_settings SET type = ‘C’, value_string = '” … pVarValue … “’ WHERE name = '” … string.upper(pVarName) … “’;”)
end
else
if vVarType == “N” then
db:exec (“INSERT INTO tb_settings ( name, type, value_number) VALUES (’” … string.upper(pVarName) … “’,‘N’,” … pVarValue … “);”)
else
db:exec (“INSERT INTO tb_settings ( name, type, value_string) VALUES (’” … string.upper(pVarName) … “’,‘C’,’” … pVarValue … “’);”)
end
end
end
end
[/code] [import]uid: 8556 topic_id: 5884 reply_id: 20176[/import]

Thanks for the quick reply Ricardo

Where would i insert this code and how would i implement this into my levels and menu.

Sorry for asking such novice questions, im still a beginner :slight_smile:

[import]uid: 24981 topic_id: 5884 reply_id: 20178[/import]

hey Ricardo! I would also love some additional information on how to implement this code. I’m using your Director library heavily (Thank you by the way!) and I think this is a great way to transfer things back and forth between pages. [import]uid: 13801 topic_id: 5884 reply_id: 20284[/import]

That’s easy, you only need to put it like this:

settings:setVar ( "myVar", 1 )  
print("result: " .. settings:getVar ( "myVar" ) )  

And at the main.lua file you put this:

local settings = require("settings") [import]uid: 8556 topic_id: 5884 reply_id: 20295[/import]

Ace! Thanks so much! [import]uid: 13801 topic_id: 5884 reply_id: 20296[/import]

Hey Ricardo

So iv created the settings.lua file and inserted the other parts of the code into my level and main.lua files. What would i do next.

It would be great if you could create a video explaining all this like you did with director class as that was very helpful :slight_smile: [import]uid: 24981 topic_id: 5884 reply_id: 20346[/import]

Iv brushed up on my SQL skills and im understanding it a lot better now. Thanks for the help [import]uid: 24981 topic_id: 5884 reply_id: 20434[/import]

Using database for storing variables is an easy way to save states and progress but to customize it you need some knowledge in SQL. [import]uid: 8556 topic_id: 5884 reply_id: 20499[/import]

Can you help me out by explaining what variables this is saving and what I should be editing for my application? I am trying to create locked levels and only unlock them when the user beats the previous level.

This is the function to decifer if the level is playable, but i’m not sure what to save and how to save it.

if lastLevelUnlocked == levelNumber then levelPlayable=true elseif lastLeveunlocked \> levelNumber then levelPlayable=true elseif lastLevelUnlocked \< levelNumber then levelPlayable=false end [import]uid: 32061 topic_id: 5884 reply_id: 22876[/import]

Ok, let’s go step-by-step.

1 - Create a file called settings.lua with the code that I put on the comment #1.

2 - At the main.lua file, you have to require it, like this:

local settings = require("settings")  

3 - When you start the game, you want to load the stored variable so you have to do it at the main.lua file:

-- Test if it exists. If false then create it with a 0 value  
if type(settings:loadVar("lastLevelUnlocked")) == "nil" then  
 settings:saveVar( "lastLevelUnlocked", 0 )  
else  
 settings:setVar( "lastLevelUnlocked", settings:loadVar("lastLevelUnlocked") )  
end  

4 - Change your test to decipher if the level is playable:

if settings:getVar("lastLevelUnlocked") \>= levelNumber then  
 levelPlayable=true  
else  
 levelPlayable=false  
end  

5 - Finally, when the player beats the level, you just need to save the state:

settings:saveVar( "lastLevelUnlocked", settings:getVar("lastLevelUnlocked") + 1 ) [import]uid: 8556 topic_id: 5884 reply_id: 22924[/import]

Wow. Thanks for the help!

My Main file now looks like this.

  
local settings = require("settings")  
  
-- Test if it exists. If false then create it with a 0 value  
if type(settings:loadVar("lastLevelUnlocked")) == "nil" then  
 settings:saveVar( "lastLevelUnlocked", 0 )  
else  
 settings:setVar( "lastLevelUnlocked", settings:loadVar("lastLevelUnlocked") )  
end  
  
if settings:getVar("lastLevelUnlocked") \>= levelNumber then  
 levelPlayable=true  
else  
 levelPlayable=false  
end  
  
settings:saveVar( "lastLevelUnlocked", settings:getVar("lastLevelUnlocked") + 1 )  
  
-- Import director class  
local director = require("director")  
  
-- Create a main group  
local mainGroup = display.newGroup()  
  
-- Main function  
local function main()  
  
 -- Add the group from director class  
 mainGroup:insert(director.directorView)  
  
 -- Change scene without effects  
 -- This sends user to the main menu  
 director:changeScene("screen1")  
  
 return true  
end  
  
-- Begin  
main()  

And my Settings.lua file looks like this.

module(..., package.seeall)  
  
---------------------------------------------------------  
-- DATABASE  
---------------------------------------------------------  
  
require "sqlite3"  
--  
local dbPath = system.pathForFile("settings.db", system.DocumentsDirectory)  
local db = sqlite3.open( dbPath )  
--  
db:exec [[CREATE TABLE IF NOT EXISTS tb\_settings (  
 name VARCHAR(50) PRIMARY KEY,  
 type VARCHAR(1),  
 value\_string TEXT,  
 value\_number NUMBER);]]  
--  
local function onSystemEvent( event )  
 if( event.type == "applicationExit" ) then  
 db:close()  
 end  
end  
  
---------------------------------------------------------  
-- VARIABLES  
---------------------------------------------------------  
  
local tabVars = {}  
--  
tabVars["numPlayers"] = 2  
  
---------------------------------------------------------  
-- FUNCTIONS  
---------------------------------------------------------  
  
-- GET  
function settings:getVar ( pVarName )  
 return tabVars[pVarName]  
end  
  
-- SET  
function settings:setVar ( pVarName, pVarValue )  
 tabVars[pVarName] = pVarValue  
end  
  
-- LOAD  
function settings:loadVar( pVarName )  
 for row in db:nrows("SELECT \* FROM tb\_settings WHERE name = '" .. string.upper(pVarName) .. "'") do  
 if row.type == "N" then  
 return tonumber(row.value\_number)  
 else  
 return tostring(row.value\_string)  
 end  
 end  
 return nil  
end  
  
-- SAVE  
function settings:saveVar( pVarName, pVarValue )  
 --  
 if type(pVarValue) == "nil" then  
 pVarValue = tabVars[pVarName]  
 else  
 settings:setVar ( pVarName, pVarValue )  
 end  
 --  
 local vVarType  
 --  
 if type(pVarValue) == "number" then  
 vVarType = 'N'  
 elseif type(pVarValue) == "string" then  
 vVarType = 'C'  
 else  
 return true  
 end  
 --  
 for row in db:nrows("SELECT count(\*) as cont FROM tb\_settings WHERE name = '" .. string.upper(pVarName) .. "'") do  
 if row.cont \> 0 then  
 if vVarType == "N" then  
 db:exec ("UPDATE tb\_settings SET type = 'N', value\_number = " .. pVarValue .. " WHERE name = '" .. string.upper(pVarName) .. "';")  
 else  
 db:exec ("UPDATE tb\_settings SET type = 'C', value\_string = '" .. pVarValue .. "' WHERE name = '" .. string.upper(pVarName) .. "';")  
 end  
 else  
 if vVarType == "N" then  
 db:exec ("INSERT INTO tb\_settings ( name, type, value\_number) VALUES ('" .. string.upper(pVarName) .. "','N'," .. pVarValue .. ");")  
 else  
 db:exec ("INSERT INTO tb\_settings ( name, type, value\_string) VALUES ('" .. string.upper(pVarName) .. "','C','" .. pVarValue .. "');")  
 end  
 end  
 end  
end  

Where do I enter the function that states when something happens, the level is completed, thus unlocking the next level?

Also, where do I put the list of levels or do I need to? [import]uid: 32061 topic_id: 5884 reply_id: 22965[/import]

I am working on the same issue right now. From above, do I used this code at the end of the level?

settings:saveVar( “lastLevelUnlocked”, settings:getVar(“lastLevelUnlocked”) + 1

[import]uid: 33363 topic_id: 5884 reply_id: 22982[/import]

Guys,

It depends on how you structured the game. If you are using a table to put all your levels then you just need to put the commands with the table. If you are using a bunch of objects to represent each level then you have to test on each.

Think like Cut The Rope, if you have equal or more then 250 stars, you can play the Cosmic Box levels. You don’t need to create a single variable for all your levels. Use the settings:getVar(“lastLevelUnlocked”) to store the “star count” like Cut The Rope then put a test on level 5 (example) to check if the lastLevelUnlocked is more or equal to 5, something like that.

Before going coding, stop for a moment to create a structure to your software. [import]uid: 8556 topic_id: 5884 reply_id: 22986[/import]

My game is structured using director obviously and each level is a different lua file. level1.lua level2.lua etc…

I have a single goal at the end of each level, to touch a crate with an object, so a collision.

My confusion is, do I need to list out each level and mark them as locked or unlocked? or does the setting.lua file take care of that with variables?

Thanks again for your help. [import]uid: 32061 topic_id: 5884 reply_id: 22988[/import]

@4d32petersc

This settings.lua file that I put here is only to make easier the way you use variables between scenes and load/save them into a database. How do you will organize your levels on the screen it’s up to you. If you want to save them all or just a token is your choice. Also, this file doesn’t work with display objects, only data.

My advice is to create movieclips with 2 frames (locked/unlocked) and test the lastLevelUnlocked variable. Each movieclip can be a button to one level and can be changed to go to the level or not.

[code]
local level01button = movieclip.newAnim{“levelLocked.png”,“levelUnlocked.png”}
localGroup:insert(level01button)

local function level01touch ( event )
if event.phase == “ended” then
if settings:getVar(“lastLevelUnlocked”) >= 1 then
director:changeScene(“level1”,“fade”)
end
end
end
level01button:addEventListener( “touch” , level01touch )

if settings:getVar(“lastLevelUnlocked”) >= 1 then
level01button:stopAtFrame(2)
end
[/code] [import]uid: 8556 topic_id: 5884 reply_id: 22991[/import]

That makes sense. The issue I can’t figure out is where the data is stored for each level?

So each level is shown as locked until an event changes it to unlocked, and then the game references that file whenever it is opened. [import]uid: 32061 topic_id: 5884 reply_id: 23016[/import]

Yes, if you use the saveVar function then the variable will be saved at SQLite database. If you use only the setVar function then the variable will stay at the memory inside the tabVars table at settings.lua file. [import]uid: 8556 topic_id: 5884 reply_id: 23090[/import]

Hello Ricardo, I read through this to try and figure out how to do this, and I kind of got an idea but I’m not sure…

as an example, could you show me how the code could be used with ghosts vs monsters sample code so I could get an idea how it would look?

I’m recently new to lua so I’m still learning

Thanks [import]uid: 14940 topic_id: 5884 reply_id: 23336[/import]

any help? =[[import]uid: 14940 topic_id: 5884 reply_id: 23799[/import]