Añade profundidad a tu juego con el desplazamiento de paralaje
Spanish (Español) translation by Manuel (you can also view the original English article)
Dos veces al mes, revisamos algunas de las publicaciones favoritas de nuestros lectores a lo largo de la historia de Activetuts+. Este tutorial se publicó por primera vez en octubre de 2009 (y me llevó a invitar a Michael a ser el editor técnico de Activetuts+).
Se trata de una técnica muy sencilla que puedes utilizar para añadir la ilusión de profundidad a cualquier juego de desplazamiento lateral. Mientras explico cómo se consigue, también echaremos un vistazo a la creación de fondos que se repiten infinitamente.
Introducción
En la demostración se puede ver el efecto básico de desplazamiento de paralaje. Ajustando la velocidad a la que se desplazan ciertos objetos, podemos cambiar lo cerca o lo lejos que parecen estar.
Este tutorial explicará cómo codificar el efecto, así como cómo hacer que la cámara del juego parezca seguir al coche. Por último, se explicará cómo crear fondos que se repiten infinitamente, como en Scooby Doo.
Paso 1: La configuración
Si usas Flash, crea un nuevo archivo de ActionScript 3.0 Flash. Configura el tamaño del escenario como quieras; yo he elegido el predeterminado de 550 por 400 píxeles.
Si no estás usando el IDE de Flash, no te preocupes; simplemente crea un nuevo proyecto AS3. El archivo zip contiene un SWC con todos mis gráficos, así que puedes utilizarlos simplemente añadiéndolos a tu biblioteca. Si lo haces, sáltate todos los pasos de dibujo.
Si estás usando el IDE de Flash pero no quieres dibujar nada, el zip también contiene un archivo FLA que contiene todos mis MovieClips :)
Paso 2: Dibujar un auto
Crea un nuevo símbolo MovieClip y dibuja un coche. Puedes animarlo si quieres. Aquí está el mío:

Intenta centrar el coche de forma que su punto de registro (la pequeña cruz) esté más o menos a la mitad. Esto facilitará el seguimiento posterior por parte de la cámara.
Paso 3: Exporta tu auto para ActionScript
Haz clic derecho en el símbolo del auto en la Biblioteca y seleccione Propiedades:

Dale a tu auto una Clase (Car servirá) y marca la casilla Exportar para ActionScript (esto nos permite acceder al auto usando código). Además, marca la casilla Exportar en el primer fotograma (de lo contrario, tendremos que hacer un precargador).
Paso 4: Dibuja una carretera
Crea otro símbolo nuevo, pero esta vez dibuja una carretera:

Hazlo más ancho que el escenario, pero a diferencia del auto, alinea el punto de registro con el borde izquierdo de la carretera. Esto ayudará más adelante, cuando tengamos que convertirlo en un patrón repetitivo.
Al igual que hiciste con el auto, dale una clase a la carretera, expórtala para ActionScript y expórtala en el primer cuadro.
Paso 5: Crear la clase de documento
Crea un nuevo archivo AS y pega en él el siguiente código:
1 |
package |
2 |
{
|
3 |
import flash.display.MovieClip; |
4 |
public class ParallaxDemo extends MovieClip |
5 |
{
|
6 |
public function ParallaxDemo() |
7 |
{
|
8 |
|
9 |
} |
10 |
} |
11 |
} |
Guarda esto como ParallaxDemo.as, en la misma carpeta que tu FLA (o como tu proyecto, si no estás usando el IDE).
Si estás usando el IDE, asegúrete de establecer esto como tu clase de documento en el Panel de Propiedades de tu documento:

