How to Load and Save Game Data in the Corona SDK

How to Use SQLite to Store Game Data and Settings

In Dungeons of Evermore, I used a settings table to store what missions were offered to the player, so if they quit and restarted, they would still receive the same missions.

One thing almost every app and game has in common is the need to store and retrieve data. Even the most simple game can utilize SQLite to save the app version number, which can be used to ensure compatibility when performing upgrades, or simple settings such as turning the game's sound on or off.

If you've never done much work with databases or used the database features in the Corona SDK, don't worry. It's actually a relatively straightforward process thanks to the power of LUA and the SQLite database engine utilized in the Corona SDK. This tutorial will walk through the process of creating a settings table and both storing and retrieving information from it.

Keep in mind that this technique can go beyond storing user-based settings. For example, what if you have a game that can be played using different game modes such as "story" mode and "arcade" mode. This settings table can be used to store the current mode. Any other piece of data that you want to remain persistent even if the user quits out of the game and relaunches it.

Initializing the database and creating the settings table.

The first thing we need to do is declare the SQLite library and tell our app where to find the database file. The best place to put this code is right at the top of the main.lua file along with the other require statements. The database file will be created if none is found, and we'll store it in the Documents folder so that we can read from it and write to it.

require "sqlite3"local data_path=system.pathForFile("data.db",system.DocumentsDirectory);db=sqlite3.open(data_path);

Notice how the "db" variable isn't localized. We've done this to make sure we can access the database throughout our project. You can also create a specific .lua file for all database functions and keep the database localized to that file.

Next, we need to create the database table that will store our settings:

local sql= "CREATE TABLE IF NOT EXISTS settings (name,value);"db:exec(sql);

This statement creates our settings table. It's okay to run it every time the app loads because if the table already exists, this statement won't do anything. You can put this statement right under where we've declared the database or in the function that sets up your app to run. The main requirement is (1) to execute those statements every time the app is launched and (2) execute it before any calls to load or save settings.

Saving settings to the database.

function setSetting(name,value)       sql="DELETE FROM settings WHERE name='"..name.."'";    db:exec( sql )        sql="INSERT INTO settings (name,value) VALUES ('"..name.."',"..value..");";    db:exec( sql )    end

function setSettingString(name,value)    setSetting(name,"'"..value.."'");end

The setting function deletes any previous settings saved to the table and inserts our new value. It will work with both integers and strings, but saving a string requires single quotes around the value, so we've used the setSettingString function to do that extra bit of work for us.

Loading settings from the database.

function getSetting(name)

    local sql="SELECT * FROM settings WHERE name='"..name.."'";    local value=-1;

    for row in db:nrows(sql) do        value=row.value;    end    

    return value;end

function getSettingString(name)    local sql="SELECT * FROM settings WHERE name='"..name.."'";    local value='';

    for row in db:nrows(sql) do        value=row.value;    end    

    return value;end

As above, we've broken the functions into two versions: one for integers and one for strings. The main reason we've done this is so that we can initialize them with specific values if no setting exists in the database. The getSetting function will return a -1, which will let us know that the setting hasn't been saved. The getSettingString will return a blank string.

The getSettingString function is completely optional. The only difference between it and the normal getSetting function is what is returned if nothing is found in the database.

Using our settings table.

Now that we have the hard work done, we can easily load and save settings to a localized database. For example, we could mute the sound with the following statement:

setSetting('sound',false);

And we could utilize the setting in a global function for playing sounds:

function playSound(soundID)    if (getSetting('sound')) then        audio.play( soundID )    endend

To turn the sound back on, we simply set the sound setting to true:

setSetting('sound',true);

The nice part about these functions is you can save strings or integers to the settings table and retrieve them easily. This allows you to do anything from saving a player's name to saving their high score.