Eccomi con un nuovo devlog. Questa settimana ho introdotto la componente camera, e la serializzazione per il caricamento e il salvataggio su file dello stato del gioco. Mentre la prima parte è stata abbastanza facile da implementare, la seconda ha richiesto l’aggiunta di una nuova dipendenza e varie modifiche per pagare un po’ di technical debt accumulato durante le iterazioni di sviluppo precedenti.
The smooth
Questo è stato facile. La componente camera ha due attributi principali: il nodo root della scena e il nodo target. Il nodo root della scena è necessario perché dobbiamo simulare la camera, ovvero ciò che viene modificato è in realtà il nodo root della scena. In altre parole, per muovere la camera in una direzione, trasliamo il nodo root della scena verso la direzione opposta. Il nodo target è quello che la camera dovrebbe seguire. Così come il target si muove nella scena, la camera viene aggiornata per avere le stesse coordinate.
La cosa più facile da fare per implementare una camera che segue qualcosa consiste nello scrivere roba come camera.position = target.position
, e sebbene funzioni non è la migliore delle soluzioni. Un approccio migliore e più elegante, che potrebbe anche prevenire casi di motion sickness, sarebbe implementare una camera che abbia un movimento fluido, morbido. Ciò può essere fatto facendo un’interpolazione lineare tra la posizione della camera e la posizione del target usando un piccolo valore ad ogni update del gioco.
void Camera::update() {
float smooth_factor = 0.125f;
Vec2f smoothed_position = lerp(this->position, target->position, smooth_factor);
this->position = smoothed_position;
}
The file
D’altra parte, questa feature ha richiesto un po’ di lavoro in più. Ho iniziato aggiungendo @nlohmann/json come nuova dipendenza del progetto per poter leggere e scrivere file json. Trovo questa libreria molto facile da usare oltre al fatto che l’ho usata con successo in altri progetti, come Jamspot: Sokoban. Il secondo step ha visto l’implementazione di funzioni per salvare e caricare determinati oggetti da file.
void to_json(json& j, const T& t);
void from_json(const json& j, T& t);
La parte più laboriosa è stata assicurarsi che tutte le classi serializzabili potessero essere default constructed. Ciò significa evitare references come membri delle classi e preferire puntatori, quindi permettere la creazione di oggetti inizializzati a metà e fare in modo allo stesso tempo che tali oggetti rimangano in questo stato per il periodo più breve possibile per evitare errori e crash.
Dopo aver risolto tutto, sono stato in grado di modificare la configurazione del gioco, il tileset, e la tilemap a runtime, chiudere il gioco, e riaprirlo per trovare tutto così come avevo lasciato. Ciò risulta di fondamentale importanza per poter lavorare ai livelli del gioco, che saranno parte della prossima iterazione dello sviluppo di ncJump.