GMS 2.3+ Problem with saving characters location in JSON

So I have been trying to save the x and y coordinates of the player in the room and load the player in the same x and y coordinates (the same place he was when the game is saved but I can't get it to work can anyone help? I thought using the .x and .y after an object meant saving the location of that object so why doesn't it work?? Object1 is the player by the way.


Saving object code :


GML:
var _saveData = array_create(0);



//for every instance, create a struct and add it to the array

with (Object1)

{

    var _saveEntity =

    {

        obj : object_get_name(object_index),

         saved_room : room,

        save_name : global.realName,

        player_x : Object1.x,

        player_y : Object1.y,

    }

    array_push(_saveData, _saveEntity);

}



//turn all this data into a JSON string and save it via a buffer

var _string = json_stringify(_saveData);

var _buffer = buffer_create(string_byte_length(_string) +1, buffer_fixed, 1);

buffer_write( _buffer, buffer_string, _string);

buffer_save ( _buffer, "savedgame.save");

buffer_delete( _buffer);



Loading object code :

GML:
if (file_exists("savedgame.save"))

                    {



                        var _buffer = buffer_load("savedgame.save");

                        var _string = buffer_read( _buffer, buffer_string);

                        buffer_delete( _buffer);

               

                        var _loadData = json_parse( _string);

               

                        while (array_length(_loadData) > 0)

                        {

                            var _loadEntity = array_pop(_loadData);

                            with (instance_create_layer(0,0,layer,asset_get_index(_loadEntity.obj)))

                            {

                                room = _loadEntity.saved_room;

                                Object1.x = _loadEntity.player_x;

                                Object1.y = _loadEntity.player_y;

                                global.realName = _loadEntity.save_name;

                           

                            }

                        }

                    }
 
Last edited:

kupo15

Member
did you open up the save file to make sure it saved those values just to double check? Also, what happens when you show message _loadEntity.player_x? Does it give you the value you stored?

(lastly use code tags to make it easier to read please: code=gml)
 
I didn't know you could open the JSON file and check it how is that possible? What do you mean by show message? I changed it so that it has code tags
 
Last edited:

kupo15

Member
well, you are simply creating a json file. Go into your local app folder (the one where saved data for the game is stored) and open it up in notepad. You can copy that text to a json viewer or notepad++ has a json formatting plugin to make it easier to read.

So then check to see if the file is storing the information you expected it to store. For the show message another way to check the loading for example is to do show_message(_loadEntity.player_x) to see what value is being assigned to your player xpos from the file. You can also show message the _loadEntity if you wanted to show the full json file that you loaded in to make sure its correct
 

chamaeleon

Member
Unrelated, but to save you headaches down the road, don't store asset ids in save files, store their names or some other representative value you define yourself. room value for any given room may change between releases. For any assets use the corresponding get name function (in this case, room_get_name()), and upon loading convert it as needed using asset_get_id(). Applies to objects, sprites, etc.
 

GMWolf

aka fel666
Couple things:

Object1.x will get the X variable of an instance of Object1. So if you only have one object of that type it will work but not otherwise.
Generally speaking you should avoid accessing variables through Object names rather than instances.


with( foobar ) already changes the scope to the foobar instance.
So instead of doing 'Object1.x' you can just do 'x' in both your loading and saving code.
 
Couple things:

Object1.x will get the X variable of an instance of Object1. So if you only have one object of that type it will work but not otherwise.
Generally speaking you should avoid accessing variables through Object names rather than instances.


with( foobar ) already changes the scope to the foobar instance.
So instead of doing 'Object1.x' you can just do 'x' in both your loading and saving code.
I changed the code but it didn't save the Object1 location (the player)






GML:
var _saveData = array_create(0);

//for every instance, create a struct and add it to the array
with (Object1)
{
    var _saveEntity =
    {
        obj : object_get_name(object_index),
         saved_room : room,
        save_name : global.realName,
        player_x : x,
        player_y : y,
      
    }
    array_push(_saveData, _saveEntity);
}

//turn all this data into a JSON string and save it via a buffer
var _string = json_stringify(_saveData);
var _buffer = buffer_create(string_byte_length(_string) +1, buffer_fixed, 1);
buffer_write( _buffer, buffer_string, _string);
buffer_save ( _buffer, "savedgame.save");
buffer_delete( _buffer);
GML:
if (file_exists("savedgame.save"))
                    {

                        var _buffer = buffer_load("savedgame.save");
                        var _string = buffer_read( _buffer, buffer_string);
                        buffer_delete( _buffer);
                  
                        var _loadData = json_parse( _string);
                  
                        while (array_length(_loadData) > 0)
                        {
                            var _loadEntity = array_pop(_loadData);
                            with (instance_create_layer(0,0,layer,asset_get_index(_loadEntity.obj)))
                            {
                                room = _loadEntity.saved_room;
                                x = _loadEntity.player_x;
                                y = _loadEntity.player_y;
                                global.realName = _loadEntity.save_name;
                              
                            }
                        }
                    }
 
Unrelated, but to save you headaches down the road, don't store asset ids in save files, store their names or some other representative value you define yourself. room value for any given room may change between releases. For any assets use the corresponding get name function (in this case, room_get_name()), and upon loading convert it as needed using asset_get_id(). Applies to objects, sprites, etc.
How would that work?
Like this for saving:

GML:
saved_room : room_get_name(room),
and like this for loading:

GML:
asset_get_index(room) = _loadEntity.saved_room;
by the way, asset_get_id doesn't exist as a function, so what do you mean by that code?
 

GMWolf

aka fel666
Did you check the contents of the saved JSON file?
It's just a text file. Any text editor should be able to open it.
 

chamaeleon

Member
How would that work?
Like this for saving:

GML:
saved_room : room_get_name(room),
and like this for loading:

GML:
asset_get_index(room) = _loadEntity.saved_room;
by the way, asset_get_id doesn't exist as a function, so what do you mean by that code?
Sorry, I did mean asset_get_index(). As for the loading part, convert the room to an an asset first, then use room_goto() to go to the room when it make sense to do so in your code.
GML:
saved_room = asset_get_index(saved_room);
...
room_goto(saved_room);
 
Ok I can't find the JSON file for some reason, but I checked using show_message( _loadEntity.player_x) and it does save the characters location x and y (they change if I save somewhere else) but it just doesn't load them
 

chamaeleon

Member
Ok I can't find the JSON file for some reason, but I checked using show_message( _loadEntity.player_x) and it does save the characters location x and y (they change if I save somewhere else) but it just doesn't load them
Is this restarting the program from the IDE? If so, you'll have to keep in mind that each build/run from the IDE uses a new temporary directory. Essentially a clean slate every run.
 
Sorry, I did mean asset_get_index(). As for the loading part, convert the room to an an asset first, then use room_goto() to go to the room when it make sense to do so in your code.
GML:
saved_room = asset_get_index(saved_room);
...
room_goto(saved_room);
That gave me this error :
___________________________________________
############################################################################################
ERROR in
action number 1
of Step EventObject1
for object savedata:

Variable Object1.saved_room(100115, -2147483648) not set before reading it.
at gml_Object_savedata_Collision_Object1 (line 20) - saved_room : asset_get_index(saved_room),
############################################################################################
gml_Object_savedata_Collision_Object1 (line 20)
 

chamaeleon

Member
That gave me this error :
___________________________________________
############################################################################################
ERROR in
action number 1
of Step EventObject1
for object savedata:

Variable Object1.saved_room(100115, -2147483648) not set before reading it.
at gml_Object_savedata_Collision_Object1 (line 20) - saved_room : asset_get_index(saved_room),
############################################################################################
gml_Object_savedata_Collision_Object1 (line 20)
I just gave sample code. I made no attempt to make sure the variable name used is correct. Adjust according to what you have in your code.
 
I just gave sample code. I made no attempt to make sure the variable name used is correct. Adjust according to what you have in your code.
My bad I didn't think about how the code would work so I tried it after creating the save_room but even then it just gives you an error

Code:
___________________________________________
############################################################################################
ERROR in
action number 1
of  Step Event0
for object Object18:

Unexisting room number: -1
at gml_Object_Object18_Step_0 (line 19) -                                                          room_goto( _loadEntity.saved_room1);
############################################################################################
gml_Object_Object18_Step_0 (line 19)
Save Code :

GML:
var l57DB53F0_0;
l57DB53F0_0 = keyboard_check_pressed(ord("Z"));
if (l57DB53F0_0)
{
   



//make save array
var _saveData = array_create(0);

//for every instance, create a struct and add it to the array
with (Object1)
{
    var _saveEntity =
    {
        obj : object_get_name(object_index),
         saved_room1 : asset_get_index(saved_room),
        save_name : global.realName,
        player_x : x,
        player_y : y,
       
    }
    array_push(_saveData, _saveEntity);
}

//turn all this data into a JSON string and save it via a buffer
var _string = json_stringify(_saveData);
var _buffer = buffer_create(string_byte_length(_string) +1, buffer_fixed, 1);
buffer_write( _buffer, buffer_string, _string);
buffer_save ( _buffer, "savedgame.save");
buffer_delete( _buffer);


}
Step code :

GML:
Object1.saved_room = room_last
Load code :
GML:
if (file_exists("savedgame.save"))
                    {

                        var _buffer = buffer_load("savedgame.save");
                        var _string = buffer_read( _buffer, buffer_string);
                        buffer_delete( _buffer);
                   
                        var _loadData = json_parse( _string);
                   
                        while (array_length(_loadData) > 0)
                        {
                            var _loadEntity = array_pop(_loadData);
                            with (instance_create_layer(0,0,layer,asset_get_index(_loadEntity.obj)))
                            {
                             
                                x = _loadEntity.player_x;
                                y = _loadEntity.player_y;
                                global.realName = _loadEntity.save_name;
                                 room_goto( _loadEntity.saved_room1);
                            }
                        } show_message( _loadEntity.player_x)
                    }
 

chamaeleon

Member
My bad I didn't think about how the code would work so I tried it after creating the save_room but even then it just gives you an error

Code:
___________________________________________
############################################################################################
ERROR in
action number 1
of  Step Event0
for object Object18:

Unexisting room number: -1
at gml_Object_Object18_Step_0 (line 19) -                                                          room_goto( _loadEntity.saved_room1);
############################################################################################
gml_Object_Object18_Step_0 (line 19)
You should add some show_debug_message() statements in relevant parts of code (or breakpoints if you prefer to use the debugger, both a solid tools well worth being familiar with), showing what the strings are before converting to asset ids, verifying that you have correct data before trying to make it into an asset. -1 one as a room number seems to indicate the string you converted was not the name of a room to begin with, so you need to figure out why that is.
 
Top