¿No estás seguro de lo que estamos haciendo aquí? Consulta mi consejo rápido sobre el uso de una clase de documento.
Paso 6: Preparar el auto y la carretera
Crea nuevas instancias de tu auto y carretera en el archivo AS: (líneas 6, 7, 11, 12)
1 |
package |
2 |
{
|
3 |
import flash.display.MovieClip; |
4 |
public class ParallaxDemo extends MovieClip |
5 |
{
|
6 |
public var car:Car; |
7 |
public var road:Road; |
8 |
|
9 |
public function ParallaxDemo() |
10 |
{
|
11 |
car = new Car(); |
12 |
road = new Road(); |
13 |
} |
14 |
} |
15 |
} |
Paso 7: Colocar el auto y la carretera
Si estás usando mis gráficos, puedes simplemente copiar el siguiente código (líneas 14-17):
1 |
package |
2 |
{
|
3 |
import flash.display.MovieClip; |
4 |
public class ParallaxDemo extends MovieClip |
5 |
{
|
6 |
public var car:Car; |
7 |
public var road:Road; |
8 |
|
9 |
public function ParallaxDemo() |
10 |
{
|
11 |
car = new Car(); |
12 |
road = new Road(); |
13 |
|
14 |
car.x = 275.0; |
15 |
car.y = 235.0; |
16 |
road.x = 0.0; |
17 |
road.y = 294.0; |
18 |
} |
19 |
} |
20 |
} |
De lo contrario, tendrás que averiguar dónde deben colocarse el auto y la carretera al principio. Crea una nueva capa en la línea de tiempo de tu FLA, y luego conviértela en una capa guía haciendo clic derecho y seleccionando Guía. Flash ignorará cualquier cosa que hagas en esta capa cuando cree un SWF, así que arrastra tus símbolos de auto y carretera aquí.
Asegúrate de que el borde izquierdo de tu carretera está alineado con el borde izquierdo del escenario, y que el auto está más o menos en el centro (horizontalmente). A continuación, ajústalos para que encajen:

Ahora toma mi código de arriba y ajústalo para que coincida con las coordenadas x e y de tu auto y carretera. Haciendo clic en tu auto o carretera, podrás ver estos valores en el panel de Propiedades.
Paso 8: Añade tus símbolos al escenario
Si pruebas tu película ahora, no verás nada. Tenemos que addChild() el auto y la carretera al escenario:
1 |
public function ParallaxDemo() |
2 |
{
|
3 |
car = new Car(); |
4 |
road = new Road(); |
5 |
|
6 |
car.x = 275.0; |
7 |
car.y = 235.0; |
8 |
road.x = 0.0; |
9 |
road.y = 294.0; |
10 |
|
11 |
stage.addChild( road ); |
12 |
stage.addChild( car ); |
13 |
} |
(Asegúrate de añadir primero la carretera, ¡o cubrirá el auto!)
Prueba tu película ahora, y debería tener este aspecto:
¡Genial! Bueno, ok, no es nada espectacular todavía. Pero ahora la configuración está fuera del camino, podemos hacer esto más interesante. Para empezar, pongamos este auto en movimiento...
Paso 9: Añadir un receptor de eventos ENTER_FRAME
Modifica tu clase de documento para añadir un receptor de eventos que se active en cada fotograma: (líneas 4, 23, 26-29)
1 |
package |
2 |
{
|
3 |
import flash.display.MovieClip; |
4 |
import flash.events.Event; |
5 |
public class ParallaxDemo extends MovieClip |
6 |
{
|
7 |
public var car:Car; |
8 |
public var road:Road; |
9 |
|
10 |
public function ParallaxDemo() |
11 |
{
|
12 |
car = new Car(); |
13 |
road = new Road(); |
14 |
|
15 |
car.x = 275.0; |
16 |
car.y = 235.0; |
17 |
road.x = 0.0; |
18 |
road.y = 294.0; |
19 |
|
20 |
stage.addChild( road ); |
21 |
stage.addChild( car ); |
22 |
|
23 |
addEventListener( Event.ENTER_FRAME, onEnterFrame ); |
24 |
} |
25 |
|
26 |
public function onEnterFrame( evt:Event ):void |
27 |
{
|
28 |
|
29 |
} |
30 |
} |
31 |
} |
Si mantienes la velocidad de fotogramas por defecto de 12fps, la función onEnterFrame() será llamada cada 1/12 de segundo.
Paso 10: ¡Mueve el auto!
Si seguimos aumentando la posición x del auto...
1 |
public function onEnterFrame( evt:Event ):void |
2 |
{
|
3 |
car.x = car.x + 10; |
4 |
//if you're up for a challenge, try adding basic |
5 |
//keyboard controls to let the player accelerate |
6 |
//and decelerate. |
7 |
} |
...podemos hacer que el auto se mueva hacia adelante...

