Sistema di salvataggi

Salvare e caricare i progressi è una di quelle cose che, prima o poi tocca fare.
E anche se GameMaker offre già alcune funzioni base per gestire file (i file .ini ad esempio), spesso sono complicate da gestire e richiedono ripetizioni di blocchi di codice.
Per questo ho preparato uno script GML mono-file pensato per semplificare tutto il processo: un sistema di salvataggio basato su file JSON, facile da integrare in qualunque progetto.
Basta creare un nuovo script Storage.gml e incollare questo
global.local_storage = [];
global.local_storage_slot = 0;
global.local_storage_max_save_slots = 1; // You can change this to the desired number of slots
for (var i = 0; i < global.local_storage_max_save_slots; i++) {
var fname = "save_slot_" + string(i) + ".json";
global.local_storage[i] = {
fname: fname,
data: {}
};
}
if(storage_slot_exists(global.local_storage_slot))
storage_load();
/**
* @desc Set the current active slot
* @param {Real} slot - The slot index to set as active
*/
function storage_set_slot(slot) {
if (slot < 0 || slot >= global.local_storage_max_save_slots) {
show_error("Invalid save slot.", false);
return;
}
local_storage_slot = slot;
}
/**
* @desc Check if the save file exists for a given slot
* @param {Real} slot - The slot index to check
* @returns {bool} - Returns true if the save file exists, false otherwise
*/
function storage_slot_exists(slot) {
if (slot < 0 || slot >= global.local_storage_max_save_slots) {
show_error("Invalid save slot.", false);
return false;
}
var fname = "save_slot_" + string(slot) + ".json";
return file_exists(fname);
}
/**
* @desc Load the storage data from the current slot
*/
function storage_load() {
var slot = global.local_storage_slot;
var fname = global.local_storage[slot].fname;
if (!file_exists(fname)) {
show_error("Save file does not exist.", false);
return;
}
var buf = buffer_load(fname);
var json = "{}";
if(buffer_get_size(buf) > 0) {
buffer_seek(buf, buffer_seek_start, 0);
json = buffer_read(buf, buffer_text);
buffer_delete(buf);
}
try {
global.local_storage[slot].data = json_parse(json);
} catch (error) {
show_error($"Failed to parse save data. Please move the corrupted file into another directory {fname}: {json}", false);
}
}
/**
* @desc Save the storage data to the current slot
*/
function storage_save() {
var slot = global.local_storage_slot;
var json = "";
try {
json = json_stringify(global.local_storage[slot].data, true);
} catch (error) {
show_error($"Failed to save a corrupted storage: {global.local_storage[slot].data}", false);
return;
}
var buf = buffer_create(string_byte_length(json), buffer_fixed, 1);
buffer_write( buf, buffer_text, json);
try {
buffer_save ( buf, global.local_storage[slot].fname);
} catch(error) {
print($"{error}: unable to save game");
}
buffer_delete( buf);
}
function storage_clear() {
global.local_storage = [];
for (var i = 0; i < global.local_storage_max_save_slots; i++) {
var fname = "save_slot_" + string(i) + ".json";
global.local_storage[i] = {
fname: fname,
data: {}
};
}
}
function storage_print() {
show_debug_message(global.local_storage);
}
/**
* @param {String} key
* @param {any} value
*/
function storage_set(key, value) {
var slot = global.local_storage_slot;
global.local_storage[slot].data[$ key] = value;
}
/**
* @param {String} key
*/
function storage_delete(key) {
var slot = global.local_storage_slot;
struct_remove(global.local_storage[slot].data, key);
}
/**
* Get value from storage
* @param {String} key
* @param {any*} [default_value]
*/
function storage_get(key, default_value=undefined) {
var slot = global.local_storage_slot;
if (struct_exists(global.local_storage[slot].data, key))
return global.local_storage[slot].data[$ key];
return default_value;
}Adesso abbiamo accesso a tutta una serie di funzionalità comode.
Cosa fa
In pratica, lo script crea una piccola struttura globale dove puoi salvare e caricare qualsiasi dato del tuo gioco posizione del giocatore, livello, opzioni, inventario, ecc.
All'occorrenza poi, viene memorizzato in un file .json per mantenere i nostri dati tra le varie sessioni di gioco o caricarli su cloud.
Puoi avere più slot di salvataggio, ognuno con il proprio file indipendente.
Perfetto se vuoi gestire profili diversi o più partite separate.
Come si usa
1. Inizializza lo storage
Dove farlo dipende dal tuo progetto, può essere all'avvio del gioco o al click di "Carica partita"
storage_set_slot(0);
if (storage_slot_exists(0))
storage_load();2. Metti i dati nello storage
storage_set("player_x", player.x);
storage_set("player_y", player.y);
storage_set("coins", coins);2. Leggi i dati dallo storage
var hp = storage_get("hp", 0); //il secondo parametro è il valore default nel caso non venisse trovato "hp" nello storage, utile per inizializzare
show_debug_message($"Player HP: {hp}");
var coins = storage_get("coins", 0);
show_debug_message($"Coins: {coins}");
var stats = {
strength: 5,
dexterity: 3,
mana: 2
}
storage_set("player_stats", stats)
//per cancellare un elemento dallo storage
storage_delete("coins");3. Salva i dati su disco
Quando il gioco deve salvare (autosalvataggio o salvataggio manuale da parte del giocatore), è sufficiente chiamare una funzione che si occuperà di salvare nello slot precedentemente selezionato
storage_save();Ci sono altre funzioni utili, ma lascio a te il piacere di scoprirle.