Risoluzione e aspect ratio in GameMaker

Avviano il tuo gioco su uno schermo ultrawide e si ritrovano le bande nere ai lati. Oppure su Steam Deck la viewport non occupa tutto lo schermo. La gestione della risoluzione è uno di quei problemi che si rimandano finché non si presenta un caso concreto, e a quel punto tocca capire cosa fare.
In questo articolo raccogliamo le soluzioni discusse nella community di GMI: adattamento dinamico, pixel perfect, e come gestire (o sfruttare) le bande nere quando ci sono.
Le strade principali sono tre:
Adattamento dinamico - la finestra si ridimensiona e la camera si aggiusta di conseguenza.
Pixel perfect con bande nere - si mantiene un aspect ratio fisso accettando di sacrificare i bordi.
Stretch - Veloce da implementare (letteralmente una spunta) ma sconsigliato
Adattamento dinamico
La soluzione che ho usato in Chakana (un gioco 3D), aggiorna l'aspect ratio della camera ogni volta che la finestra cambia dimensione. L'idea è nata proprio risolvendo i problemi di visualizzazione su widescreen:
// Funzione da chiamare quando cambia la dimensione della finestra
refresh_aspect = function() {
var ww = window_get_width();
if (ww <= 0) ww = display_get_width();
var wh = window_get_height();
if (wh <= 0) wh = display_get_height();
last_window_width = ww;
last_window_height = wh;
calculate_gui_size();
if (ww != 0 && wh != 0) {
resize_surfaces();
main_cam.ratio = ww / wh;
main_cam.update_perspective_matrix();
}
}// Step event: controlla se la finestra è cambiata
if (ww != last_window_width || wh != last_window_height) {
refresh_aspect();
}La camera 3D aggiorna la propria matrice di proiezione col nuovo ratio:
static update_perspective_matrix = function() {
var aspect_ratio = last_window_width / window_last_height;
matrix = matrix_build_projection_perspective_fov(self.fov, aspect_ratio, 0.1, 10000);
matrix[5] *= -1;
camera_set_proj_mat(camera, matrix);
}
Il codice è pensato per il 3D, ma il principio vale anche in 2D. La cosa importante è che la GUI sia ancorata al bordo destro e in basso: ad esempio anzichè usare un valore fisso come 580 e 400, usare gui_width - 80 e gui_height - 80, in questo modo l'interfaccia rimarrà ancorata ai bordi quando si allarga la finestra.
Nel 2D l'adattamento dinamico si traduce nel modificare l'ampiezza o l'altezza della telecamera per mostrare più o meno porzione di livello, mantenendo però la proporzione dei pixel invariata (evitando lo stretching).
Il codice seguente rileva il cambio di risoluzione e ridimensiona la camera in base alla variazione dell'altezza della finestra, estendendo la visuale in larghezza (orizzontalmente):
// Create Event di un tuo oggetto che gestisce la finestra
// Altezza base di riferimento
base_height = 360;
base_width = 640;
gui_base_height = 360;
last_window_width = 0;
last_window_height = 0;
view_scale = 4;
/// @function refresh_view()
refresh_view = function() {
var ww = window_get_width();
var wh = window_get_height();
if (ww <= 0 || wh <= 0) return;
last_window_width = ww;
last_window_height = wh;
// Calcola nuova larghezza camera mantenendo ALTEZZA fissa
// Larghezza = altezza * aspect_ratio della finestra
var aspect = ww / wh;
var new_width = round(base_height * aspect);
// Aggiorna camera: altezza fissa, larghezza adattata
camera_set_view_size(view_camera[0], new_width / view_scale, base_height / view_scale);
var scale = window_get_height() / gui_base_height;
display_set_gui_maximise(scale, scale, 0, 0);
// Ridimensiona application surface
surface_resize(application_surface, ww, wh);
};
// Applica subito
refresh_view();// Step Event
var ww = window_get_width();
var wh = window_get_height();
if (ww != last_window_width || wh != last_window_height) {
refresh_view();
}Vantaggi
- Niente bande nere su tutti i tipi di schermo
- Si può lasciare il resize libero della finestra
Svantaggi
- Con schermi ultra-wide il giocatore potrà vedere una porzione più ampia della room.
Se il design del tuo gioco prevede una difficoltà basata sulla visione limitata (ad esempio alcuni boss di Hollow Knight: Silksong), potrebbe abbassare artificialmente la difficoltà. - Bisogna gestire bene la UI per non uscire dallo schermo ed evitare sovrapposizioni se la finestra si restringe troppo


Pixel perfect con bande nere
Le risoluzioni come 480x270 e 640x360 (quindi i multipli di 1920x1080) scalano in modo pulito sui display più comuni full HD, e sono un buon punto di partenza se vuoi mantenere la pixel art precisa.
In fullscreen su schermi con aspect ratio diverso, i bordi laterali saranno coperti dalle classiche bande nere.
Ampliare la visuale infatti non è sempre desiderabile. In Lone Planet di Ballman, ad esempio, il level design è costruito attorno a una risoluzione fissa, e mostrare più schermo rompe l'esperienza. Le bande nere in quel caso sono una scelta, non un ripiego.
ci sono 2 ottimi articoli di Nocturne sul blog di GameMaker riguardo allo scaling:
- https://gamemaker.io/en/tutorials/the-basics-of-scaling-the-game-camera
- https://gamemaker.io/en/blog/the-basics-of-scaling-the-gui-layer
Colorare le bande nere
Se le bande ci sono, almeno non devono essere nere. Né le Game Options né window_set_colour() bastano da soli - la soluzione l'ha trovata Mad: usare draw_clear() nell'evento Pre-Draw.
// Evento Pre-Draw
draw_clear(colore_desiderato);Il Pre-Draw disegna direttamente sul display buffer, che copre l'intera finestra incluso lo spazio fuori dai viewport. Gli altri eventi Draw operano dentro i confini della camera, quindi non raggiungono quelle zone.
Attenzione: perché funzioni, il clearing automatico dei viewport va disabilitato nelle impostazioni della Room, altrimenti il primo viewport sovrascrive tutto. Se lo disabiliti, gestisci il clearing manualmente con draw_clear_alpha() per evitare i trail frame su frame.
Sfruttare lo spazio fuori dai bordi
Le bande non devono per forza essere spazio vuoto. Si può disegnare roba fuori dai confini della viewport - il giocatore la vedrà solo se allarga la finestra abbastanza da rivelare quella zona. Mad, per esempio lo ha usato per delle cornici decorative su NothingElse un gioco con viewport quadrata: più ingrandisci la finestra, più contenuto appare ai lati.

Goldensun ha espanso l'idea con il suo gioco Resize Land facendo del resize una meccanica vera e propria.
Stretch
Non t'azzardare!
(se proprio non hai tempo e non vuoi le bande nere c'è il pulsantino nei game settings...)
