SOLVED Best Practice For Initializing Global Variables Whilst (almost) Simultaneously Reading Them From an INI file?

otterZ

Member
What is the best practice for initializing global variables when also (almost simultaneously) reading them from an INI file?

For example, I have an object called 'obj_first_room_controller', where I am initializing global variables at the start of the game in the Create Event. I also have code in that same Create Event to read INI files fetching the value of those same global variables.

For example:
GML:
// This code is in the Create Event in the first room controller object

// Initializing global variables
global.magic = noone;
global.weapons = noone;

// Reading INI file values
global.magic = ini_read_real("savegame", "magic", true);
global.weapons = ini_read_real("savegame", "weapons", false);
So, here are a few questions for what is the best pracitice:

* Do I need to declare and initialize a global variable if I am reading them from an INI file that will do kind of the same thing anyhow? It does make it more readable if I declare and initialize them first though. Plus I'd feel oddly uncomfortable leaving it to the INI file code to initialize them for some reason.
* Should I use true/false, noone or -1 when initializing a global variable when the INI file will write over it anyhow, or does it even matter?
* Should I have the INI read code as a separate object even?
* This object is in a persistent First Room, but would other GM users usually initialize global variables in a Game Start Event?

(Please note that I did not initialize the variables in Room Start, as I only want them accessed at the very start of the game.)

I am starting a new project and this time I want to take the time to code a bit more elegantly, and make it more readable, rather than work/code like a maniac into the early hours with an 'if it works . . . whatever' type attitude.
 

TsukaYuriko

☄️
Forum Staff
Moderator
* Do I need to declare and initialize a global variable if I am reading them from an INI file that will do kind of the same thing anyhow? It does make it more readable if I declare and initialize them first though. Plus I'd feel oddly uncomfortable leaving it to the INI file code to initialize them for some reason.
* Should I use true/false, noone or -1 when initializing a global variable when the INI file will write over it anyhow, or does it even matter?
You don't need to declare them separately if you're going to read them from a file anyway, as it will be declared the first time you assign any value to it. Where that value comes from doesn't matter.

However, what if this file doesn't exist? You'd have to have a way to declare them and set them to something meaningful in that case anyway. What's more is that if at any point you decide that you need to store more data in this file than in a previous version of your game, any file created with an old version of the game and then loaded with the new version of the game won't have this new data stored in it at all. You'd then have to have extra code what checks what exists in the file and, if something doesn't exist, to declare it otherwise and... you get the point.


Therefore:
Declare them to some meaningful default value (e.g. full health when you start the game, no items in inventory...).
After that, read the file and overwrite the variables with whatever data the file contains.

While this is technically redundant, "optimizing" this is not worth the hassle.


* Should I have the INI read code as a separate object even?
If this makes sense from your game's perspective, sure (e.g. there's a save file select screen but some stuff needs to be declared before the title screen). If it doesn't, no. Put it wherever it seems logical to you. If it doesn't need to be split, you may as well keep it grouped closely together, but not necessarily tightly coupled.

For example, you may want to split declaring defaults and loading the save file into separate functions, then call them in sequence. Keeps it neat and tidy, but still grouped.

* This object is in a persistent First Room, but would other GM users usually initialize global variables in a Game Start Event?
I can't speak for others, but in 1.x~2.2 I personally use a non-persistent start room that is visited exactly once during the game's run time and the room creation code (or call a script containing the declarations in said room creation code), while in 2.3 I use a script (as they run at global scope at the start of the game) and the same room as mentioned before.
 
F.I.Y. "Simultaneously" simply doesn't exists in Game Maker.
It would not matter if you had a million (unrelated, of course) operations in-between the declaration and the file read, as long as it's done in the same step.
 

NightFrost

Member
I initialize a variable only if it might not get a value from elsewhere, or may get a value from elsewhere... later. That is, the system requires the variable to be able to run, but it may not have yet received data. Or when I intend to display lack of actionable data with a default value. For example, a UI element base constructor initializes background sprite variable to undefined, and a struct extending it later sets a value, maybe. The draw checks for if(!is_undefined()), and only draws if so. For default values, I use a lot of undefined for resource pointers, and -1 for counters and other numeric range variables.
 

GMWolf

aka fel666
* Do I need to declare and initialize a global variable if I am reading them from an INI file that will do kind of the same thing anyhow? It does make it more readable if I declare and initialize them first though. Plus I'd feel oddly uncomfortable leaving it to the INI file code to initialize them for some reason.
It's a matter of style.
I think it's worth initializing them somewhere on startup just in case you then choose to not load the ini file (debugging, different targets, etc).

* Should I use true/false, noone or -1 when initializing a global variable when the INI file will write over it anyhow, or does it even matter?
It depends on your case.
I think noone is notnthe right answer unless your variable is meant to store an object index or instance index.

If you want to catch any use of the variable that hasn't been loaded from ini, you could use undefined.

If you want your game to run regardless of if you loaded the ini or not then use defaults.

* Should I have the INI read code as a separate object even?
Not necessarily, but I would at least have it as a separate function.

* This object is in a persistent First Room, but would other GM users usually initialize global variables in a Game Start Event?
You could use a first room just for initializing, you could put it in the game start of your first room.
You could do both.


Or you could even put it in global scope as GM will execute that first. I would avoid that however as controlling the order of execution can be tough across multiple scripts.
If you don't would have a single initialization script that does all that.
 

Nidoking

Member
global.magic = ini_read_real("savegame", "magic", true);
global.weapons = ini_read_real("savegame", "weapons", false);
Keep in mind that these lines ARE initializers. The third parameter is the default value if the file or the value within the file doesn't exist. Instead of providing initial values, you can just ensure that this is the first time you use this variable, and it will have the default value you specify. I start my games with the ini read function immediately followed by the ini write function, just to set up the default ini file if it doesn't exist.
 

otterZ

Member
Thank you @TsukaYuriko , @Slow Fingers , @NightFrost , @GMWolf and @Nidoking , that was interesting to get your opinion on this. The upshot seems to be that it is not set in stone - depends on your style and the type of game. Very interesting to find out what approach you all individually take on this.
Kind of like there is wiggle room to select a way that suits you and your game and your preferred way of working.
 

renex

Member
typically when dealing with user-defined files such as inis, i separate my code into 3 parts:

1. a script that gives every single variable a default value, always called before 2
2. a script that replaces those variables with range-checked, sanitized values from the ini file
3. a script that updates the ini file with the current values, always called after 2

doing it like this prevents mistakes from my part and errors from the user's fault.
 
Top