Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Gestione e caricamento degli asset di gioco

Impostare la logica per il caricamento degli asset di gioco (elementi grafici e sprite) e creare un loader
Impostare la logica per il caricamento degli asset di gioco (elementi grafici e sprite) e creare un loader
Link copiato negli appunti

In questa lezione vedremo come aggiungere al game engine un gestore di risorse, che ci permetterà di caricare immagini, suoni ed effettuare il check di eventuali errori, lasciando comunque la possibilità di espandere il "resource handler" per l'aggiunta futura di feature come il caricamento di modelli 3D, shaders e altri tipi di file.

Definiamo l'oggetto (la funzione) ResourcesHandler all'interno di un nuovo file resources.js:

/*
 *  resources.js
 */
function ResourcesHandler(callback) {
	/* dichiarazione proprietà  */
	this.resNumber = 0;
	this.resLoaded = 0; 
	this.errors = [];
	this.status = 0;
	this.loading = false;
}

Inizializziamo le proprietà resNumber e resLoaded, che terranno il conto delle risorse caricate e di quelle ancora in caricamento, un array errors[] che conterrà eventuali errori, una variabile status, che indica la percentuale di caricamento, e una variabile loading che indica se abbiamo chiamato le funzioni per caricare risorse.

Caricare immagini e sprite

Aggiungiamo poi a ResourcesHandler una funzione metodo per caricare le immagini e gli sprite:

function ResourcesHandler(callback) {
	/* dichiarazione proprietà */
	// ...
	/* caricamento sprite e immagini */
	this.LoadSprite = function(url, frames, funct) {
		this.loading = true;
		var img = new Image();
		img.src = url;
		img.rh = this;
		this.resNumber++;
		img.frames = frames;
		this.w = this.width/this.frames;
		img.onload = function() { 
			if(funct != undefined) {
				funct();
			}
			this.w = this.width/this.frames;
			this.rh.resLoaded++;
			this.rh.CheckLoaded();
		};
		img.addEventListener("error", function(e) {
			this.rh.resNumber--;
			this.rh.errors.push([url, e]);
			this.rh.CheckLoaded();
		});
		return img;
	}
}

Vediamo gli argomenti:

Argomento Descrizione
url L'URL dell'immagine da caricare (può anche essere un link locale)
frames Il numero di frames presenti nella nostra immagine
funct (opzionale) la funzione da eseguire al termine del caricamento dell'immagine

In LoadSprite creiamo un'immagine, la assegnamo ad una variabile temporanea img e impostiamo la sorgente dell'immagine (img.src) in base all'argomento url.

Fatto questo aggiungiamo all'oggetto img la proprietà rh, che utilizziamo per mantenere all'interno dello scope di img un riferimento all'istanza attuale dell'oggetto contenitore ResourceHandler. Ci servirà per modificare le variabili del ResourceHandler in una funzione globale che utilizzeremo successivamente.

Dopodiché incrementiamo di 1 il numero di risorse da caricare e salviamo il numero di frames in una variabile locale dell'immagine.

Calcoliamo la larghezza del singolo frame (per gli sprite delle animazioni utilizzeremo strip affiancate, come nella prossima immagine) e la salviamo nella variabile locale img.w (non possiamo utilizzare img.width, dato che è già una variabile interna, corrispondente alla lunghezza dell'intera immagine).

Gestiamo ora l'evento onload di img, che viene scatenato quando il caricamento dell'immagine è completo: incrementiamo il numero di risorse caricate di 1, ed eseguiamo (se esiste) la funzione passata come parametro, infine controlliamo se il processo di caricamento è terminato, tramite la funzione CheckLoaded del ResourceHandler che definiremo tra poco.

Infine gestiamo l'evento error per dare qualche informazione in più sull'eccezione generata, tipicamente un problema di caricamento dell'immagine. Inseriamo nell'array errors[] del ResourceHandler, un array di due elementi, contenente l'URL dell'immagine impossibile da caricare e l'errore ritornato.

Ovviamente il report degli errori può essere migliorato, traducendo l'errore riscontrato ("URL non funzionante", "immagine corrotta" o "formato non supportato") e cercando eventuali soluzioni, ma questo va oltre lo scopo di questa guida.

Infine controlla nuovamente se il caricamento è completato, utilizzando CheckLoaded e ritorna un riferimento a img.

Nota: Anche se il riferimento all'immagine si ottiene instantaneamente, questa viene caricata in modo asincrono, è quindi necessario attendere una risposta dall'evento load o error prima di utilizzarla.

Loader, gestire il caricamento degli asset

Ora aggiungiamo al ResourceHandler, la funzione CheckLoaded (sempre in resources.js). Questa funzione si occuperà di due cose:

  • Disegnare la barra di avanzamento, utilizzando DrawLoading (che definiremo successivamente)
  • Controllare se il numero di risorse caricate + numero di risorse che hanno dato errore sia maggiore o uguale al numero di risorse da caricare, e quindi eseguire la funzione callback() passata come argument al ResourceHandler.

function ResourcesHandler(callback) {
	/* dichiarazione proprietà */
	// ...
	/* caricamento sprite e immagini */
	// ...
	/* controllo caricamento risorse */
	this.CheckLoaded = function() {
		if(!this.loading) return null;
		this.DrawLoading();
		if(this.resLoaded + this.errors.length >= this.resNumber) {
			callback();
			this.resNumber = 0;
			this.resLoaded = 0;
			this.loading = false;
		}
	}
}

Disegno del loader

Definiamo quindi, la funzione DrawLoading, con cui creiamo l'animazione che appare durante il caricamento.

function ResourcesHandler(callback) {
	/* dichiarazione proprietà */
	// ...
	/* caricamento sprite e immagini */
	// ...
	/* controllo caricamento immagini */
	// ...
	/* disegno del loader */
	this.DrawLoading = function() {
		//percentuale di caricamento
		this.status = (this.resLoaded) / (this.resNumber + this.errors.length);
		//centro del canvas
		var cx = game.canvas.width/2;
		var cy = game.canvas.height/2;
		//imposta il colore di riempimento
		game.ctx.fillStyle = "#333";
		//disegna un rettangolo grande quanto il canvas
		game.ctx.fillRect(0, 0, game.canvas.width, game.canvas.height);
		//avvia il path di disegno primitive
		game.ctx.beginPath();
		game.ctx.strokeStyle = "#222";
		//imposta lo spessore della linea da disegnare
		game.ctx.lineWidth = 25;
		//aggiunge un arco al path (una corona circolare di raggio 80)
		game.ctx.arc(cx, cy, 80, 0, Math.PI*2, false);
		//disegna il path
		game.ctx.stroke();
		//calcola i radianti del secondo arco,
		var radians = (360 * this.status) * Math.PI / 180;
		//disegna il secondo arco
		game.ctx.beginPath();
		game.ctx.strokeStyle = "#ddd";
		game.ctx.lineWidth = 25;
		game.ctx.arc(cx, cy, 80, 0 - 90*Math.PI/180, radians - 90*Math.PI/180, false);
		game.ctx.stroke();
		//Imposta un font e disegna il testo al centro del cerchio di caricamento
		game.ctx.font = '22pt Segoe UI Light';
		game.ctx.fillStyle = '#ddd';
		game.ctx.fillText(Math.floor(this.status*100) + "%",cx-25,cy+10);
	}
}

Drawloading disegnerà una corona circolare grigia, che viene riempita da un'arco di corona bianco con il procedere del caricamento. Il risultato è questo:

Ti consigliamo anche