...¡justo en el borde de la pantalla!
Paso 11: ¡Sigue a ese auto!
Esto no es lo ideal; después de unos segundos ya no podemos ver el auto. Así que hagamos que la "cámara" parezca seguir al auto.
¿Qué significa esto exactamente? Bueno, básicamente necesitamos que el auto permanezca en el mismo lugar, mientras que la carretera parece moverse hacia atrás.
Eso significa que podríamos hacer algo así:
1 |
public function onEnterFrame( evt:Event ):void |
2 |
{
|
3 |
road.x = road.x - 10; |
4 |
} |
...pero esto solo complicaría las cosas más adelante. Por ejemplo, imagina que quisiéramos añadir otros autos al camino, o potenciadores, o manchas de aceite, o cualquier cosa; tendríamos que mover cada uno de ellos hacia atrás en la función onEnterFrame().
No, hay una técnica mucho más sencilla que podemos utilizar. En lugar de añadir el auto y la carretera al escenario, creamos un nuevo objeto, le añadimos el auto y la carretera, y luego movemos este objeto hacia atrás en la función onEnterFrame().
Parece más complicado de lo que es. Déjame mostrarte el código real:
1 |
package |
2 |
{
|
3 |
import flash.display.MovieClip; |
4 |
import flash.events.Event; |
5 |
public class ParallaxDemo extends MovieClip |
6 |
{
|
7 |
public var car:Car; |
8 |
public var road:Road; |
9 |
public var roadContainer:MovieClip; |
10 |
|
11 |
public function ParallaxDemo() |
12 |
{
|
13 |
car = new Car(); |
14 |
road = new Road(); |
15 |
|
16 |
car.x = 275.0; |
17 |
car.y = 235.0; |
18 |
road.x = 0.0; |
19 |
road.y = 294.0; |
20 |
|
21 |
roadContainer = new MovieClip(); |
22 |
roadContainer.addChild( road ); |
23 |
roadContainer.addChild( car ); |
24 |
|
25 |
stage.addChild( roadContainer ); |
26 |
addEventListener( Event.ENTER_FRAME, onEnterFrame ); |
27 |
} |
28 |
|
29 |
public function onEnterFrame( evt:Event ):void |
30 |
{
|
31 |
car.x = car.x + 10; |
32 |
roadContainer.x = roadContainer.x - 10; |
33 |
} |
34 |
} |
35 |
} |
En las líneas 9 y 21 creamos un nuevo MovieClip en blanco llamado roadContainer. Flash establece automáticamente sus valores x e y a 0.
En las líneas 22 y 23 añadimos la carretera y el auto al roadContainer, en lugar de al escenario. En la línea 25 añadimos el propio roadContainer al escenario - y como el auto y la carretera están ahora añadidos al roadContainer, esto nos permite verlos en el escenario.
La línea 32 es la parte más importante. Aquí, movemos el roadContainer hacia atrás en la misma cantidad que acabamos de mover el auto hacia adelante. Esto significa que todo lo que está dentro del roadContainer se mueve 10 píxeles a la izquierda, pero como el auto acaba de ser movido 10 píxeles a la derecha, permanece en el centro de la pantalla.
Es un poco como subir la escalera mecánica. Si subes a la misma velocidad a la que baja, a una persona que esté en la escalera de al lado le parecerá que no te estás moviendo.
El efecto en general:

