Due volte al mese, rivisitiamo alcuni dei post preferiti dei nostri lettori da tutta la storia di Activetuts +. Questo tutorial è stato pubblicato per la prima volta nell'ottobre 2009 (e ha portato il mio invitando Michael ad essere Activetuts + Tech Editor!)
Questa è una tecnica davvero semplice che puoi usare per aggiungere l'illusione della profondità a qualsiasi gioco di esplorazione laterale. Mentre sto spiegando come è stato realizzato, daremo anche un'occhiata a sfondi che si ripetono all'infinito.
Puoi vedere la base scorrimento di parallasse effetto al lavoro nella demo. Regolando le velocità a cui alcuni oggetti scorrono, possiamo cambiare quanto vicino o lontano sembrano essere.
Questo tutorial spiegherà come codificare l'effetto e come far apparire la macchina fotografica del gioco per seguire l'auto. Infine, ti spiegherà come creare sfondi a ripetizione infinita, proprio come in Scooby Doo.
Se si utilizza Flash, creare un nuovo file Flash ActionScript 3.0. Imposta la dimensione del palco come vuoi; Ho scelto il predefinito 550 per 400 pixel.
Se non stai utilizzando l'IDE Flash, non preoccuparti; basta creare un nuovo progetto AS3. Il file zip contiene un SWC con tutti i miei elementi grafici, quindi puoi usarli semplicemente aggiungendolo alla tua libreria. Salta tutti i passaggi del disegno se lo fai.
Se tu siamo usando l'IDE Flash ma non vuoi disegnare nulla, lo zip contiene anche un file FLA contenente tutti i miei MovieClip :)
Crea un nuovo simbolo MovieClip e disegna una macchina. Puoi animarlo se vuoi. Ecco il mio:
Prova a centrare la macchina in modo che il suo punto di registrazione (la piccola croce) sia circa a metà strada. In questo modo sarà più facile per la telecamera seguirla in seguito.
Fai clic con il tasto destro del mouse sul simbolo dell'auto nella libreria e seleziona Proprietà:
Dai alla tua auto una classe (Auto farà) e controllare il Esporta per ActionScript box (questo ci permette di accedere alla macchina usando il codice). Inoltre, controlla il Esporta nel primo fotogramma box (altrimenti, dovremo fare un preloader).
Crea un altro nuovo simbolo, ma questa volta traccia una strada:
Rendilo più largo del palco, ma a differenza della macchina, allinea il punto di registrazione con il bordo sinistro della strada. Questo ti aiuterà in seguito, quando avremo bisogno di trasformarlo in uno schema ripetitivo.
Proprio come hai fatto per la macchina, dai alla strada una classe, esportala per ActionScript ed esportala nel primo fotogramma.
Creare un nuovo file AS e incollarvi il seguente codice:
package import flash.display.MovieClip; public class ParallaxDemo estende MovieClip public function ParallaxDemo ()
Salva questo come ParallaxDemo.as, nella stessa cartella del FLA (o come progetto, se non si utilizza l'IDE).
Se si utilizza l'IDE, assicurarsi di impostarlo come classe del documento nel pannello Proprietà del documento:
Non sei sicuro di quello che stiamo facendo qui? Dai un'occhiata al mio suggerimento rapido sull'uso di una classe di documenti.
Crea nuove istanze della tua auto e strada nel file AS: (righe 6, 7, 11, 12)
package import flash.display.MovieClip; public class ParallaxDemo estende MovieClip public var car: Car; strada pubblica: Strada; funzione pubblica ParallaxDemo () car = new Car (); strada = nuova strada ();
Se stai usando la mia grafica, puoi semplicemente copiare il seguente codice (righe 14-17):
package import flash.display.MovieClip; public class ParallaxDemo estende MovieClip public var car: Car; strada pubblica: Strada; funzione pubblica ParallaxDemo () car = new Car (); strada = nuova strada (); car.x = 275,0; car.y = 235.0; road.x = 0.0; road.y = 294.0;
Altrimenti, dovrai capire dove dovranno essere posizionate la macchina e la strada all'inizio. Crea un nuovo livello nella timeline del tuo FLA, quindi trasformalo in un livello guida facendo clic con il pulsante destro del mouse e selezionando Guida. Flash ignorerà tutto ciò che fai in questo livello quando crea un file SWF, quindi trascina qui i simboli della tua auto e della tua strada.
Assicurati che il bordo sinistro della tua strada sia allineato con il bordo sinistro del palco e che l'auto sia all'incirca al centro (in orizzontale). Quindi regolale in modo che si adattino:
Ora prendi il mio codice da sopra e regolalo in modo che corrisponda alle coordinate x e y della tua auto e strada. Cliccando sulla tua auto o su strada, sarai in grado di vedere questi valori nel pannello Proprietà.
Se metti alla prova il tuo film ora, non vedrai nulla. Abbiamo bisogno di aggiungereChild () l'auto e la strada al palco:
funzione pubblica ParallaxDemo () car = new Car (); strada = nuova strada (); car.x = 275,0; car.y = 235.0; road.x = 0.0; road.y = 294.0; stage.addChild (strada); stage.addChild (car);
(Assicurati di aggiungere prima la strada, o coprirà la macchina!)
Metti alla prova il tuo film ora, e dovrebbe assomigliare a questo:
Grande! Bene, OK, non è ancora niente di spettacolare. Ma ora che l'installazione è fuori mano, possiamo renderlo più interessante. Per cominciare, facciamo muovere questa macchina?
Modifica la classe del documento per aggiungere un listener di eventi da attivare su ciascun frame: (righe 4, 23, 26-29)
package import flash.display.MovieClip; import flash.events.Event; public class ParallaxDemo estende MovieClip public var car: Car; strada pubblica: Strada; funzione pubblica ParallaxDemo () car = new Car (); strada = nuova strada (); car.x = 275,0; car.y = 235.0; road.x = 0.0; road.y = 294.0; stage.addChild (strada); stage.addChild (car); addEventListener (Event.ENTER_FRAME, onEnterFrame); public function onEnterFrame (evt: Event): void
Se hai mantenuto il frame rate predefinito di 12 fps, la funzione onEnterFrame () verrà chiamata ogni 1 / 12th di secondo.
Se continuiamo ad aumentare la posizione x dell'auto?
funzione pubblica onEnterFrame (evt: Event): void car.x = car.x + 10; // se sei pronto per una sfida, prova ad aggiungere comandi di tastiera // di base per consentire al giocatore di accelerare // e decelerare.
? possiamo far muovere la macchina in avanti?
? proprio fuori dal bordo dello schermo!
Questo non è l'ideale; dopo pochi secondi non possiamo più vedere la macchina. Facciamo in modo che la "macchina fotografica" appaia per seguire la macchina.
Cosa significa esattamente questo? Beh, fondamentalmente abbiamo bisogno che l'auto rimanga nello stesso posto, mentre la strada sembra muoversi all'indietro.
Ciò significa che noi poteva fare qualcosa del genere:
public function onEnterFrame (evt: Event): void road.x = road.x - 10;
? ma questo complicherebbe le cose dopo. Per esempio, immagina se volessimo aggiungere altre auto alla strada, o potenziamenti, o chiazze di petrolio, o qualcosa del genere; dovremmo spostare ognuno di essi all'indietro nella funzione onEnterFrame ().
No, c'è una tecnica molto più semplice che possiamo usare. Invece di addChild () - l'auto e la strada verso il palco, creiamo un nuovo oggetto, addChild () a questo, e poi spostiamo Questo oggetto all'indietro nella funzione onEnterFrame ().
Sembra più complicato di quello che è. Lascia che ti mostri il codice attuale:
package import flash.display.MovieClip; import flash.events.Event; public class ParallaxDemo estende MovieClip public var car: Car; strada pubblica: Strada; public var roadContainer: MovieClip; funzione pubblica ParallaxDemo () car = new Car (); strada = nuova strada (); car.x = 275,0; car.y = 235.0; road.x = 0.0; road.y = 294.0; roadContainer = new MovieClip (); roadContainer.addChild (strada); roadContainer.addChild (auto); stage.addChild (roadContainer); addEventListener (Event.ENTER_FRAME, onEnterFrame); public function onEnterFrame (evt: Event): void car.x = car.x + 10; roadContainer.x = roadContainer.x - 10;
Nel righe 9 e 21 creiamo un nuovo MovieClip vuoto chiamato roadContainer. Flash imposta automaticamente i valori xey su 0.
Nel righe 22 e 23 aggiungiamo la strada e l'auto al RoadContainer, invece del palco. Nel riga 25 aggiungiamo il roadContainer al palcoscenico - e poiché l'auto e la strada sono ora aggiunti al roadContainer, questo ci permette di vederli sul palco.
Linea 32 è la parte più importante. Qui, spostiamo il roadContainer indietro dello stesso importo che abbiamo appena spostato l'auto in avanti. Ciò significa che tutto ciò che si trova all'interno di roadContainer viene spostato a sinistra di 10 pixel, ma poiché l'auto è stata appena spostata di 10 pixel a destra, rimane al centro dello schermo.
È un po 'come correre su per la scala mobile. Se cammini alla stessa velocità in cui si muove verso il basso, quindi a una persona in piedi sulle scale accanto a te, non sembra che ti stia muovendo.
L'effetto complessivo:
L'auto rimane al centro! Grande. Bene, fantastico a parte il buco bianco spalancato. Ma ci arriveremo. Ora, se vuoi aggiungere più auto sulla strada, tutto ciò che devi fare è aggiungereChild () a RoadContainer.
Il problema con il semplice spostamento di tutto il contenitore all'indietro di un fotogramma è che non è molto flessibile. Cosa succede se il giocatore utilizza un powerup per teletrasportare l'auto di 100 pixel anziché 10? E se volessimo mettere la fotocamera al centro di una macchina diversa?
Quando il SWF viene caricato per la prima volta, la posizione x dell'auto è 275 e la posizione x del roadContainer è 0. Come cambiano nel tempo?
Vedi una regola generale che collega i due? In caso contrario, controlla questo:
La connessione è un po 'più ovvia ora! Mettiamolo nel codice:
funzione pubblica onEnterFrame (evt: Event): void car.x = car.x + 10; roadContainer.x = 275 - car.x;
Puoi fare quello che ti piace con la macchina ora. Acceleralo, teletrasportalo in avanti di un numero casuale di pixel, smettila di spostarlo - qualunque cosa! La fotocamera continuerà a seguirlo.
E se vuoi che la fotocamera segua un oggetto diverso, sostituiscilo car.x con otherObject.x nella linea abbiamo appena cambiato.
È ora di fissare l'infinito vuoto bianco del nulla alla fine della strada.
Il modo più semplice per rendere la strada più lunga è semplicemente aggiungere un'altra istanza del simbolo della strada alla destra del nostro simbolo esistente, in questo modo: (righe 9, 22, 23, 27)
package import flash.display.MovieClip; import flash.events.Event; public class ParallaxDemo estende MovieClip public var car: Car; strada pubblica: Strada; public var road2: Road; public var roadContainer: MovieClip; funzione pubblica ParallaxDemo () car = new Car (); strada = nuova strada (); road2 = new Road (); car.x = 275,0; car.y = 235.0; road.x = 0.0; road.y = 294.0; road2.x = road.x + road.width; road2.y = road.y; roadContainer = new MovieClip (); roadContainer.addChild (strada); roadContainer.addChild (road2); roadContainer.addChild (auto); stage.addChild (roadContainer); addEventListener (Event.ENTER_FRAME, onEnterFrame); public function onEnterFrame (evt: Event): void car.x = car.x + 10; roadContainer.x = 275 - car.x;
Ecco come appare il mio quando viene eseguito:
Oh caro. Meglio aggiustare il divario.
(Se non stai disegnando la tua grafica, vai al passaggio 17.)
Il problema è nella riga 22 del codice precedente, road2.x = road.x + road.width. Le strade larghezza il valore deve essere leggermente più grande di quanto la mia strada sembra essere.
Anche se la tua strada non ha lo stesso problema, potrebbe comunque non combaciare perfettamente. Quindi torna al tuo FLA e trascina un altro simbolo Road dalla libreria al tuo livello Guide.
Assicurati che abbia la stessa posizione y del primo segmento stradale, quindi spostalo orizzontalmente fino a quando non ci sono spazi vuoti:
Se i bordi dei due simboli non si uniscono perfettamente, fai doppio clic su uno di essi. Sarai in grado di modificarlo e vedere immediatamente come le modifiche apportate influenzano l'altra:
Usa questo trucco per regolare i bordi del simbolo in modo che l'unione sia pulita.
Invece di usare road.width per capire dove dovrebbe essere posizionato il secondo segmento stradale, useremo un numero che chiamo il ampiezza.
Per trovare questo numero per la tua strada, basta prendere la posizione x del simbolo della strada più a destra (nel livello Guide) e sottrarre la posizione x del simbolo della strada più a sinistra.
Tutto quello che stai facendo qui è capire quanti pixel devono essere i tuoi due segmenti stradali per ottenere lo stesso join perfetto che hai appena creato in Flash.
Crea una nuova variabile Numero, roadBreadth, e imposta il suo valore sul numero che hai elaborato nel passaggio precedente: (Se stai usando la mia grafica, quel numero è 653.7).
public class ParallaxDemo estende MovieClip public var car: Car; strada pubblica: Strada; public var road2: Road; public var roadContainer: MovieClip; public var roadBreadth: Number; funzione pubblica ParallaxDemo () car = new Car (); strada = nuova strada (); road2 = new Road (); roadBreadth = 653,7;
Sostituisci la linea:
road2.x = road.x + road.width;
con:
road2.x = road.x + roadBreadth;
Ora provalo. Non ci dovrebbe essere spazio vuoto:
Grande! Corriamo ancora nell'infinito vuoto bianco, però?
Potremmo creare un road3 e un road4 e un road5 e così via, posizionandoli ciascuno a destra di quello che li precede, ma non importa quanti segmenti abbiamo creato, l'auto sarebbe arrivata alla fine di essi.
Per una soluzione migliore, ripensa a quando eri un bambino. Hai mai giocato a quel gioco in cui fingi che il pavimento sia fatto di lava, ma in qualche modo devi andare dall'altra parte della stanza? (Se no, diamine, vai a giocare ora, è molto divertente.)
Non so voi, ma a casa mia i cuscini del divano erano considerati resistenti alla lava, in grado di essere usati come pietre da passeggio. Avevamo solo un paio, che non era abbastanza per raggiungere la fine della stanza - ma alla fine ho capito come farli arrivare oltre.
Metterei giù i due cuscini per fare un breve sentiero e andare verso il secondo. Poi, raccoglierei quello dietro di me, lascialo cadere davanti a me e vieni verso di esso. Raccogliendo ripetutamente quello dietro di me e spostandolo di fronte a me, potevo arrivare ovunque mi piacesse.
Possiamo usare la stessa tecnica per rendere la strada dura per sempre, senza dover utilizzare più di due segmenti. Tutto quello che dobbiamo fare è rilevare quando un segmento stradale è "dietro" alla telecamera e spostarlo di fronte ad esso.
Cosa intendo per "dietro" la fotocamera? Intendo dire che il margine destro del segmento è fuori dal bordo sinistro del palco. Possiamo usare questa dichiarazione if per verificare che:
if (road.x + roadBreadth + roadContainer.x < 0 ) //road is behind the camera
Curioso sul perché questo funziona? In caso contrario, passa al passaggio successivo. Altrimenti, lasciami spiegare:
Accidenti! OK, lo ammetto, è abbastanza confuso. Se desideri una spiegazione più approfondita, non esitare a chiedere nei commenti :)
Ora che possiamo capire quando il segmento stradale è dietro la telecamera, dobbiamo spostarlo di nuovo davanti alla videocamera.
Se spostassimo la strada a destra roadBreadth numero di pixel, sarebbe nello stesso identico posto dell'altro segmento stradale. Quindi, dobbiamo spostarlo verso destra di una quantità doppia di:
if (road.x + roadBreadth + roadContainer.x < 0 ) road.x = road.x + (2 * roadBreadth);
Metti questo nella tua funzione onEnterFrame () e provalo:
Come puoi vedere, un segmento stradale si sta ripetendo, ma l'altro non lo è ancora.
Possiamo solo copiare il codice sopra per il nostro altro segmento stradale, road2:
public function onEnterFrame (evt: Event): void car.x = car.x + 25; roadContainer.x = 275 - car.x; if (road.x + roadBreadth + roadContainer.x < 0 ) road.x = road.x + (2 * roadBreadth); if ( road2.x + roadBreadth + roadContainer.x < 0 ) road2.x = road2.x + (2 * roadBreadth);
Provalo di nuovo:
Fantastico! Uno sfondo a scorrimento continuo a scorrimento laterale :) Ora per creare l'effettivo effetto di parallasse?
(Salta questo passaggio se stai usando la mia grafica.)
Avremo bisogno di uno sfondo ripetuto per mostrare lo scorrimento della parallasse. Ho scelto le colline, ma potresti costruire edifici, foreste, sculture aliene - qualsiasi cosa ti piaccia!
Ci sono alcuni trucchi che puoi usare per rendere quello che disegni sembra essere più lontano della macchina:
Segui gli stessi passi base che abbiamo usato per disegnare la strada:
Ecco il mio:
Il codice relativo alle colline è quasi identico al codice che abbiamo appena scritto riguardo alle strade. Prova a scriverlo da solo. Ho incollato il mio file AS con tutte le nuove aggiunte di seguito, quindi puoi fare riferimento ad esso se ti piace:
package import flash.display.MovieClip; import flash.events.Event; public class ParallaxDemo estende MovieClip public var car: Car; strada pubblica: Strada; public var road2: Road; public var roadContainer: MovieClip; public var roadBreadth: Number; public var hills: Hills; public var hills2: Hills; public var hillsBreadth: Number; public var hillsContainer: MovieClip; funzione pubblica ParallaxDemo () car = new Car (); strada = nuova strada (); road2 = new Road (); roadBreadth = 653,7; hills = new Hills (); hills2 = new Hills (); hillsBreadth = 890,5; car.x = 275,0; car.y = 235.0; road.x = 0.0; road.y = 294.0; road2.x = road.x + roadBreadth; road2.y = road.y; hills.x = 0; hills.y = 14,5; hills2.x = hills.x + hillsBreadth; hills2.y = hills.y; roadContainer = new MovieClip (); roadContainer.addChild (strada); roadContainer.addChild (road2); roadContainer.addChild (auto); hillsContainer = new MovieClip (); hillsContainer.addChild (hills); hillsContainer.addChild (hills2); stage.addChild (hillsContainer); stage.addChild (roadContainer); addEventListener (Event.ENTER_FRAME, onEnterFrame); public function onEnterFrame (evt: Event): void car.x = car.x + 10; roadContainer.x = 275 - car.x; if (road.x + roadBreadth + roadContainer.x < 0 ) road.x = road.x + (2 * roadBreadth); if ( road2.x + roadBreadth + roadContainer.x < 0 ) road2.x = road2.x + (2 * roadBreadth); hillsContainer.x = 275 - car.x; if ( hills.x + hillsBreadth + hillsContainer.x < 0 ) hills.x = hills.x + (2 * hillsBreadth); if ( hills2.x + hillsBreadth + hillsContainer.x < 0 ) hills2.x = hills2.x + (2 * hillsBreadth);
(Le nuove linee sono 12-15, 24-26, 35-38, 45-47, 49 e 67-75. Come hai fatto?)
Ecco il risultato:
Ti starai chiedendo perché mi sono preso la briga di creare un hillsContainer. Se è così, allora ben chiazzato! Potremmo semplicemente aggiungereChild () le colline a roadContainer - ma creare un nuovo contenitore per lo sfondo è ciò che ci permette di creare l'effettivo effetto di parallasse.
L'effetto richiede solo la modifica di una riga di codice:
hillsContainer.x = 275 - car.x;
in questo:
hillsContainer.x = (275 - car.x) * 1/5;
Ciò fa scorrere le colline ad 1/5 della velocità della strada e dell'auto.
Sembra questo:
Non devi usare 1/5; rendere questo valore più grande o più piccolo fino a quando la velocità ti sembra giusta.
Perché funziona? Bene, ricorda che vediamo le cose in a cono di visione; più lontano c'è qualcosa di più che possiamo vedere. Quindi se passiamo accanto a due oggetti della stessa dimensione, ma uno è più lontano, il più vicino dei due sembrerà muoversi più velocemente, in questo modo:
Aggiungiamo un altro livello di sfondo, anche più lontano delle colline.
Questo è esattamente lo stesso come creare la strada e le colline, quindi non ho intenzione di incollare il codice questa volta! Tutto quello che farò è pubblicare una foto delle mie montagne?
? ti dico che l'ampiezza delle mie montagne è 751,5, x è 0 e y è 63,0; ricordati di creare un nuovo MountainContainer MovieClip; e ti faccio sapere che le mie montagne scorrono ad 1/16 della velocità della mia strada.
Oh, e mostraci il risultato:
Il cielo è bello e facile. Dal momento che è molto lontano, scorre così lentamente che sembra quasi che stia scorrendo a malapena. Nuvole e uccelli si muovono, naturalmente, e il Sole sorge e tramonta, ma nulla di tutto ciò è dovuto a un effetto di scorrimento della parallasse. Questo significa che non dobbiamo fare nulla nello scroll del cielo!
(L'eccezione a questo è se la telecamera viaggia davvero, veramente veloce, come la velocità di un aereo o di un razzo. Anche in questo caso, assicurati di farlo scorrere molto lentamente.)
Quindi, non c'è bisogno di preoccuparsi di larghezza qui, o di creare un'immagine ripetuta all'infinito. È comunque una buona idea creare un skyContainer, solo per mantenere le cose coerenti. Il mio cielo è solo un rettangolo blu:
Se lo metti a x = 0, y = 0 coprirà l'intero livello. Ecco come appare nel file SWF:
Abbiamo creato molti oggetti di sfondo, ma niente più vicino alla macchina della macchina. Come sono sicuro ti rendi conto, un tale oggetto dovrebbe scorrere Più veloce di roadContainer, proviamo a farlo.
Per il mio oggetto in primo piano, ho disegnato un albero:
L'albero è un po 'diverso dagli altri oggetti che abbiamo creato fino a questo momento perché non è stato creato in loop: si trova da solo, non si unirà a un altro albero accanto. Ciò significa che abbiamo sempre e solo bisogno di un albero sullo schermo in qualsiasi momento (soprattutto perché è così grande!)
Quindi abbiamo solo bisogno di un oggetto Tree nel codice. Scrivi il codice per questo oggetto. Se stai usando la mia grafica, la posizione iniziale di x sarà 780.0 e la posizione y sarà 175.0.
Poiché l'albero scorrerà, abbiamo ancora bisogno di un treeContainer e abbiamo ancora bisogno di un alberoBreadth. Tuttavia, questa volta, treeBreadth controlla solo il numero di pixel tra ogni albero. Ho usato un bel round 1000.0 per il mio.
Poiché esiste un solo albero, il codice a scorrimento è molto più semplice:
treeContainer.x = (275 - car.x) * 3; if (tree.x + treeBreadth + treeContainer.x < 0 ) tree.x = tree.x + (2 * treeBreadth);
Niente di complicato :) Basta notare che scorre tre volte Più veloce rispetto alla strada. Questo è il risultato finale:
Congratulazioni! Hai creato una fotocamera a scorrimento dinamico, sfondi infinitamente ripetuti e un effetto di parallasse pseudo-3D :)
Ecco alcune altre cose che puoi fare con lo stesso codice:
Se stai creando una sparatoria e desideri che tutte le tue esplosioni appaiano più vicine alla tua macchina dei tuoi nemici, crea semplicemente una nuova esplosioneContenitore, aggiungiChiamata () qualsiasi esplosione a quella, e fallo scorrere verso il basso stessa velocità del contenitore nemici.
Metti in gioco il punteggio del giocatore, le loro vite, i pulsanti mute e pause e tutte le altre parti dell'interfaccia del gioco in un unico contenitore. Posiziona questo contenitore davanti a tutti gli altri contenitori, ma non farlo scorrere. Questo è un modo semplice per tenere la videocamera e le risorse di un gioco separate dalla sua interfaccia.
Prova a tenere fermo un contenitore mentre fai i contenitori davanti e dietro di esso scorri in direzioni opposte. Questo crea un fantastico effetto di rotazione, come si vede circa cinque minuti in questa clip da Disney Snow White!
Grazie per aver letto questo tutorial; Spero ti sia piaciuto. Se qualcosa non è chiaro, o se vuoi fare qualche domanda sull'effetto, per favore pubblica un commento qui sotto.
A proposito di commenti, se crei qualcosa usando questo tutorial, mi piacerebbe se tu pubblicassi un link in modo da poterlo vedere :)