@TsukaYuriko is wise. Json is beautiful, Json is good.
Let's sat you have an object in a game, and the object has data.
Let's give the object a data structure:
myData = ds_map_create();
Done.
Now, the data has some properties:
Code:
myData[?"sprite"] = "nameOfSprite";
myData[?"name"] = "nameOfObject";
myData[?"description"] = "description";
myData[?"cost"] = amount;
Done.
This much, then, is easy with code. You can quickly and easily design level editors and such, and set these properties accordingly and use code to place the data into a map. And this method goes deeper.
Suppose the object's data should include...a list of items.
Code:
myItemList = ds_list_create();
ds_list_add(myItemList, "item_0", "item_1", "item_2");
ds_map_add_list(myData, "itemList", myItemList);
Done. Now, the value of myData[?"itemList"] is a list of data, embedded within the overall data structure. So yea, you can make a structure with names and values....and the values can be regular text or number data but ALSO map and list structures. Maps inside of maps. Lists inside of maps. All the data in one structure. Easily accessible.
Now, you want to store this as text in a file, right? Json. The ds_map and ds_list structures convert to and from json natively. Check this out:
Tadaaaa! Your whole data structure, with nested lists and all, is now a simple string that you can write to a text file. You can read it out from a text file and convert it back to maps and list like this:
Writing it down? Depends on how you want to store it, but could be this simple:
Code:
var file = file_text_open_write("my_filename.txt");
file_text_write_string( json_encode(myData) );
file_text_close(file);
Just like that, you have a file with all of that object's data. But now, you need to read that data back in, and put the data back into maps and lists for the game, right? So you create your object, and then you do this:
Code:
if( file_exists("my_filename.txt")){
var file = file_text_open_read("my_filename.txt");
var data = file_text_read_string(file);
file_text_close(file);
var map = json_decode(data);
if( map!=-1 ){
myData = map;
}
}
That's a bit thorough, more code than strictly needed but here's the idea:
- You create the object. Since you don't know initially whether there's saved data, you create, in the Create Event, something like a default value for myData...maybe something like -1. (Bear in mind that you'll want ALL of your code to check for whether myData is -1 before reading from it. This is not specific to ds_maps....any circumstance where you load external data into your game *should* have code to check whether the data is ACTUALLY loaded before trying to read from it, and a condition to fail gracefully with an error if not.
- The object checks for the existence of a file that should have its data.
- If the data is there, read it, and attempt to turn it into a decoded map structure.
- If that succeeds, myData is now equal to the map containing all of the needed data and data lists.
- If it fails, myData remains -1 or whatever--it doesn't change at all as a result of this process since no valid map was found.
That's the idea, in a nutshell, and GameMaker does all of the heavy lifting in terms of building out your data structures for you. Now, if want to edit the data *externally* instead of building a ds_map in code and using json_encode(), you can do that, too. The data is readable, assuming you know the basic format:
{Curly Brackets} are Maps (objects in json)
[Square brackets] are lists
The rest is data.
Data values are referenced by names, or "keys."
Keys and value pairs are separated by : colon
Data is separated by comma (,)
Everything I described above, then, looks like this in JSON.
Code:
{
"sprite" : "nameOfSprite",
"name" : "nameOfObject",
"description" : "description",
"cost" : 10,
"myItems" : [ "item_0", "item_1", "item_2"]
}
Notice that the entire thing is within curly brackets, and then the name of a thing is in quotes followed by a colon, followed by the data stored with that key, followed by a comma.
Most of the key names are followed by just a piece of data, but the last one is followed by a square bracket, which means that a LIST is stored at that key. Then each item appears in the list.
Back in GameMaker, you might have something like this to read and use the sprite info:
Code:
if( myData!= -1){
spriteName = myData[?"sprite"];
sprite_index = asset_get_index(smriteName);
}
To get things from the list, it might be this:
Code:
if( myData!=-1 ){
var myList = myData[?"itemList"];
first_item = myList [|0];
}
Note that I retrieved the list from myData, then I can use it like a regular ds_list, including getting the size and looping through items, or whatever I need. (And note that I used the | accessor, since it's a ds_list, not an array).
Once you're working with maps/lists in your code and saving them all out to JSON, it becomes pretty quickly apparent how insanely powerful everything gets. Since everything in a map has a name, it's very powerful and easy to modify your data.
Last point to make, by way of comparison, if you haven't drifted off to sleep yet...
When I first started using this stuff about 4 years ago, I was working with data set property stuff like you. I was storing things in "long sets"--basically the CSV approach, where each "row" is an item, and each "column" is a piece of data about the item. Here's a fun problem I kept having:
This row starts at counting index zero and has properties: shape, color, x, y, description. EZ. Need the X and Y coord? Look up item 2 and 3.
WAIT! I need width and height, too. That'll be useful! Ok, I can put those in after x, y....but that means the position of description just changed, so I've got to change that code, too.........OR I can just tack width and height onto the end. Ok. New row data:
shape, color, x, y, description, width, height
Wait, the color should be customize-able! I need r, g, and b! Ummmmm. If I replace "color" with R, G, and B, then ALL of my data shifts over by 2 spaces. Unless I store it as a string and parse it later?
WAIT! All of these custom appearance settings should go into a central style sheet, to be shared by multiple items...um... So...really, I need:
style, x, y, description?
But that shifts all my data around again!!! GRAREORGRGGE!
And then I discovered that I could just use data structures. Need to change color from a single value to a list of 3 numbers? Fine. Instead of "color" : "ff0000", make it "color" : [255, 0, 0]. The code that reads and interprets what to do with color has to be changed, of course, but
no other data in the structure is affected in any way at all. Re-structuring things, and inserting lists and even entire additional map structures into things is simple and easy, and quite robust.