¡El auto se mantiene en el centro! Genial. Bueno, genial aparte del enorme agujero blanco. Pero ya llegaremos a eso. Ahora, si quieres añadir más autos a la carretera, todo lo que tienes que hacer es añadirlos a la roadContainer.
Paso 12: Mejorar el seguimiento
El problema de mover todo el contenedor hacia atrás un poco cada fotograma es que no es muy flexible. ¿Qué pasa si el jugador utiliza un potenciador para teletransportar el auto 100 píxeles hacia adelante en lugar de 10? ¿Y si queremos que la cámara se centre en un auto diferente?
Cuando el SWF se carga por primera vez, la posición x del auto es 275, y la posición x del roadContainer es 0. ¿Cómo cambia cada uno de ellos con el tiempo?
- Inicio: car.x es 275, roadContainer.x es 0
- Cuadro 1: car.x es 285, roadContainer.x es -10
- Cuadro 2: car.x es 295, roadContainer.x es -20
- Cuadro 3: car.x es 305, roadContainer.x es -30
¿Ves una regla general que conecte ambas cosas? Si no, mira esto:
- Inicio: car.x es 275, roadContainer.x es 275 - 275
- Cuadro 1: car.x es 285, roadContainer.x es 275 - 285
- Cuadro 2: car.x es 295, roadContainer.x es 275 - 295
- Cuadro 3: car.x es 305, roadContainer.x es 275 - 305
¡La conexión es un poco más obvia ahora! Pongámoslo en código:
1 |
public function onEnterFrame( evt:Event ):void |
2 |
{
|
3 |
car.x = car.x + 10; |
4 |
roadContainer.x = 275 - car.x; |
5 |
} |
Ahora puedes hacer lo que quieras con el auto. Acelerarlo, teletransportarlo hacia delante un número aleatorio de píxeles, detener su movimiento... ¡lo que sea! La cámara continuará siguiéndolo.
Y si quieres hacer que la cámara siga un objeto diferente, solo tienes que sustituir car.x por otherObject.x en la línea que acabamos de cambiar.
Paso 13: Ampliar el camino
Es hora de arreglar el interminable vacío blanco de la nada al final del camino.
La forma más sencilla de alargar la carretera es simplemente añadir otra instancia del símbolo de la carretera a la derecha de nuestro símbolo existente, así: (líneas 9, 22, 23, 27)
1 |
package |
2 |
{
|
3 |
import flash.display.MovieClip; |
4 |
import flash.events.Event; |
5 |
public class ParallaxDemo extends MovieClip |
6 |
{
|
7 |
public var car:Car; |
8 |
public var road:Road; |
9 |
public var road2:Road; |
10 |
public var roadContainer:MovieClip; |
11 |
|
12 |
public function ParallaxDemo() |
13 |
{
|
14 |
car = new Car(); |
15 |
road = new Road(); |
16 |
road2 = new Road(); |
17 |
|
18 |
car.x = 275.0; |
19 |
car.y = 235.0; |
20 |
road.x = 0.0; |
21 |
road.y = 294.0; |
22 |
road2.x = road.x + road.width; |
23 |
road2.y = road.y; |
24 |
|
25 |
roadContainer = new MovieClip(); |
26 |
roadContainer.addChild( road ); |
27 |
roadContainer.addChild( road2 ); |
28 |
roadContainer.addChild( car ); |
29 |
|
30 |
stage.addChild( roadContainer ); |
31 |
addEventListener( Event.ENTER_FRAME, onEnterFrame ); |
32 |
} |
33 |
|
34 |
public function onEnterFrame( evt:Event ):void |
35 |
{
|
36 |
car.x = car.x + 10; |
37 |
roadContainer.x = 275 - car.x; |
38 |
} |
39 |
} |
40 |
} |
Así es como se ve el mío cuando se ejecuta:

Oh, Dios. Será mejor que arregle ese hueco.
Paso 14: Cuidado con el hueco
(Si no vas a dibujar tus propios gráficos, salta al paso 17).
El problema está en la línea 22 del código anterior, road2.x = road.x + road.width. El valor de la anchura de la carretera debe ser un poco más grande de lo que realmente parece ser mi carretera.
Incluso si tu carretera no tiene el mismo problema, todavía podría no encajar perfectamente. Así que vuelve a tu FLA y arrastra otro símbolo de carretera de la biblioteca a tu capa de Guía.
Asegúrate de que tiene la misma posición y que el primer segmento de carretera, y luego muévelo horizontalmente hasta que no quede ningún hueco:

