Saving Score for Multiple Levels

I am using Rob’s tutorial for Displaying and Saving Score. It is awesome and I have it working for my first level without widget buttons. :smiley:

Now I would like to modify the code to save the scores for multiple levels.  I thought about changing the variable name of score to score1, score2 etc… but I wasn’t sure how to set that up in the save, load and set functions. I’ve tried various things to no avail.

Do I need to create a seperate M.save() , M.load() and set() function for each of the game levels or can the existing code be modified to save the scores for multiple game levels using the same three functions?

The code in question:

25.function M.set( value )

  1. M.score = value

  2. M.scoreText.text = string.format( M.format, M.score )

28.end

39.function M.save()

  1. local path = system.pathForFile( M.filename, system.DocumentsDirectory )

  2. local file = io.open(path, “w”)

  3. if ( file ) then

  4. local contents = tostring( M.score )

  5. file:write( contents )

  6. io.close( file )

  7. return true

  8. else

  9. print( "Error: could not read ", M.filename, “.” )

  10. return false

  11. end

51.end

53.function M.load()

  1. local path = system.pathForFile( M.filename, system.DocumentsDirectory )

  2. local contents = “”

  3. local file = io.open( path, “r” )

  4. if ( file ) then

  5. – read all contents of file into a string

  6. local contents = file:read( “*a” )

  7. local score = tonumber(contents);

  8. io.close( file )

  9. return score

  10. else

  11. print( "Error: could not read scores from ", M.filename, “.” )

  12. end

  13. return nil

67.end

Thanks.

Lori

I use a slightly different variation of Robs code to do this…

json = require ( "json" ) function saveTable(t, filename, directory) local path = system.pathForFile( filename, system.DocumentsDirectory) local file = io.open(path, "w") if file then local contents = json.encode(t) file:write( contents ) io.close( file ) return true else return false end end function loadTable(filename, directory) local path = system.pathForFile( filename, directory) local contents = "" local myTable = {} local file = io.open( path, "r" ) if file then -- read all contents of file into a string local contents = file:read( "\*a" ) myTable = json.decode(contents); io.close( file ) return myTable end return nil end highScores = loadTable ( "highScores.json", system.DocumentsDirectory ) if highScores == nil then highScores = {"easy"=1000, "normal"=1000, "hard"=1000} saveTable ( highScores, "highScores.json", system.DocumentsDirectory ) end

When the app is run it attempts to load the highScores file.  This is followed by a check to see if the highScores exist.  If they don’t (for example if the app has never been run before) then a default set of scores is created and saved out to the documents directory.

When a player gets a new high score for a level the table is updated with the new score and the table saved.  e.g (for easy level) …

if score \> highScores.easy then highScores.easy = score saveTable (highScores, "highScores.json". system.DocumentsDirectory ) end

When I want to display the score I just use 

highScoreDisplay.text = highScores.easy

where HighScoreDisplay has previously been created as a text object.

I hope this makes some sense and is useful to you.

Thank you for responding.  One thing I’m not quite understanding.  What part of the code makes a distinction between the high score for level 1 versus the high score for level two?  I don’t want to overwrite the level 1 high score with the high score for level 2.

Thanks,

Lori

If you need something more complex that an single score, you could update the load and save functions to work with a table of scores.

Rob

Ah right.  In my game I only have the one level, but with different difficulties.  For your game the default score table you would look something like…

highScores = {"level1"=0, "level2"=0, "level3"=0} -- Just expand for however many levels you have

So if the player has just played level 3 you would update it with 

if score \> highScores.level3 then highScores.level3 = score saveTable (highScores, "highScores.json". system.DocumentsDirectory ) end

As Rob said the load/save needs to deal with the entire table which is what the two functions in my code do.

I will try that.  Thanks for the help. :rolleyes:

Hi,

Theres something I don’t get here and its not about the code but mostly with the external module.

I create a new file called json.lua with this code but why it starts by require (“json”) in this case? It doesn’t makes sense to me…

json = require ( "json" ) function saveTable(t, filename, directory) local path = system.pathForFile( filename, system.DocumentsDirectory) local file = io.open(path, "w") if file then local contents = json.encode(t) file:write( contents ) io.close( file ) return true else return false end end function loadTable(filename, directory) local path = system.pathForFile( filename, directory) local contents = "" local myTable = {} local file = io.open( path, "r" ) if file then -- read all contents of file into a string local contents = file:read( "\*a" ) myTable = json.decode(contents); io.close( file ) return myTable end return nil end highScores = loadTable ( "highScores.json", system.DocumentsDirectory ) if highScores == nil then highScores = {"level1"=0, "level2"=0, "level3"=0} saveTable ( highScores, "highScores.json", system.DocumentsDirectory ) end

Then in my game I make sure to require (“json”) and add this code?

if score \> highScores.level3 then highScores.level3 = score saveTable (highScores, "highScores.json". system.DocumentsDirectory ) end

