Home > Tech Geek > Need to save your game data in Corona SDK? Check out this little bit of code.

Need to save your game data in Corona SDK? Check out this little bit of code.

A very frequent question in the Corona SDK Forums is “How do I save my game data?”.  There are several published solutions in the Community Code and while I they are good, they don’t help you learn how to program or carry extra functions that you may not need.

I (and several other’s) frequently suggest “Just use JSON!”.  But in a recent post in the forums, I realized that as simple as this really is, the language encouraged people to go look up JSON with the concept that they needed to learn JSON.  JSON or JavaScript Object Notation, is a simple syntax for encoding data in a light-weight standard way.  You can dig into the guts of JSON at http://json.org.

The typical JSON file is considerably smaller than the same data encoded in XML and it’s a great way to represent table data like in a language like Lua, which Corona SDK.

If you click through to the json.org links above, you may be immediately intimidated, in fact so intimidated that you are turned off to the concept of using JSON.  But here is the beauty with Lua and Corona SDK, you don’t need to know JSON at all.  In fact it may be a bit better if you just accept that Corona provides you two API calls and assume that everything else is simply magic.

To see just how simple this is, check out this code.  But before I present this code, some of it may still be scary and that is the code to open a file and to read and write files.  However, it’s important to learn this code because as you work on other apps, you will need to read and write files to the file system.

Mobile applications run in a “Sandbox”, which is a protected area.  You can only access files inside your space only.  There are typically four specific locations where files are stored and retrieved from.  They include:

  • The Resource Folder (called a Directory)
  • The Documents Directory
  • The Temporary Directory
  • The Cache Directory

The Resources directory, which Corona SDK,  calls:  system.ResourcesDirectory,  is basically your application files that are “bundled” together and installed on your device.  This frequently referred to as the “app bundle”.  These file can be read only and not written to.  This is for security to prevent malware from infecting your app.

The Documents Directory is where you store your permanent files.  In Corona SDK, this is known as system.DocumentsDirectory.  Any file that your app needs to run that cannot be re-created gets saved here.  It should be noted that Apple with iOS 5 and iCloud, files in this folder get automatically backed up to iCloud.  Corona SDK currently does not give us an option to turn off those backups.  Apple is cracking down on downloaded files, that can be reproduced being saved in this directory since iCloud’s “free” space is limited and they don’t want it full of game code, graphics and other downloaded directory.

Because of this we now have the Caches directory or system.CachesDirectory.  This is a folder to store these downloaded files that can be re-downloaded.  In most senses, you “cache” files that you download that doesn’t change frequently and only download the files when they change.  Web browsers help websites load faster by keeping images, CSS and JavaScript files around on your computer so they don’t have to reload them over the Internet.  You’re app should do the same thing for files that you download.   Files in this folder **CAN** be deleted by the system if the overall file storage gets too low, but they for the most part should remain from session to session, but can be re-downloaded if necessary.

The final location to store files is the Temporary directory or system.TemproaryDiretory.  This is where you put files you don’t care about from session to session.

Files in general require three operations:

  • Open the file
  • Read or write data to/from the file
  • Close the file

Corona SDK uses some syntax for processing files that’s a bit confusing.  After a year of working with the product, I still have to look up the file operation API calls, so don’t worry if you don’t get this code right away.

 Lua |  copy code |? 
01
02
-- load the JSON library.
03
local json = require("json")
04
 
05
-- Function to save a table.  Since game settings need to be saved from session to session, we will
06
-- use the Documents Directory
07
 
08
local json = require("json")
09
function saveTable(t, filename)
10
    local path = system.pathForFile( filename, system.DocumentsDirectory)
11
    local file = io.open(path, "w")
12
    if file then
13
        local contents = json.encode(t)
14
        file:write( contents )
15
        io.close( file )
16
        return true
17
    else
18
        return false
19
    end
20
end
21
 
22
function loadTable(filename)
23
    local path = system.pathForFile( filename, system.DocumentsDirectory)
24
    local contents = ""
25
    local myTable = {}
26
    local file = io.open( path, "r" )
27
    if file then
28
         -- read all contents of file into a string
29
         local contents = file:read( "*a" )
30
         myTable = json.decode(contents);
31
         io.close( file )
32
         return myTable 
33
    end
34
    return nil
35
end
36
 
37

So while we are using JSON to format the data when we save it and read it back in, you have to learn ZERO JSON to use this. It magically turns a Lua table into a string that can be then written to a file. If you read that string back in, then decode it with json.decode you end up with the exact came table you started with.