Paso 15: Ajustar la unión
Si los bordes de tus dos símbolos no se unen bien, haz doble clic en uno de ellos. Podrás editarlo y ver inmediatamente cómo los cambios que hagas afectan al otro:

Utiliza este truco para ajustar los bordes del símbolo de forma que la unión sea limpia.
Paso 16: Elaborar la amplitud
En lugar de utilizar road.width para averiguar dónde debe colocarse el segundo segmento de carretera, utilizaremos un número que llamo breadth.
Para encontrar este número para tu carretera, simplemente toma la posición x de tu símbolo de carretera más a la derecha (en tu capa Guía), y resta la posición x de tu símbolo de carretera más a la izquierda.
Todo lo que estás haciendo aquí es calcular cuántos píxeles de distancia deben tener tus dos segmentos de carretera para obtener la misma unión perfecta que acabas de crear en Flash.
Paso 17: Añadir una variable de amplitud
Crea una nueva variable numérica, roadBreadth, y establece su valor al número que has calculado en el paso anterior: (Si estás usando mis gráficos, ese número es 653,7).
1 |
public class ParallaxDemo extends MovieClip |
2 |
{
|
3 |
public var car:Car; |
4 |
public var road:Road; |
5 |
public var road2:Road; |
6 |
public var roadContainer:MovieClip; |
7 |
public var roadBreadth:Number; |
8 |
|
9 |
public function ParallaxDemo() |
10 |
{
|
11 |
car = new Car(); |
12 |
road = new Road(); |
13 |
road2 = new Road(); |
14 |
roadBreadth = 653.7; |
Paso 18: Sustituye la anchura por la amplitud
Reemplaza la línea:
1 |
road2.x = road.x + road.width; |
con:
1 |
road2.x = road.x + roadBreadth; |
Ahora pruébalo. No debería haber ningún hueco:

¡Genial! Sin embargo, todavía nos encontramos con el interminable vacío blanco...
Paso 19: Hacer que el fondo se repita infinitamente
Podríamos crear un road3 y un road4 y un road5 y así sucesivamente, colocando cada una de ellas a la derecha de la anterior, pero no importa cuántos segmentos creáramos, el auto llegaría al final de ellos eventualmente.
Para una mejor solución, piensa en cuando eras niño. ¿Has jugado alguna vez a ese juego en el que finges que el suelo es de lava, pero tienes que llegar al otro extremo de la habitación de alguna manera? (Si no es así, ve a jugar ahora, es muy divertido).
No sé acerca de ustedes, pero en mi casa los cojines de los sofás se consideraban resistentes a la lava, capaces de servir de peldaños. Solo teníamos un par, lo que no era suficiente para llegar al final de la habitación, pero al final descubrí cómo hacer que llegaran más lejos.
Colocaba los dos cojines en el suelo para hacer un pequeño camino y me acercaba al segundo. Luego, recogía el que estaba detrás de mí, lo dejaba caer frente a mí y cruzaba hacia él. Recogiendo repetidamente el que estaba detrás de mí y moviéndolo delante de mí, podía llegar a donde quisiera.
Podemos utilizar la misma técnica para hacer que la carretera dure siempre, sin tener que utilizar más de dos segmentos. Todo lo que tenemos que hacer es detectar cuando un segmento de carretera está "detrás" de la cámara, y moverlo delante de ella.
¿Qué quiero decir con "detrás" de la cámara? Quiero decir que el borde derecho del segmento está fuera del borde izquierdo del escenario. Podemos utilizar esta declaración if para comprobarlo:
1 |
if ( road.x + roadBreadth + roadContainer.x < 0 ) |
2 |
{
|
3 |
//road is behind the camera |
4 |
} |
¿Tienes curiosidad por saber por qué funciona? Si no es así, pasa al siguiente paso. Si no, déjame explicarte:
- road.x es el número de píxeles a la derecha del borde izquierdo de roadContainer
- road.x + roadBreadth es el número de píxeles a la derecha del borde derecho de la carretera desde el borde izquierdo de roadContainer
- roadContainer.x es el número de píxeles a la derecha del borde izquierdo de roadContainer desde el borde izquierdo del escenario (como roadContainer se mueve constantemente hacia la izquierda, normalmente será negativo)
- Entonces, ( road.x + roadBreadth + roadContainer.x ) es cuántos píxeles a la derecha está el borde derecho de la carretera desde el borde izquierdo del escenario.
¡Uf! Ok, lo admito, es bastante confuso. Si quieres una explicación más profunda, no dudes en preguntar en los comentarios :)
Paso 20: Mover la carretera delante de la cámara
Ahora que podemos saber cuándo el segmento de carretera está detrás de la cámara, tenemos que volver a moverlo delante de la cámara.
Si movemos la carretera a la derecha por el número de píxeles de roadBreadth, estaría en el mismo lugar que el otro segmento de carretera. Por lo tanto, tenemos que moverlo a la derecha por el doble de esa cantidad:
1 |
if ( road.x + roadBreadth + roadContainer.x < 0 ) |
2 |
{
|
3 |
road.x = road.x + (2 * roadBreadth); |
4 |
} |
Pon eso en tu función onEnterFrame(), y pruébalo:
Como puedes ver, un segmento de la carretera se está repitiendo, pero el otro aún no.
Paso 21: Mover el otro segmento de carretera
Podemos copiar el código anterior para nuestro otro segmento de carretera, la road2:
1 |
public function onEnterFrame( evt:Event ):void |
2 |
{
|
3 |
car.x = car.x + 25; |
4 |
roadContainer.x = 275 - car.x; |
5 |
if ( road.x + roadBreadth + roadContainer.x < 0 ) |
6 |
{
|
7 |
road.x = road.x + (2 * roadBreadth); |
8 |
} |
9 |
if ( road2.x + roadBreadth + roadContainer.x < 0 ) |
10 |
{
|
11 |
road2.x = road2.x + (2 * roadBreadth); |
12 |
} |
13 |
} |
Pruébalo de nuevo:
¡Fantástico! Un fondo en bucle infinito, de desplazamiento lateral :) Ahora a crear el efecto de paralaje real...
Paso 22: Crear colinas onduladas
(Omite este paso si utiliza mis gráficos).
Necesitaremos un fondo que se repita para mostrar el desplazamiento de paralaje. Yo he elegido colinas, pero puedes hacer edificios, bosques, esculturas alienígenas ¡Lo que quieras!
Hay algunos trucos que puedes utilizar para que lo que dibujes parezca estar más lejos que el auto:
- Utiliza colores más apagados (por ejemplo, un tono de verde más oscuro para el césped)
- Dibuja menos detalles (no hay mechones individuales de hierba)
- Añade un efecto de "desenfoque" a los bordes (porque la cámara está enfocada en el auto)
Sigue los mismos pasos básicos que utilizamos para dibujar la carretera:
- Haz el símbolo más ancho que el escenario
- Alinea el símbolo para que el punto de registro esté en el borde izquierdo
- Darle un nombre de clase, exportarlo para ActionScript, y exportarlo en el primer cuadro
- Ajusta la unión para que los dos símbolos encajen bien
- Averigua la "amplitud" del símbolo
Aquí está la mía:

Paso 23: Programa las colinas
El código relativo a las colinas es casi exactamente el mismo que el que acabamos de escribir para las carreteras. Intenta escribirlo tú mismo. He pegado mi archivo AS con todas las nuevas adiciones a continuación, por lo que puede referirse a él si lo deseas:
1 |
package |
2 |
{
|
3 |
import flash.display.MovieClip; |
4 |
import flash.events.Event; |
5 |
public class ParallaxDemo extends MovieClip |
6 |
{
|
7 |
public var car:Car; |
8 |
public var road:Road; |
9 |
public var road2:Road; |
10 |
public var roadContainer:MovieClip; |
11 |
public var roadBreadth:Number; |
12 |
public var hills:Hills; |
13 |
public var hills2:Hills; |
14 |
public var hillsBreadth:Number; |
15 |
public var hillsContainer:MovieClip; |
16 |
|
17 |
public function ParallaxDemo() |
18 |
{
|
19 |
car = new Car(); |
20 |
road = new Road(); |
21 |
road2 = new Road(); |
22 |
roadBreadth = 653.7; |
23 |
|
24 |
hills = new Hills(); |
25 |
hills2 = new Hills(); |
26 |
hillsBreadth = 890.5; |
27 |
|
28 |
car.x = 275.0; |
29 |
car.y = 235.0; |
30 |
road.x = 0.0; |
31 |
road.y = 294.0; |
32 |
road2.x = road.x + roadBreadth; |
33 |
road2.y = road.y; |
34 |
|
35 |
hills.x = 0; |
36 |
hills.y = 14.5; |
37 |
hills2.x = hills.x + hillsBreadth; |
38 |
hills2.y = hills.y; |
39 |
|
40 |
roadContainer = new MovieClip(); |
41 |
roadContainer.addChild( road ); |
42 |
roadContainer.addChild( road2 ); |
43 |
roadContainer.addChild( car ); |
44 |
|
45 |
hillsContainer = new MovieClip(); |
46 |
hillsContainer.addChild( hills ); |
47 |
hillsContainer.addChild( hills2 ); |
48 |
|
49 |
stage.addChild( hillsContainer ); |
50 |
stage.addChild( roadContainer ); |
51 |
addEventListener( Event.ENTER_FRAME, onEnterFrame ); |
52 |
} |
53 |
|
54 |
public function onEnterFrame( evt:Event ):void |
55 |
{
|
56 |
car.x = car.x + 10; |
57 |
roadContainer.x = 275 - car.x; |
58 |
if ( road.x + roadBreadth + roadContainer.x < 0 ) |
59 |
{
|
60 |
road.x = road.x + (2 * roadBreadth); |
61 |
} |
62 |
if ( road2.x + roadBreadth + roadContainer.x < 0 ) |
63 |
{
|
64 |
road2.x = road2.x + (2 * roadBreadth); |
65 |
} |
66 |
|
67 |
hillsContainer.x = 275 - car.x; |
68 |
if ( hills.x + hillsBreadth + hillsContainer.x < 0 ) |
69 |
{
|
70 |
hills.x = hills.x + (2 * hillsBreadth); |
71 |
} |
72 |
if ( hills2.x + hillsBreadth + hillsContainer.x < 0 ) |
73 |
{
|
74 |
hills2.x = hills2.x + (2 * hillsBreadth); |
75 |
} |
76 |
} |
77 |
} |
78 |
} |
(Las nuevas líneas son 12-15, 24-26, 35-38, 45-47, 49 y 67-75.) ¿Cómo lo has hecho?)
Aquí está el resultado:
Quizás te preguntes por qué me he molestado en crear un hillsContainer. Si es así, ¡bien visto! Podríamos simplemente addChild() las colinas al roadContainer, pero la creación de un nuevo contenedor para el fondo es lo que nos permite crear el efecto real de paralaje.
Paso 24: El efecto de paralaje real
El efecto solo requiere cambiar una línea de código:
1 |
hillsContainer.x = 275 - car.x; |
En esto:
1 |
hillsContainer.x = (275 - car.x) * 1/5; |
Esto hace que las colinas se desplacen a 1/5 de la velocidad de la carretera y del auto.
Se ve así:
No tienes que usar 1/5; aumenta o disminuye este valor hasta que la velocidad te parezca adecuada.
¿Por qué funciona esto? Bueno, recuerda que vemos las cosas en un cono de visión; cuanto más lejos está algo, más podemos ver. Entonces si pasamos por delante de dos objetos del mismo tamaño, pero uno está más lejos, el más cercano de los dos parecerá moverse más rápido, así:
Añadamos otra capa de fondo, aún más alejada que las colinas.
Paso 25: Crea montañas
¡Esto es exactamente lo mismo que crear la carretera y las colinas, así que ni siquiera voy a pegar el código esta vez! Todo lo que voy a hacer es publicar una foto de mis montañas..

...decirte que la anchura de mis montañas es 751,5, x es 0 e y es 63,0; recordarte que debes crear un nuevo MovieClip mountainContainer; y que sepas que mis montañas se desplazan a 1/16 de la velocidad de mi carretera.
Ah, y mostrarte el resultado:
Paso 26: Crear el cielo
El cielo es bonito y fácil. Como está muy lejos, se desplaza tan lentamente que parece que apenas se desplaza. Las nubes y los pájaros se mueven, por supuesto, y el Sol sale y se pone, pero nada de esto se debe a ningún efecto de desplazamiento de paralaje. Esto significa que no tenemos que hacer que nada en el cielo se desplace.
(La excepción es si la cámara se desplaza muy, muy rápido, como la velocidad de un avión o un cohete. Incluso en ese caso, asegúrate de que se desplaza muy lentamente).
Por lo tanto, no es necesario preocuparse por la amplitud aquí, o la creación de una imagen que se repite infinitamente. Sin embargo, es una buena idea hacer un skyContainer, solo para mantener la coherencia. Mi cielo es solo un rectángulo azul:

Si lo colocas en x=0, y=0 cubrirá todo el escenario. Esto es lo que parece en el SWF:
Paso 27: Crear un gran árbol en primer plano
Hemos creado un montón de objetos de fondo, pero nada más cerca de la cámara que el coche. Como seguro te das cuenta, un objeto así tendría que desplazarse más rápido que el roadContainer, así que vamos a probar esto.
Para mi objeto de primer plano, he dibujado un árbol:

El árbol es un poco diferente de los otros objetos que hemos hecho hasta ahora porque no está hecho para hacer un bucle, se mantiene solo, no se unirá a otro árbol que esté a su lado. Esto significa que solo necesitamos un árbol en la pantalla en todo momento (especialmente porque es muy grande).
Así que solo necesitamos un objeto Árbol en el código también. Escribe el código para este objeto. Si estás usando mis gráficos, la posición x inicial será 780.0 y la posición y será 175.0.
Como el árbol se desplazará, seguimos necesitando un treeContainer, y seguimos necesitando un treeBreadth. Sin embargo, esta vez, el treeBreadth solo controla el número de píxeles entre cada árbol. Yo he utilizado un bonito y redondo 1000.0 para el mío.
Paso 28: Desplazar el árbol
Como solo hay un árbol, el código de desplazamiento es mucho más sencillo:
1 |
treeContainer.x = (275 - car.x) * 3; |
2 |
if ( tree.x + treeBreadth + treeContainer.x < 0 ) |
3 |
{
|
4 |
tree.x = tree.x + (2 * treeBreadth); |
5 |
} |
Nada complicado :) Solo hay que tener en cuenta que se desplaza tres veces más rápido que la carretera. Aquí está el resultado final:
¡Felicidades! Has creado una cámara que se desplaza dinámicamente, fondos que se repiten infinitamente y un efecto de paralaje pseudotridimensional :)
Otras ideas para probar
Aquí hay algunas cosas más que puedes hacer con el mismo código:
Si estás creando un juego de disparos y quieres que todas tus explosiones aparezcan más cerca de la cámara que tus enemigos, simplemente crea un nuevo explosionsContainer, añadeChild() cualquier explosión a eso, y haz que se desplace a la misma velocidad que el enemiesContainer.
Coloca la puntuación del jugador, su contador de vidas, los botones de silencio y pausa, y cualquier otra parte de la interfaz de tu juego en un único contenedor. Coloca este contenedor delante de todos los demás contenedores, pero no lo hagas desplazar. Esta es una manera fácil de mantener la cámara y los activos de un juego separados de su interfaz.
Intenta que un contenedor permanezca inmóvil mientras haces que los contenedores situados delante y detrás se desplacen en direcciones opuestas. Esto crea un efecto de rotación genial, como se ve a los cinco minutos de este clip de Blancanieves de Disney.
Conclusión
Gracias por leer este tutorial; espero que lo hayas disfrutado. Si algo no ha quedado claro, o si quieres hacer alguna pregunta sobre el efecto, por favor, publica un comentario abajo.
Hablando de comentarios, si creas algo usando este tutorial, me encantaría que publicaras un enlace para poder verlo :)