If someone could explain me this, That would be great.

Thanks,

Leo

Have a look at some libraries like GGData or DMC Autostore. DMC Autostore is brilliant in that you don’t even have to ask it to save, you change values like you would with any other table and it saves them automatically.

Thanks!  I’ll give that a try.

I use a slightly different variation of Robs code to do this…

json = require ( "json" ) function saveTable(t, filename, directory) local path = system.pathForFile( filename, system.DocumentsDirectory) local file = io.open(path, "w") if file then local contents = json.encode(t) file:write( contents ) io.close( file ) return true else return false end end function loadTable(filename, directory) local path = system.pathForFile( filename, directory) local contents = "" local myTable = {} local file = io.open( path, "r" ) if file then -- read all contents of file into a string local contents = file:read( "\*a" ) myTable = json.decode(contents); io.close( file ) return myTable end return nil end highScores = loadTable ( "highScores.json", system.DocumentsDirectory ) if highScores == nil then highScores = {"easy"=1000, "normal"=1000, "hard"=1000} saveTable ( highScores, "highScores.json", system.DocumentsDirectory ) end

When the app is run it attempts to load the highScores file.  This is followed by a check to see if the highScores exist.  If they don’t (for example if the app has never been run before) then a default set of scores is created and saved out to the documents directory.

When a player gets a new high score for a level the table is updated with the new score and the table saved.  e.g (for easy level) …

if score \> highScores.easy then highScores.easy = score saveTable (highScores, "highScores.json". system.DocumentsDirectory ) end

When I want to display the score I just use 

highScoreDisplay.text = highScores.easy

where HighScoreDisplay has previously been created as a text object.

I hope this makes some sense and is useful to you.

Thank you for responding.  One thing I’m not quite understanding.  What part of the code makes a distinction between the high score for level 1 versus the high score for level two?  I don’t want to overwrite the level 1 high score with the high score for level 2.

Thanks,

Lori

If you need something more complex that an single score, you could update the load and save functions to work with a table of scores.

Rob

Ah right.  In my game I only have the one level, but with different difficulties.  For your game the default score table you would look something like…

highScores = {"level1"=0, "level2"=0, "level3"=0} -- Just expand for however many levels you have

So if the player has just played level 3 you would update it with 

if score \> highScores.level3 then highScores.level3 = score saveTable (highScores, "highScores.json". system.DocumentsDirectory ) end

As Rob said the load/save needs to deal with the entire table which is what the two functions in my code do.

I will try that.  Thanks for the help. :rolleyes:

Sorry it’s taken me so long to get back to you on this, not been near my computer for a while…

The json.lua is a a standard library that is included as part of Corona.  The code above goes in whichever file in your project that it is needed (eg. game.lua ).  You need to require json at the top of the file to load the module, and then the loadtable and savetable are just two functions that you call as needed, so at game over or level over you check to see if it is a new highscore and then call the savetable function as I mentioned above.

I hope that makes it a bit easier to understand.

To add to what @Appletreeman said… If you have a json.lua file in your project, you’re likely going to run into problems down the road.  We provide json.lua as part of our core.  Just do: 

local json = require(“json”)

and you should be all set.

Thank you all for your help.

I figured out everything and it works fine but I have another question. When I exit the app and re-open it, then the score goes back to the initial value, not the last one it was supposed to save…

How do I keep my score in memory even when the app is closed and reset?

Thanks

Hi,

Theres something I don’t get here and its not about the code but mostly with the external module.

I create a new file called json.lua with this code but why it starts by require (“json”) in this case? It doesn’t makes sense to me…

json = require ( "json" ) function saveTable(t, filename, directory) local path = system.pathForFile( filename, system.DocumentsDirectory) local file = io.open(path, "w") if file then local contents = json.encode(t) file:write( contents ) io.close( file ) return true else return false end end function loadTable(filename, directory) local path = system.pathForFile( filename, directory) local contents = "" local myTable = {} local file = io.open( path, "r" ) if file then -- read all contents of file into a string local contents = file:read( "\*a" ) myTable = json.decode(contents); io.close( file ) return myTable end return nil end highScores = loadTable ( "highScores.json", system.DocumentsDirectory ) if highScores == nil then highScores = {"level1"=0, "level2"=0, "level3"=0} saveTable ( highScores, "highScores.json", system.DocumentsDirectory ) end

Then in my game I make sure to require (“json”) and add this code?

if score \> highScores.level3 then highScores.level3 = score saveTable (highScores, "highScores.json". system.DocumentsDirectory ) end

If someone could explain me this, That would be great.

Thanks,

Leo

Have a look at some libraries like GGData or DMC Autostore. DMC Autostore is brilliant in that you don’t even have to ask it to save, you change values like you would with any other table and it saves them automatically.

Thanks!  I’ll give that a try.