Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.
Los videojuegos de plaformas ven sus orígenes en la década de los 80. Space Panic (1980), Pitfall (1981, de la Atari 2600), Super Mario Bros (1985).
En un videojuego de plataformas típico, el jugador irá saltando de plataforma en plataforma hasta llegar a su destino. Puede haber distintos tipos de plataformas, enemigos, ataques, etc.
Pasos en la realización de un juego de plataformas con PhaserJS
Carga de estructura y fondo
Definimos la estructura global del juego y cargamos la imagen de fondo. Como siempre, en la escena Boot.js precargamos la imagen de fondo y en la escena Game.js la ubicamos en pantalla.
Cargar el mapa
En este juego, hemos creado un mapa utilizando la aplicación Tiled. En la escena de nuestro juego, cargamos el JSON generado con esta herramienta y cargamos la imagen tiles.png que será usado por dicho JSON para poner los cuadraditos de la escena en pantalla.
En el fichero JSON, collisionLayer es la capa en la que hemos definido las plataformas contra las que podrá colisionar el jugador y en las que se podrá apoyar.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Ubicar el punto de origen de la cámara en pantalla.
Es posible que querramos que la cámara comience en un punto diferente del que comienza por defecto. Para lograrlo, podemos utilizar la siguiente clase, que nos permitirá sobrevolar la escena, para decidir las coordenadas iniciales de la cámara.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Y luego, dentro de la escena donde queremos fijar la cámara, usaremos:
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Con esto podremos mover la cámara utilizando los cursores del teclado y decidir donde queremos ubicarla:
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Cargar Player con el JSON de Tiled
Primero definiremos la clase del Player en un fichero externo, para que todo quede más ordenado. Esta clase tendrá el código necesario para crear un jugador y añadirlo a la escena. Este jugador, que hereda de la clase Sprite, tendrá físicas, así que deberemos activarlas en el main.js.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
En la clase Game, necesitaremos el siguiente método para buscar las coordenadas del player en el JSON de Tiled:
/src/utils.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Finalmente, cargamos el player en la escena.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Hacer la capa collisionLayer colisionable con el player
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Cargar el resto de capas no colisionables (grassLayer y backgroundLayer)
El el fichero generado con Tiled, además de la capa collisionLayer que contiene los objetos colisionables, también tenemos otras dos capas que contienen elementos del decorado. La capa de la hierba (grassLayer) que pondremos por delante del personaje y la capa backgroundLayer, con el resto de tiles de la decoración.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Ajustando la boundingbox del player
El spritesheet del player es un poco grande y eso hace que su area de colisión también lo sea. Para reducir este area de colisión, llamaremos al método setSize y le pasaremos como ancho el valor 90, que es la mitad del valor original
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
El jugador se mueve
En la clase Player vamos a integrar el código necesario para controlar su movimiento. Utilizaremos el objeto this.cursors dentro del método update para evaluar que tecla ha pulsado el usuario (la flecha de ir hacia la izquierda o la flecha de ir hacia la derecha). En función de la tecla pulsada llamaremos a la función leftWalk() o la función rightWalk(), que desplazará al jugador aplicándole una velocidad horizontal.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Animación del jugador
Cargamos la animación de caminar del Player…
/src/scenes/Boot.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
… Y en la clase del Player activamos dicha animación cuando el Player se mueva hacia los lados. También haremos un flip del spritesheet para que el Player siempre mire en la dirección en la que se está desplazando.
/src/characters/Player.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Reposo
Vamos a añadir al Player la animación de estar en reposo. Esto es una animación en la que se ve al Player respirando y que estará activa cuando el Player no se mueva en ninguna dirección.
Cargaremos la animación de estar en reposo del Player en la escena Boot.js a partir del spritesheet.
/src/scenes/Boot.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Tras cargar la animación de estar en reposo (dile), la activamos en la clase Player siempre y cuando no se esté moviendo.
/src/characers/Player.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Saltar
Añadimos el método saltar a la clase Player. El jugador sólo debe poder saltar si está tocando el suelo. Para ello, cuando pulsemos la flecha de dirección hacia arriba, llamamos a la función jump que será la que lo evalúe.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Añadir nuevos controles para un segundo jugador (paso opcional)
Una variante que podemos añadir a nuestro videojuego es que haya dos jugadores. Incluso podríamos partir la pantalla y añadir una cámara que siga a cada uno de los dos jugadores. Para ello, cada jugador será controlado con unas teclas diferentes del teclado. A continuación tienes el código para las teclas que controlarán al segundo jugador.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Además, debemos tener en cuenta que los nombres de los recursos y de las animaciones no pueden estar repetidos.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Animación de Caer
Vamos a activar una animación para el jugador para cuando no esté en contacto con el suelo, es decir, para cuando esté en la trayectoria ascendente o descendente de un salto.
Como utilizaremos una nueva animación, la cargamos dentro del método create de la clase Boot.js.
/src/scenes/Boot.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
En la clase Player, activaremos todas las animaciones que teníamos (idle y caminar) siempre que el player esté en contacto con el suelo. Cuando el player no esté en contacto con el suelo, activaremos la animación de caer.
/src/scenes/Player.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Controles visuales – poniendo los botones en pantalla
Para poder jugar desde un dispositivo móvil, definiremos la función visualControls, que colocará los controles visuales del jugador en escena.
El método setDepth hará que los controles siempre esten superpuestos al resto de elementos.
El método setScrollFactor hará que los botones no se desplacen aunque el jugador si lo haga.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Controles visuales – dando funcionalidad
Vamos a completar el código que definimos en el paso anterior y que añadía controles visuales al videojuego. A estos controles visuales vamos a añadir funcionalidad para controlar el moviento del jugador. De esta forma, cuando el jugador los pulse, modificaremos una propiedad data vinculada al propio Player, que almacenará información sobre los botones pulsados.
En el método update evaluaremos tanto los botones que el jugador ha pulsado como la información almacenada en data. En función de esto determinaremos el movimiento del jugador.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
La cámara sigue al prota
Hasta ahora, aunque podíamos controlar al player, la camara no lo seguía y podía desaparecer por los límites de la pantalla. Con este código hacemos que la cámara se desplace y siga al jugador.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
La cámara sigue al prota horizontalmente
En este juego concretamente no queremos que la cámara se desplace verticalemente. Sólo queremos que la cámara siga al jugador horizontalmente. Para limitar el movimiento horizontal de la cámara usaremos la línea this.cameras.main.scrollY = 0;
Eliminamos la línea:
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
El fondo se repite
Igual que hicimos en el juego del Flappy Bird, vamos a hacer que la imagen de fondo se repita horizontalmente. Esta imagen debe estar preparada para que los pixels de un de sus lados coincidan con los pixeles del otro lado.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Método para la inserción de enemigos
El método insertBadGuys que vamos a definir y a usar, recibirá como parámetro de entrada, la escena en la que queremos cargar los enemigos, el array con las coordenadas de cada uno de los enemigos y el tipo de enemigo que vamos a cargar.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
/src/utils.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
/src/characters/AntEnemy.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Enemigo con animación
En el preload de la escena Boot cargaremos el spritesheet de la hormiga y en el create definiremos su animación de andar. Luego, en el constructor de la clase hormiga debemos activar esta animación.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Enemigo se mueve
Aunque en el paso anterior cagamos la animación de andar de la hormiga, esta todavía no se esta desplazando. Para lograrlo, le aplicaremos una velocidad en su método update. Dicha velocidad tendrá una magnitud, que llamaremos speed y una dirección, que llamaremos direction y podrá ser hacia la derecha o hacia la izquierda.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Enemigo inteligente
Vamos a darle un poco de cerebro a nuestra hormiga. Vamos a hacer que cuando la hormiga llegue al límite de un barranco se mueva en dirección opuesta. Para ello, crearemos la variable nextY que contendrá información del pixel que hay justo delante de la hormiga a ras de suelo. Si justo delante de la hormiga a ras de suelo no hay una plataforma colisionable, significará que hay un precipicio y la hormiga dará media vuelta (modificaremos la variable direction).
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Player muere, Enemigo muere
Cuando el jugador colisione contra una hormiga llamaremos al método checkEnemy de la clase Player que podrá hacer dos cosas:
- Si el jugador se encontraba en un movimiento descendente, será porque el jugador esta aplastando al enemigo, y en ese caso llamaremos a la función die del enemigo, que lo desactivará.
- Si el jugador no se encontraba en un movimiento descendente, eliminaremos al desactivaremos al jugador.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Enemigo explota
Vamos a completar el código que se ejecuta cuando un enemigo muere. Hasta ahora, sólo estabamos desactivando sus físicas. En este paso vamos a activar una animación de explosión que debemos haber cargado previamente en la clase Boot y vamos a añadir un listener que escucha cuando finaliza cualquier animación, y cuando termine la animación de explosión vamos a eliminar a la hormiga.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Prota explota
Ahora programaremos la muerte del jugador. El código es similar al de la muerte de la hormiga. Utilizaremos la variable isAlive para detener todas las demás animaciones cuando el Player es colisionado.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Enemigo con Herencia
Creamos una nueva clase llamada Enemy de tal forma que AntEnemy herede de Enemy. Meteremos las partes del código de AntEnemy que son comunes a todos los enemigos a la clase Enemy.
Aunque cambiemos la estructura del código interno, en este punto el juego debe seguir haciendo lo mismo.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Insertar Oruga
Vamos a programar un nuevo tipo de enemigo: la oruga. Realmente, el comportamiento de la oruga y de la hormiga es muy similar. Ambos bichos se desplazar horizontalmente hasta encontrarse con un precipicio. En ese momento darán media vuelta. Como hemos encapsulado este comportamiento en la clase Enemy, si la oruga hereda de Enemy, hará eso mismo.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Utilizaremos de nuevo el método findObjectsByClassInObjectsLayer para buscar las coordenadas de todas las orugas que pusimos en el mapa utilizando Tiled. Cuando las tengamos, se las pasamos al método insertBadGuys para que se inserten en pantalla.
/src/scenes/Game.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Insertar Avispa
Vamos a crear un nuevo enemigo: la avispa. Este enemigo no tiene el mismo comportamiento que la hormiga y la oruga, y por tanto, no heredará de la clase Enemy.
De momento, crearemos la clase de este enemigo y activaremos su animación, que debe haber sido cargada en la escena Boot.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Hacer que la avispa de vueltas
El comportamiento de la avispa consistirá en dar vueltas en círculos hasta que el jugador se acerque lo suficiente. En ese momento, la avispa atacará al jugador y finalmente volverá a su posición original.
Para hacer que la avispa vuele en círculos, definiremos la trayectoria flyPath que será un círculo con centro en la posición x,y y radio 100. la variable pathIndex contiene el grado de completitud de la trayectoria, y currentPosition será una variable que será alimentada automáticamente mediante la función getPoint.
El método update irá llamando al método getPoint que en función del grado de completitud de la trayectoria (pathIndex) irá alimentando a la variable currentPosition. Por su lado, como puedes ver en el código, la variable pathIndex esta en función de la velocidad (pathSpeed).
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Refactorizar el código para utilizar el estado FLYING y la función checkPlayer
Añadiremos los estados después de la clase Avispa. La avispa ejecutará uno u otro comportamiento en función de unas constantes llamadas estados. Inicialmente, tendremos un estado llamado FLYING. Cuando este sea el estado activo (el valor de la variable this.state) el comportamiento de la avispa será el que definimos en el paso anterior, es decir, volará en círculos.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Avispa detecta a Player
Cuando el jugador esté lo suficientemente cerca de la avispa, esta le atacará. Para ello, definiremos un area alredodor de la avispa, de tal forma que cuando el jugador penetre en dicho area, la avispa le ataque. Este area será la variable patrolCircle, que como puedes ver es un círculo con origen en la propia avispa y radio 256.
El método checkUpdate irá actualizando constantemente el centro de este círculo a partir de la posición de la propia avispa. También evaluará si el jugador entra dentro del patrolCircle, en cuyo caso mostrará un mensaje de alerta.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Avispa persigue a Player
En el caso de que el jugador entre dentro del patrolCircle, en lugar de mostrar un mensaje de alerta, vamos a cambiar el estado de la avispa a CHASING.
Al tener el estado CHASING activado, en el método update estaremos llamando constantemente a la función chasePlayer, que moverá la avispa en la dirección del player, llamando a la función moveTo.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Avispa ataca a Player
Finalmente, la avispa colisionará con el player y le atacará. En ese momento, activaremos la animación beeAtack, que habremos precargado en la escena Boot.
Cuando la animación de ataque concluya, de momento, mostraremos un mensaje de alerta.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Avispa vuelve a casa
En lugar de mostrar un mensaje de alerta cuando la animación de ataque concluya, lo que haremos será hacer que la avispa vuelva a su posición inicial.
Para ello, activaremos un nuevo estado llamado RETURNING. Al evaluar los estados en el método update y comprobar que el estado activo es RETURNING, llamaremos a la función returnHome.
La función returnHome irá moviendo la avispa a su posición original y cuando llegue a esta posición, activaremos de nuevo el estado FLYING, que pondrá la avispa a dar vueltas.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
La avispa siempre mira al protagonista
Durante todo el movimiento de la avispa, esta siempre mira en la misma dirección. Queremos que la avispa siempre mire en la dirección del jugador, y para ello, la voltearemos (haremos flip) en función de la posición del player respecto de la avispa. Si el player está a la izquierda de la avispa, la avispa mirará hacia la derecha y si no, mirará hacia la izquierda
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
El heroe recibe daño
Durante el ataque de la avispa, cuando esta colisione contra el player, de momento no esta ocurriendo nada. Vamos a añadir un código que haga que el jugador realmente reciba el impacto de la avispa.
De momento, cuando se produca esta colisión entre ambos sprites llamaremos a la función hittedByBee, que mostrará un mensaje de alerta.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
El Player sale despedido por los aires
En lugar de un mensaje de alerta, vamos a aplicar al player una velocidad para que salga despedido por los aires, a activar su animación de caer y a activar una variable (isDazing) que bloqueará temporalmente los controles del jugador.
Debemos bloquear los controles del jugador porque si no la velocidad que le aplicamos en el momento de la colisión se verá contrarrestada por las velocidades que se le aplican al jugador cuando estamos controlándolo con las flechas del teclado y no se verá ninguna velocidad aplicada.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Reactivar los controles del jugador
Al cabo de un tiempo debemos poder volver a controlar al jugador. Para ello, al cabo de un tiempo, volvemos a setear la variable isDazing con valor false.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Añadir meta
El nivel que hemos hecho concluirá cuando el jugador llegue a cierto punto de la escena. Este punto lo habremos colocado previamente en la escena utilizando Tiled, y lo colocaremos de la misma forma que hemos coocado los enemigos, obteniendo sus coordenadas con el método findObjectsByClassInObjectsLayer.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Fin del juego
Cuando el jugador colisione con la meta, cargaremos una nueva escena de partida ganada.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Limitando la cámara
No queremos que la cámara rebase ciertos límites. Podemos limitar el rango de movimiento de la cámara utilizando la siguiente línea.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Escena de perder tras explotar
Cuando el jugador pierde, a parte
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Escena de perder tras caer por precicipio
Además de perder la partida cuando el enemigo nos colisiona, también podemos perder al caer por alguno de los agujeros del decorado.
Para ello, el método setBoundCollision activará la colisión con la parte inferior de la pantalla para que cuando esta ocurre se cargue la escena de GameOver.
/src/scenes/Game.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Además, el jugador también tiene que tener activas algunas propiedades para poder detectar la colisión con el fondo de la pantalla.
/src/characters/Player.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.