Then to use this magic, you simply do:

 Lua |  copy code |? 
1
2
myGameSettings = {}
3
myGameSettings.highScore = 1000
4
myGameSettings.soundOn = true
5
myGameSettings.musicOff = true
6
myGameSettings.playerName = "Barney Rubble"
7
saveTable(myGameSettings, "mygamesettings.json")
8

To read your game settings:

 Lua |  copy code |? 
1
2
myGameSettings = loadTable("mygamesettings.json")
3

While you’re getting two very simple, easy to use calls that you really don’t have to think about, please take time to learn what those two functions are doing with regards to opening, reading, writing and closing files. You can save learning the JSON format until another day.

Corona SDK excels in letting you do complex tasks in simple easy ways. We don’t think twice about what’s under the hood of the display.newImageRect() API call. You don’t need to think about what’s under the hood with JSON either.

This code can be downloaded from Github.

Categories: Tech Geek Tags:
  1. February 23rd, 2012 at 18:27 | #1

    Hi Rob!

    As a big fan of your knowledge and your WAY to explain the code (as Mrs. Peach does so well too), I only would like to say a big thank you for posting this great topic and all the awesome helps on CoronaSDK Forums as well.

    Best Regards,
    Rodrigo.

  2. February 23rd, 2012 at 22:45 | #2

    Ha! Glad my forum post could inspire this article. What a great help this is!
    Thanks again!

  3. Guy T.
    February 27th, 2012 at 12:00 | #3

    This will be very helpful. Thanks!

  4. Danny
    March 4th, 2012 at 18:38 | #4

    This was a fantastic help to me! Thanks a bazillion! :-D (Official number! ;-P )

    One little query – shouldn’t the load line be:

    [quote] myGameSettings = loadTable(“mygamesettings.json”) [/quote]

    instead of :

    [quote] mySettings = loadTable(“mygamesettings.json”) [/quote]

    Otherwise it doesn’t work for me. But worked when I changed it as above.

  5. Danny
    March 4th, 2012 at 18:39 | #5

    Sorry, poor quote editing there. ^_^

  6. March 4th, 2012 at 19:45 | #6

    @Danny
    Thanks for the spot Danny! I’ve adjusted the code!

  7. Gary
    March 21st, 2012 at 11:03 | #7

    You missed a “t” in settings in the sample save code

  8. April 18th, 2012 at 16:50 | #8

    Epic sir! Man, you are going straight into my RSS feeds for Corona. I don’t know WHY I haven’t done so already. And looking forward to reading about the RESTful integration too! Thanks Rob!

  9. May 17th, 2012 at 12:57 | #9

    thanks rob for the great lesson.

    how do i go about outputting the highScore onto the screen? and also have it update while moving around the storyboard?

    thanks

  10. Robin Hood
    March 12th, 2013 at 21:15 | #10

    thanks for the awesome post.

    one question here, how can i encrypt the contents saving to json file then decrypt again when read the file.

    thanks in advance.

  11. EHO
    April 4th, 2013 at 11:54 | #11

    This is killer. I set this up and was saving and loading data in about 2.5 minutes flat. I did take the time to better understand the io API. It would have been solvable for me to set up on my own but your solution strikes me as excellent and certainly saved me a number of hours of work.

    For anyone that is new to working with system information, I got some forum help that explained you can use the File -> Show Project Sandbox to find the folder on your machine that keeps the system.DocumentsDirectory content for your Corona Simulator work.

    Thanks for the nice article and the code :)

  12. April 17th, 2013 at 16:29 | #12

    I guess it depends on how you want to encrypt it, but you could take the JSON output which is just a text string, then encrypt the whole thing, then create a new json structure that is just the one variable:


    $data = json_encode($array);
    $edata = encrypt($data);
    echo(json_encode($edata));

    or something similar.

  13. April 18th, 2013 at 11:54 | #13

    hi Rob,
    I asked this in a reply to one of your posts in another forum. I need an answer relatively quickly so I’m trying you here as well. sorry… what I need to know is how one can email the contents of a table (specifically a photo captured by an iPhone in an app). but since I’m here, does json allow you to upload image data as well?
    THANKS!

  14. Satwant
    May 31st, 2013 at 08:51 | #14

    @EHO

    Thank you soo much for pointing out the file > show project sandbox. I am new to lua so that reallllyyy helped!

    Fantastic code aswell =D

  15. fernando
    June 17th, 2013 at 13:08 | #15

    Hello Rob, with this method, can save also the score, and load in others levels?
    Thanks

  16. June 18th, 2013 at 14:18 | #16

    Yes you can

  17. hallmark
    June 26th, 2013 at 12:29 | #17

    Thanks for this article. It is very helpful.

    The data that we store by this method, will it persist and stay if we launch an app update?

    I am saving scores using your method and I do-not want them to be overwritten when I launch an app update

  18. Hamza
    June 27th, 2013 at 23:05 | #18

    Hi Rob,
    I am now also a great fan of your knowledge. But I have a problem when I implement this, it works great on simulator, but on device, that scene could not be open where I READ or WRITE data, app neither crashes nor open that scene, just stucked.
    What I have done, made a class of this code, and use that class by “local json = require “jsonCustomClass”", and using jsonCustomClass.saveTable(…) and jsonCustomClass.loadTable(…)
    Can you help me out and tell me what I am doing wrong?

  19. July 6th, 2013 at 12:52 | #19

    Updates don’t overwrite data. It only gets erased if they delete the app or wipe the device

  20. July 6th, 2013 at 12:54 | #20

    I would suggest posting in the forums.

  21. jeff
    September 1st, 2013 at 15:00 | #21

    Hi sorry I am newbie in corona, I dont know how to use ‘ur file

    I try to create myTable.json same folder with all lua file, and in main.lua I add this

    local loadsave = require “loadsave” –loadsave.lua in samefolder

    myTable = {}
    myTable.musicOn = false
    myTable.soundOn = true

    loadsave.saveTable(myTable, “myTable.json”)

    but when I run the program, nothing happen, I thought it suppose save value on

    myTable.musicOn = false
    myTable.soundOn = true

    right?

    please help me to understand, thx

  22. September 2nd, 2013 at 10:53 | #22

    Well first of all, you cannot save data to the same folder your main.lua is in. That is known as system.ResourcesDirectory and is READ-ONLY. You can load a JSON table from there, but you cannot write one. By default the code listed here reads/writes from your sandboxed folder known as system.DocumentsDirectory. This is the natural place to save settings too. I know some people have modified this to support reading/writing from system.TemporaryDirectory and system.CachesDirectory.

    It’s not designed to work with the same folder your main.lua is in.

  23. October 3rd, 2013 at 08:26 | #23

    Hi Rob!

    First of all, thank you for everything you do to help us struggling indie developers ;)

    I have been saving and loading like a champ for a while now, but today I got a problem. Everything has worked great for a long time, but suddenly my json file is overwritten even if I dont save it?!?!

    It happens when I change scenes in storyboard. When I create the json file in the first scene, all information is stored as it should. When I change to the next scene, the information is ereased but the json file is still there. The strange thing is that I dont have any load.save function for this json file in the next scene :( I have created three json files in the first scene but only one json file gets the information ereased.

    Have you any idea what could be the problem?

    Thanx :D

  24. October 3rd, 2013 at 08:36 | #24

    Hmmm!

    I cheated a little.
    I had to use load.save in the next scene as well and retype the information and save it again in the json file.

    Really strange :-/

  25. Ovidiu
    October 16th, 2013 at 12:30 | #25

    Hey Rob!

    First of all I’d like to thank you for all your tutorials, thanks to you and others like you I’ve managed to make my first game but I still have tons more things to learn regarding corona and game development in general. I’ve always managed to find the answers to the questions I had in forums and tutorials but this time I’m stumped. I just don’t get how to use Json and that’s why I’m asking for your help now.

    Here is the scenario:

    I have the main.lua which takes me to the start.lua (it has the title and a start game button) which takes me to the afterstart.lua (it has for now just a level select button) which takes me to the levelSelect.lua (it has a list of the available levels, some being locked); after this are the levels 1,2,3… After each level is completed the next level is unlocked.

    What I want to save for now is the level statuses, locked or unlocked, and I don’t understand where I have to put any of the code you wrote above. I mean what do I have to write in the main.lua or in the levelSelect.lua, do I have to make a new .lua file for the Json code?

    Sorry for the noob question but I didn’t know where else to turn.

    Thanks in advance

  26. October 16th, 2013 at 16:23 | #26

    @Ovidiu
    There are really two parts to this:

    1. Putting these two functions somewhere that you can access them from any of your scenes.
    2. Storing the data you want to save in a Lua table (that is probably accessible from any scene)

    Lets attack the 2nd one first. A few weeks ago Corona Labs posted a blog called Goodbye Globals (http://www.coronalabs.com/blog/2013/05/28/tutorial-goodbye-globals/) that discusses a technique of creating a lua module called mydata.lua that holds an empty table that you can use to pass data around instead of using Globals. I would advise reading this and implementing it. Because you may have data in this table that you DONT want to save, you probably should have a sub-table called gameSettings:

    mydata.gameSettings = {}
    mydata.gameSettings.musicOn = true
    mydata.gameSettings.highScore = 0

    etc. You can put in whatever data you need to track your level status (score per level, stars earned, unlocked or not, etc) into a table inside of mydata.gameSettings. The idea here is that gameSettings holds everything and only the things you want to save.

    Then you can call saveTable by simply passing it the mydata.gameSettings table. i.e.:

    saveTable(mydata.gameSettings, “settings.json”)

    You don’t really need to know any JSON, that’s what this function does for you.

    Now to get this function where you can find it. I normally have another .lua file that I call “utility.lua”. This is where I stick all my misc code and I just add these as functions in there and return the module:

    –utility.lua
    local M = {}
    function M.saveTable()

    end

    function M.loadTable

    end

    return M

    of course you have to put the code for those functions in the above snippet. Now I would just do a:

    local utility = require(“utility”)

    in each place where I need to save the table and then the all (if you do both is)

    utility.saveTable(mydata.gameSettings, “settings.json”)

    Typically you only need to load the table when the app first starts up, so you would do:

    mydata.gameSettings = utility.loadTable(“settings.json”)

  27. nowfal
    October 21st, 2013 at 09:21 | #27

    I got an error ” unexpected symbol near ‘T’” when using json load and save functions, can you help me?

  28. nowfal
    October 21st, 2013 at 09:47 | #28

    Thnx Rob for sharing this one

  29. Ovidiu
    October 21st, 2013 at 17:12 | #29

    Thanks for the help Rob. I had a lot of trouble understanding how and what at first but after a lot of trial and error I finally got it to work.
    You’re doing us all a huge favor.

    Cheers

  30. October 21st, 2013 at 21:10 | #30

    How are you calling the saveTable function? Make sure you’re not passing a nil value for your table to save.

  31. Ovidiu
    October 22nd, 2013 at 00:47 | #31

    @nowfal

    I had the same error and found that it was because I copy/pasted
    utility.saveTable(mydata.gameSettings, “settings.json”). where “settings.json” isn’t the same as “settings.json”. The quote signs are different in the first case and they are not recognized.
    At least that’s why I got that error.

  32. luanoob
    November 15th, 2013 at 20:36 | #32

    This is great. I’m looking to add to a list of data (like a history list of data created) instead of just overwriting a single value. Could you point me in the right direction to accomplish that?

    On that note, are there limits/gotchas when writing/reading a growing json file?

    Thanks!

  33. November 20th, 2013 at 11:04 | #33

    hello there i am new hear on this blog.

    i have some questions about one game that i am trayng to change the value high score and its not working can some one help me pleas the name game is clash of clans and its on android device. you can se short movies on YouTube about this game allot of people tried things and its not working

    Big 10X for the help and have nice day

  34. December 9th, 2013 at 22:35 | #34

    sir i am a newbie in corona but i’ll try to learn some hardcoded code in corona.but this code of high score is working in corona and for android also.

  35. January 11th, 2014 at 17:39 | #35

    hi Rob,
    I’m loading videos into a game accompanied by questions. when the person gets the answer correct based on the video they just watched, I don’t want that video to play again, but to skip to the next one. I was thinking of trying to store the correctly answered videos in a json file, and setting up a conditional to check the json file to see if it was there and if so to bypass it. Is this a reasonable approach: How would I check for particular strings? Or are there any examples you know of that have accomplished something similar? My research has turned up nothing. Would a table set up in a myData.lua file to store a series of strings be a better option? If so, how would I access from the table, something like if the table correctVideos contains “videos1/video11.m4v” then videoView:load(“videos1/video”..”1″..myData.score1 + (1)..”.m4v”) Hope this makes sense…Thanks, Rob!

  1. May 13th, 2013 at 11:55 | #1
  2. May 26th, 2013 at 22:02 | #2
  3. January 14th, 2014 at 01:45 | #3

%d bloggers like this: