Cosa devi sapere quando converti un gioco Flash in HTML5?

Pubblicato: 2022-03-10
Riepilogo rapido ↬ I suggerimenti presentati in questo articolo mirano ad aiutare gli sviluppatori di giochi HTML5 a evitare errori comuni durante la conversione dei loro giochi Flash in JavaScript, oltre a rendere l'intero processo di sviluppo il più agevole possibile. È richiesta una conoscenza di base di JavaScript, WebGL e del framework Phaser.

Con l'aumento dell'utilizzo di HTML5, molte aziende iniziano a rifare i loro titoli più popolari per sbarazzarsi di Flash obsoleti e abbinare i loro prodotti ai più recenti standard del settore. Questo cambiamento è particolarmente visibile nei settori del gioco d'azzardo/casinò e intrattenimento ed è in corso da diversi anni, quindi una discreta selezione di titoli è già stata convertita.

Sfortunatamente, durante la navigazione in Internet, è possibile spesso imbattersi in esempi di un lavoro apparentemente frettoloso, che si traduce nella qualità dell'amante del prodotto finale. Ecco perché è una buona idea che gli sviluppatori di giochi dedichino parte del loro tempo a familiarizzare con l'argomento della conversione da Flash a HTML5 e ad imparare quali errori evitare prima di mettersi al lavoro.

Tra i motivi per scegliere JavaScript al posto di Flash, oltre agli ovvi problemi tecnici, c'è anche il fatto che cambiare il design del tuo gioco da SWF a JavaScript può produrre una migliore esperienza utente, che a sua volta gli conferisce un aspetto moderno. ma come farlo? Hai bisogno di un convertitore di giochi JavaScript dedicato per sbarazzarti di questa tecnologia obsoleta? Bene, la conversione da Flash a HTML5 può essere un gioco da ragazzi: ecco come prendertene cura.

Letture consigliate : Principi di HTML5 Game Design

Come migliorare l'esperienza di gioco HTML5

La conversione di un gioco in un'altra piattaforma è un'eccellente opportunità per migliorarlo, risolverne i problemi e aumentare il pubblico. Di seguito sono elencate alcune cose che possono essere fatte facilmente e vale la pena considerare:

  • Supportare i dispositivi mobili
    La conversione da Flash a JavaScript consente di raggiungere un pubblico più ampio (utenti di dispositivi mobili); il supporto per i controlli touchscreen di solito deve essere implementato anche nel gioco. Fortunatamente, sia i dispositivi Android che iOS ora supportano anche WebGL, quindi di solito è possibile ottenere facilmente un rendering di 30 o 60 FPS. In molti casi, 60 FPS non causeranno alcun problema, che migliorerà solo con il tempo, man mano che i dispositivi mobili diventano sempre più performanti.

  • Miglioramento delle prestazioni
    Quando si tratta di confrontare ActionScript e JavaScript, quest'ultimo è più veloce del primo. Oltre a questo, la conversione di un gioco è una buona occasione per rivisitare gli algoritmi utilizzati nel codice del gioco. Con lo sviluppo di giochi JavaScript puoi ottimizzarli o eliminare completamente il codice inutilizzato lasciato dagli sviluppatori originali.
  • Correzione di bug e miglioramenti al gameplay
    Avere nuovi sviluppatori che esaminano il codice sorgente del gioco può aiutare a correggere bug noti o scoprirne di nuovi e molto rari. Ciò renderebbe il gioco meno irritante per i giocatori, il che li farebbe trascorrere più tempo sul tuo sito e li incoraggerebbe a provare gli altri tuoi giochi.
  • Aggiunta di analisi web
    Oltre a monitorare il traffico, l'analisi web può anche essere utilizzata per raccogliere informazioni su come si comportano i giocatori in un gioco e dove si bloccano durante il gioco.
  • Aggiunta della localizzazione
    Ciò aumenterebbe il pubblico ed è importante per i bambini di altri paesi che giocano al tuo gioco. O forse il tuo gioco non è in inglese e vuoi supportare quella lingua?
Altro dopo il salto! Continua a leggere sotto ↓

Perché saltare HTML e CSS per l'interfaccia utente di gioco migliorerà le prestazioni di gioco

Quando si tratta di sviluppo di giochi JavaScript, si potrebbe essere tentati di sfruttare HTML e CSS per pulsanti, widget e altri elementi della GUI all'interno del gioco. Il mio consiglio è di stare attenti qui. È controintuitivo, ma in realtà sfruttare gli elementi DOM è meno performante su giochi complessi e questo acquista più significato sui dispositivi mobili. Se desideri ottenere 60 FPS costanti su tutte le piattaforme, potrebbe essere necessario dimettersi da HTML e CSS.

Elementi della GUI non interattivi, come barre della salute, barre delle munizioni o contatori di punteggio possono essere facilmente implementati in Phaser utilizzando immagini regolari (la classe Phaser.Image ), sfruttando la proprietà .crop per il taglio e la classe Phaser.Text per semplificare etichette di testo.

Tali elementi interattivi come pulsanti e caselle di controllo possono essere implementati utilizzando la classe Phaser.Button . Altri elementi più complessi possono essere composti da diversi tipi semplici, come gruppi, immagini, pulsanti ed etichette di testo.

Nota: ogni volta che si crea un'istanza di un oggetto Phaser.Text o PIXI.Text, viene creata una nuova trama su cui eseguire il rendering del testo. Questa texture aggiuntiva interrompe il batching dei vertici, quindi fai attenzione a non averne troppi .

Come assicurarsi che i caratteri personalizzati siano stati caricati

Se si desidera eseguire il rendering del testo con un carattere vettoriale personalizzato (ad es. TTF o OTF), è necessario assicurarsi che il carattere sia già stato caricato dal browser prima di eseguire il rendering di qualsiasi testo. Phaser v2 non fornisce una soluzione per questo scopo, ma è possibile utilizzare un'altra libreria: Web Font Loader.

Supponendo che tu abbia un file di font e includi Web Font Loader nella tua pagina, di seguito è riportato un semplice esempio di come caricare un font:

Crea un semplice file CSS che verrà caricato da Web Font Loader (non è necessario includerlo nel tuo HTML):

 @font-face { // This name you will use in JS font-family: 'Gunplay'; // URL to the font file, can be relative or absolute src: url('../fonts/gunplay.ttf') format('truetype'); font-weight: 400; }

Ora definisci una variabile globale denominata WebFontConfig . Qualcosa di semplice come questo di solito sarà sufficiente:

 var WebFontConfig = { 'classes': false, 'timeout': 0, 'active': function() { // The font has successfully loaded... }, 'custom': { 'families': ['Gunplay'], // URL to the previously mentioned CSS 'urls': ['styles/fonts.css'] } };

Alla fine, ricorda di inserire il tuo codice nella richiamata "attiva" mostrata sopra. E questo è tutto!

Come rendere più facile per gli utenti salvare il gioco

Per archiviare in modo permanente i dati locali in ActionScript, utilizzare la classe SharedObject. In JavaScript, la semplice sostituzione è l'API localStorage, che consente di archiviare le stringhe per un successivo recupero, sopravvivendo ai ricaricamenti della pagina.

Il salvataggio dei dati è molto semplice:

 var progress = 15; localStorage.setItem('myGame.progress', progress);

Si noti che nell'esempio precedente la variabile di progress , che è un numero, verrà convertita in una stringa.

Anche il caricamento è semplice, ma ricorda che i valori recuperati saranno stringhe o null se non esistono.

 var progress = parseInt(localStorage.getItem('myGame.progress')) || 0;

Qui ci assicuriamo che il valore restituito sia un numero. Se non esiste, verrà assegnato 0 alla variabile di progress .

Puoi anche archiviare e recuperare strutture più complesse, ad esempio JSON:

 var stats = {'goals': 13, 'wins': 7, 'losses': 3, 'draws': 1}; localStorage.setItem('myGame.stats', JSON.stringify(stats)); … var stats = JSON.parse(localStorage.getItem('myGame.stats')) || {};

In alcuni casi l'oggetto localStorage non sarà disponibile. Ad esempio, quando si utilizza il protocollo file:// o quando una pagina viene caricata in una finestra privata. Puoi utilizzare l'istruzione try and catch per assicurarti che il tuo codice continui a funzionare e utilizzi i valori predefiniti, come mostrato nell'esempio seguente:

 try { var progress = localStorage.getItem('myGame.progress'); } catch (exception) { // localStorage not available, use default values }

Un'altra cosa da ricordare è che i dati archiviati vengono salvati per dominio, non per URL. Quindi, se c'è il rischio che molti giochi siano ospitati su un singolo dominio, è meglio utilizzare un prefisso (spazio dei nomi) durante il salvataggio. Nell'esempio sopra 'myGame.' è un tale prefisso e di solito vuoi sostituirlo con il nome del gioco.

Nota : se il tuo gioco è incorporato in un iframe, localStorage non persisterà su iOS. In questo caso, dovresti invece archiviare i dati nell'iframe principale .

Come sfruttare la sostituzione dello shader di frammenti predefinito

Quando Phaser e PixiJS eseguono il rendering dei tuoi sprite, usano un semplice shader di frammenti interno. Non ha molte caratteristiche perché è su misura per una velocità. Tuttavia, puoi sostituire quello shader per i tuoi scopi. Ad esempio, puoi sfruttarlo per ispezionare il superamento o supportare più funzionalità per il rendering.

Di seguito è riportato un esempio di come fornire il proprio shader di frammenti predefinito a Phaser v2:

 function preload() { this.load.shader('filename.frag', 'shaders/filename.frag'); } function create() { var renderer = this.renderer; var batch = renderer.spriteBatch; batch.defaultShader = new PIXI.AbstractFilter(this.cache.getShader('filename.frag')); batch.setContext(renderer.gl); }

Nota: è importante ricordare che lo shader predefinito viene utilizzato per TUTTI gli sprite e durante il rendering su una trama. Inoltre, tieni presente che l'utilizzo di shader complessi per tutti gli sprite di gioco ridurrà notevolmente le prestazioni di rendering .

Come modificare il metodo di colorazione con uno shader predefinito

Lo shader predefinito personalizzato può essere utilizzato per sostituire il metodo di colorazione predefinito in Phaser e PixiJS.

La colorazione in Phaser e PixiJS funziona moltiplicando i pixel della trama per un determinato colore. La moltiplicazione scurisce sempre i colori, il che ovviamente non è un problema; è semplicemente diverso dalla colorazione Flash. Per uno dei nostri giochi, dovevamo implementare una colorazione simile a Flash e abbiamo deciso di utilizzare uno shader predefinito personalizzato. Di seguito è riportato un esempio di tale shader di frammenti:

 // Specific tint variant, similar to the Flash tinting that adds // to the color and does not multiply. A negative of a color // must be supplied for this shader to work properly, ie set // sprite.tint to 0 to turn whole sprite to white. precision lowp float; varying vec2 vTextureCoord; varying vec4 vColor; uniform sampler2D uSampler; void main(void) { vec4 f = texture2D(uSampler, vTextureCoord); float a = clamp(vColor.a, 0.00001, 1.0); gl_FragColor.rgb = f.rgb * vColor.a + clamp(1.0 - vColor.rgb/a, 0.0, 1.0) * vColor.a * fa; gl_FragColor.a = fa * vColor.a; }

Questo shader schiarisce i pixel aggiungendo un colore di base a quello della tinta. Affinché funzioni, è necessario fornire il negativo del colore desiderato. Pertanto, per ottenere il bianco, è necessario impostare:

 sprite.tint = 0x000000; // This colors the sprite to white Sprite.tint = 0x00ffff; // This gives red

Il risultato nel nostro gioco è simile al seguente (nota come i carri armati lampeggiano di bianco quando vengono colpiti):

Esempio dello shader predefinito personalizzato nello sviluppo del gioco
Shader predefinito personalizzato (serbatoi lampeggianti in bianco).

Come ispezionare lo scoperto per rilevare problemi di tasso di riempimento

La sostituzione dello shader predefinito può anche essere sfruttata per facilitare il debug. Di seguito ho spiegato come è possibile rilevare l'overdraw con un tale shader.

L'overdrawing si verifica quando molti o tutti i pixel sullo schermo vengono renderizzati più volte. Ad esempio, molti oggetti che occupano lo stesso posto e vengono visualizzati l'uno sull'altro. Quanti pixel può eseguire il rendering di una GPU al secondo è descritto come velocità di riempimento. Le moderne GPU desktop hanno una velocità di riempimento eccessiva per i normali scopi 2D, ma quelle mobili sono molto più lente.

Esiste un metodo semplice per scoprire quante volte viene scritto ogni pixel sullo schermo sostituendo lo shader di frammento globale predefinito in PixiJS e Phaser con questo:

 void main(void) { gl_FragColor.rgb += 1.0 / 7.0; }

Questo shader schiarisce i pixel in fase di elaborazione. Il numero 7.0 indica quante scritture sono necessarie per far diventare bianchi i pixel; puoi sintonizzare questo numero a tuo piacimento. In altre parole, i pixel più chiari sullo schermo sono stati scritti più volte e i pixel bianchi almeno 7 volte.

Questo shader aiuta anche a trovare sia oggetti "invisibili" che per qualche motivo sono ancora renderizzati sia sprite che hanno aree trasparenti eccessive intorno che devono essere rimosse (la GPU deve ancora elaborare pixel trasparenti nelle trame).

Esempio dello shader Overdraw in azione nello sviluppo del gioco
Overdraw shader in azione. (Grande anteprima)

L'immagine a sinistra mostra come un giocatore vede il gioco, mentre quella a destra mostra l'effetto dell'applicazione dello shader di overdraw alla stessa scena.

Perché i motori fisici sono tuoi amici

Un motore fisico è un middleware responsabile della simulazione dei corpi fisici (di solito la dinamica dei corpi rigidi) e delle loro collisioni. I motori fisici simulano spazi 2D o 3D, ma non entrambi. Un tipico motore fisico fornirà:

  • movimento dell'oggetto impostando velocità, accelerazioni, giunti e motori;
  • rilevare le collisioni tra vari tipi di forme;
  • calcolare le risposte alle collisioni, ovvero come dovrebbero reagire due oggetti quando si scontrano.

In Merixstudio, siamo grandi fan del motore fisico Box2D e lo abbiamo utilizzato in alcune occasioni. C'è un plug-in Phaser che funziona bene per questo scopo. Box2D è utilizzato anche nel motore di gioco Unity e GameMaker Studio 2.

Mentre un motore fisico accelererà il tuo sviluppo, c'è un prezzo che dovrai pagare: prestazioni di runtime ridotte. Il rilevamento delle collisioni e il calcolo delle risposte è un'attività ad alta intensità di CPU. Potresti essere limitato a diverse dozzine di oggetti dinamici in una scena su telefoni cellulari o avere prestazioni ridotte, oltre a una frequenza fotogrammi ridotta al di sotto di 60 FPS.

Esempio della differenza nella scena di un gioco con e senza il nostro overlay di debug della fisica Phaser visualizzato in alto
Overlay di debug della fisica di Phaser. (Grande anteprima)

La parte sinistra dell'immagine è una scena di un gioco, mentre il lato destro mostra la stessa scena con un overlay di debug della fisica Phaser visualizzato in alto.

Come esportare suoni da un file .fla

Se disponi di effetti sonori di un gioco Flash all'interno di un file .fla , non è possibile esportarli dalla GUI (almeno non in Adobe Animate CC 2017) a causa della mancanza di opzioni di menu che servono a questo scopo. Ma c'è un'altra soluzione: uno script dedicato che fa proprio questo:

 function normalizeFilename(name) { // Converts a camelCase name to snake_case name return name.replace(/([AZ])/g, '_$1').replace(/^_/, '').toLowerCase(); } function displayPath(path) { // Makes the file path more readable return unescape(path).replace('file:///', '').replace('|', ':'); } fl.outputPanel.clear(); if (fl.getDocumentDOM().library.getSelectedItems().length > 0) // Get only selected items var library = fl.getDocumentDOM().library.getSelectedItems(); else // Get all items var library = fl.getDocumentDOM().library.items; // Ask user for the export destination directory var root = fl.browseForFolderURL('Select a folder.'); var errors = 0; for (var i = 0; i < library.length; i++) { var item = library[i]; if (item.itemType !== 'sound') continue; var path = root + '/'; if (item.originalCompressionType === 'RAW') path += normalizeFilename(item.name.split('.')[0]) + '.wav'; else path += normalizeFilename(item.name); var success = item.exportToFile(path); if (!success) errors += 1; fl.trace(displayPath(path) + ': ' + (success ? 'OK' : 'Error')); } fl.trace(errors + ' error(s)');

Come utilizzare lo script per esportare file audio:

  1. Salva il codice sopra come file .jsfl sul tuo computer;
  2. Apri un file .fla con Adobe Animate;
  3. Seleziona 'Comandi' → 'Esegui comando' dal menu in alto e seleziona lo script nella finestra di dialogo che si apre;
  4. Ora viene visualizzato un altro file di dialogo per selezionare la directory di destinazione dell'esportazione.

E fatto! Ora dovresti avere i file WAV nella directory specificata. Quello che resta da fare è convertirli, ad esempio, in MP3, OGG o AAC.

Come utilizzare gli MP3 nelle conversioni da Flash a HTML5

Il buon vecchio formato MP3 è tornato, poiché alcuni brevetti sono scaduti e ora ogni browser può decodificare e riprodurre MP3. Questo rende lo sviluppo un po' più semplice poiché finalmente non c'è bisogno di preparare due formati audio separati. In precedenza servivano, ad esempio, file OGG e AAC, mentre ora MP3 sarà sufficiente.

Tuttavia, ci sono due cose importanti che devi ricordare su MP3:

  • La necessità di decodificare gli MP3 dopo il caricamento, cosa che può richiedere molto tempo, specialmente sui dispositivi mobili. Se vedi una pausa dopo che tutte le tue risorse sono state caricate, probabilmente significa che l'MP3 è in fase di decodifica;
  • riprodurre senza interruzioni MP3 in loop è un po' problematico. La soluzione è usare mp3loop, di cui puoi leggere nell'articolo pubblicato da Compu Phase.

Quindi, perché dovresti convertire Flash in JavaScript?

Come puoi vedere, la conversione da Flash a JavaScript non è impossibile se sai cosa fare. Con conoscenza e abilità, puoi smettere di lottare con Flash e goderti i giochi fluidi e divertenti creati in JavaScript. Non cercare di riparare Flash: sbarazzati di esso prima che tutti siano costretti a farlo!

Vuoi saperne di più?

In questo articolo, mi sono concentrato principalmente su Phaser v2. Tuttavia, è ora disponibile una versione più recente di Phaser e ti consiglio vivamente di provarla, poiché ha introdotto una miriade di funzionalità fresche e interessanti, come telecamere multiple, scene, tilemap o motore fisico Matter.js.

Se sei abbastanza coraggioso e vuoi creare cose davvero straordinarie nei browser, WebGL è la cosa giusta da imparare da zero. È un livello di astrazione inferiore rispetto a vari framework o strumenti per la creazione di giochi, ma consente di ottenere prestazioni e qualità maggiori anche se si lavora su giochi o demo 2D. Tra i molti siti Web che potresti trovare utili quando impari le basi di WebGL ci sono WebGL Fundamentals (utilizza demo interattive). Inoltre, per saperne di più sui tassi di adozione delle funzionalità WebGL, controlla le statistiche WebGL.

Ricorda sempre che non esiste troppa conoscenza, specialmente quando si tratta di sviluppo di giochi!