The insults, comebacks, and characters are all stored in arrays. Because of this structure, I know that all the scoring and game progress is entirely based around these arrays. Thus I'll know when a new insult or comeback appears, all I need to do is store the key somewhere for retrieval the next time the user opens the game. But how can I manage saving progress?
The Adobe AIR framework comes complete with SQLite support. Basically, this means I have a collection of classes that allows me to create and control a local database entirely from ActionScript. I use this database to do the following:
The only issue is that this whole SQLLite-create-and-control-my-own-database is all brand new. Which means… uh oh… new syntax. Scary! Deep breaths…
_sql = new SQLConnection(); _sql.addEventListener(SQLEvent.OPEN,_onSQLConnectSuccess,false,0,true); _file = File.applicationStorageDirectory; _file = _file.resolvePath(Constants.FILE_DATABASE); _sql.openAsync(_file, "update");
… wait a minute. That's it?
Yep. Well, not quite. But that's the basics. In five lines of code, I say the following:
_onSQLConnectSuccess.Constants.FILE_DATABASE is set to insultDueler.db.Okay… so, what if the database file doesn't exist yet? How does Adobe AIR know to create it? The syntax above will automatically create the file if it doesn't exist. If you didn't want that, modify the code as follows (changes in bold):
_sql = new SQLConnection(); _sql.addEventListener(SQLEvent.OPEN,_onSQLConnectSuccess,false,0,true); _sql.addEventListener(SQLErrorEvent.ERROR,_onSQLConnectFail,false,0,true); _file = File.applicationStorageDirectory; _file = _file.resolvePath(Constants.FILE_DATABASE); _sql.open(_file,false);
Now the app will fire a SQLErrorEvent if it can't find the database file. And the _open method is passed a false, specifically telling it not to auto-create the database file. _onSQLConnectFail looks like this:
private function _onSQLConnectFail($evt:SQLErrorEvent):void
{
Out.debug(this,"_onSQLConnectFail");
_isFirstInit = true;
_sql.openAsync(_file, "create");
};
I set an _isFirstInit Boolean to true, which means I can open the database again (this time auto-creating it). I know it's the first time I'm opening it, so I'll set it to be the smallest database possible (512 is the smallest alloId) and set it so it doesn't automatically clean excess data (that's the false). Since I'm already listening for _onSQLConnectSuccess, that'll be my next stop.
private function _onSQLConnectSuccess($evt:SQLEvent):void
{
var statement:SQLStatement = new SQLStatement();
statement.sqlConnection = _sql;
if(_isFirstInit) statement.text = "CREATE TABLE " + Constants.TABLE_INSULTS + "(id INTEGER PRIMARY KEY AUTOINCREMENT,key INTEGER)";
else statement.text = "SELECT * FROM " + Constants.TABLE_INSULTS;
Out.debug(this,"_onSQLConnectSuccess: " + statement.text);
statement.addEventListener(SQLEvent.RESULT,_onSQLInsults,false,0,true);
statement.execute();
};
So I've connected. Now I'll create a new SQL statement. I'll use this statement to tell the database what I need to do. If you've seen mySQL queries before, this should all look eerily familiar. If not, here's what I'm telling the database to do: If I just created the database, create a new table. This table will be named INSULTS (the variable I have in Constants). The table will keep track of two variables: An ID that automatically counts up as I add more to the database (this is a pretty standard practice) and a KEY, which will be a variable I pass. Otherwise, I'll grab all of the rows in the existing table ("SELECT * FROM…") and wait for the result. When I get that data, I just need to turn it into an Array:
_knownInsults = [];
var results:SQLResult = $evt.target.getResult();
if(results) for(var i:int=0;i<results.data.length;i++) { _knownInsults.push(results.data[i].key); }
When a new insult needs to be added to the database, I'll run this function:
public function addToTable($table:String,$key:Number):void
{
var statement:SQLStatement = new SQLStatement();
statement.sqlConnection = _sql;
statement.text = "INSERT INTO " + $table + "(KEY) VALUES(" + $key + ")";
Out.debug(this,"addToTable: " + statement.text);
statement.execute();
};
addToTable(Constants.TABLE_INSULTS,5); // this example would add a new row into my database. Assuming this is the first row ever, the ID will automatically be 1 and the KEY will be 5.
The next time the app opens, these same functions will run, populating my _knownInsults array—all before the user sees a thing!