Hacer increíbles juegos de plataforma cruzada es ahora más fácil que siempre lo ha sido gracias a Phaser, una biblioteca de desarrollo de juegos Open Source JavaScript desarrollado por Richard Davey y su equipo en Photonstorm. Juegos desarrollados con Phaser se pueden reproducir en cualquier (moderna) del navegador web, y también se pueden convertir en aplicaciones de teléfonos nativos mediante el uso de herramientas tales como Córdoba.

Tabla de contenidos

Aprender haciendo su primer juego

El objetivo de este tutorial es para enseñarle los fundamentos de este fantástico marco (versión 3.x) mediante el desarrollo del tipo “Frogger” del juego que aparece a continuación:

juego de la travesía del dragón con el jugador se mueve hacia las joyas

Se puede descargar el juego y el código aquí. Todos los activos incluidos fueron producidos por nuestro equipo y se puede utilizar en sus propias creaciones.

objetivos de aprendizaje

  • Aprende a crear juegos simples en Phaser 3
  • Trabaja con sprites y sus transformadas
  • métodos principales de una escena Phaser
  • grupos en el comportamiento de sprites agregada Utilizar
  • efectos básicas de la cámara (nueva característica Phaser 3)

    Tutorial requisitos

    Aprender Phaser 3 con nuestro nuevo mini-Grado

    El desarrollo del juego HTML5 Mini-Grado ya está disponible en Zenva Academia. Aprender a código y hacer que los juegos impresionantes con JavaScript y Phaser 3!

    Obtenga acceso

    Entorno de desarrollo

    El entorno de desarrollo mínimo que necesita consiste en un editor de código, un navegador web y un servidor web local. Los dos primeros son triviales, pero el último requiere un poco más de explicación. ¿Por qué es que necesitamos un servidor web local?

    Cuando se carga una página web normal, es común que el contenido de la página se carga antes de que las imágenes, ¿verdad? Bueno, imagina si eso ocurriera en un juego. Sería ciertamente un aspecto terrible si la imagen del reproductor carga el juego, pero no está listo.

    Phaser 3 juego mostrando cajas negras donde los sprites descargadas deben ser

    Phaser necesita primero precarga todas las imágenes / activos antes de que comience el juego. Esto significa que el juego tendrán que acceder a archivos después de la página se ha cargado. Esto nos lleva a la necesidad de un servidor web.

    Los navegadores, por defecto, no deje que los sitios web sólo los archivos de acceso de la unidad local. Si lo hicieran, la web sería un lugar muy peligroso! Si hace doble clic en el index.html de archivo de un juego Phaser, verá que sus evita que el navegador del juego de la carga de los activos.

    Es por eso que necesitamos un servidor web a los archivos del servidor. Un servidor web es un programa que las peticiones y respuestas HTTP mangos. Por suerte para nosotros, hay conexión múltiple y fácil de configurar alternativas servidor web local!

    Configuración de su servidor web local

    La solución más sencilla que he encontrado es una aplicación de Chrome llamada (sorprendentemente) Servidor web para Chrome. Una vez que instale esta aplicación, se puede poner en marcha si directamente desde Chrome, y cargar la carpeta del proyecto.

    pestaña Google Chrome Apps con servidor Web seleccionado

    Servidor Web para la ventana del cromo con el servidor Web URL en círculos

    Usted será capaz de navegar a esta carpeta escribiendo la URL del servidor web en el navegador.

    Hello World Phaser 3

    Ahora que nuestro servidor web está en funcionamiento, permite asegurarnos de que tenemos Phaser que se ejecuta en nuestro extremo. Puede encontrar la biblioteca Phaser aquí. Hay diferentes maneras de obtener y Phaser incluyendo en sus proyectos, sino para mantener las cosas simples que va a utilizar la alternativa CDN. Me gustaría recomendar que utilice el expediente no minified para el desarrollo -. Que le hará la vida más fácil cuando la depuración del juego

    desarrolladores más avanzados podrían desviarse de estas instrucciones y usar una configuración de entorno de desarrollo más sofisticado y flujo de trabajo. Que cubran los citados está fuera del alcance de este tutorial, pero se puede encontrar un gran punto de partida aquí, que utiliza webpack y Babel.

    En nuestra carpeta de proyecto, crear un archivo index.html con el siguiente contenido:
    Aprender el desarrollo del juego en Zenva.com </ title> <script src = "// CDN. jsdelivr.net/npm/phaser@3.2.1/dist/phaser.js"></script></head><body><script src = "js / game.js"> </ script> </ body> </ html> 1234567891011 <! DOCTYPE html> <html lang = "es"> <head> <meta charset = "UTF-8" /> <title> Aprender el desarrollo del juego en Zenva.com </ title> <script src = "src = //cdn.jsdelivr.net/npm/phaser@3.2.1/dist/phaser.js"></script></head><body><script" js / game.js "> </ script > </ body> </ html> </p> <p> Ahora cree una carpeta llamada <em> JS </ em>, y dentro de ella, nuestro archivo de juego <em> game.js: </ em> </ p><br /> // crear un nuevo escenario llamado "juego" dejó gameScene = new Phaser.Scene ( 'Juego'); // nuestro juego de configurationlet config = {type: Phaser.AUTO, // Phaser decidirá el modo de hacer nuestro juego (o WebGL lienzo) ancho: 640, // juego anchura altura: 360, // juego escena altura: // gameScene nuestra escena recién creada}; // crear el juego, y pasarlo al juego configurationlet = new Phaser.Game (config); 12345678910111213 // crear un nuevo escenario llamado "juego" dejar gameScene = newPhaser.Scene ( 'juego'); // de nuestro juego configurationlet config = {type: Phaser.AUTO, // Phaser decidirá el modo de hacer nuestro juego (o WebGL lienzo) ancho: 640, // juego widthheight: 360, // heightscene juego: // gameScene nuestra escena recién creada}; // crear el juego, y pasarlo al juego configurationlet = newPhaser.Game (config); </p> <p> lo que estamos haciendo aquí: </ p><br /> <Ul><br /> <Li> Estamos creando una nueva escena. Pensar en escenas como compartimentos, donde la acción del juego se lleva a cabo. Un juego puede tener varias escenas, y en Phaser 3 un juego puede incluso tener varias escenas abiertas al mismo tiempo (echa un vistazo a este ejemplo) </ li><br /> <Li> Es necesario decir a nuestro juego cuáles serán las dimensiones en píxeles. Importante mencionar que este es el tamaño del área visible. El entorno del juego en sí no tiene el tamaño del conjunto (como se solía tener en Phaser 2 con el objeto “juego del mundo”, que no existe en Phaser 3). </ Li><br /> <Li> Una Phaser juego puede utilizar diferentes sistemas de representación. Los navegadores modernos tienen soporte para WebGL, que en términos simples consiste en “el uso de su tarjeta gráfica para representar el contenido de la página para un mejor rendimiento”. La API lienzo está presente en más navegadores. Al establecer la opción de renderizado en “AUTO”, le estamos diciendo Phaser usar WebGL si está disponible, y si no, utilizamos la lona. </ Li><br /> <Li> Por último, creamos nuestro objeto real del juego. </ Li><br /> </ Ul><br /> <P> Si ejecuta esto en el navegador y abre la consola debería ver un mensaje que indica que Phaser está en funcionamiento: </ p><br /> <P> <img src = "http://fymm-rpg.net/wp-content/uploads/placeholder-300x123.png" alt = "Google Chrome Developer Tools con iluminación cuerpo de la etiqueta en los Elementos" /> </ p><br /> <H3> Escena del ciclo de vida </ h3><br /> <P> Para que podamos añadir las primeras imágenes a nuestro juego, tendremos que desarrollar una comprensión básica del ciclo de vida Escena: </ p><br /> <P> <img src = "http://fymm-rpg.net/wp-content/uploads/placeholder-300x47.png" alt = "Phaser ciclo de vida de la ilustración 3 juego" /> </ p><br /> <Ul><br /> <Li> Cuando se inicia una escena, el método init se llama. Aquí es donde se pueden parámetros de configuración para la escena o juego. </ Li><br /> <Li> Lo que sigue es el sincronizador (método de precarga) de precarga. Como se ha explicado anteriormente, las cargas Phaser imágenes y activos en la memoria antes de iniciar el juego real. Una gran característica de este marco es que si se carga la misma escena dos veces, los activos se cargan desde una memoria caché, por lo que será más rápido. </ Li><br /> <Li> Al término de la fase de precarga, el crear es ejecutado método. Esta ejecución de una sola vez le da un lugar bueno para crear las principales entidades para su juego (jugador, enemigos, etc). </ Li><br /> <Li> Si bien la escena está en marcha (no en pausa), el método de actualización se ejecuta varias veces por segundo (el juego va a aspirar a 60. En el hardware como de baja gama Android de menos rendimiento, podría ser menor). Este es un lugar importante para nosotros usar también. </ Li><br /> </ Ul><br /> <P> Hay más métodos en el ciclo de vida escena (render, apagado, destruir), pero que no van a utilizar en este tutorial. </ P><br /> <H3> Traer en los sprites! </ H3><br /> <P> buceo Vamos a la derecha en ella y mostrar nuestro primer sprite, el juego de fondo, en la pantalla. Los activos de este tutorial se puede descargar aquí. Colocar las imágenes en una carpeta denominada “activos”. El siguiente código va después de dejar gameScene = newPhaser.Scene ( 'Juego'); : </ P><br /> // archivos de activos de carga para nuestra gamegameScene.preload = function () {// carga imágenes this.load.image ( 'fondo' 'activos / background.png');}; // ejecutan una vez, después de los activos eran loadedgameScene. crear = function () {// fondo this.add.sprite (0, 0, 'fondo');} // 12345678910111213 archivos activos de carga para nuestra gamegameScene.preload = function () {// imagesthis.load.image carga ( 'fondo', 'activos / background.png');}; // ejecuta una vez, después de activos eran loadedgameScene.create = function () {// backgroundthis.add.sprite (0,0, 'fondo');} < ul><br /> <Li> Nuestra imagen de fondo del juego “background.png” se carga. Estamos dando este activo la etiqueta de “fondo”. Este es un valor arbitrario, podría llamarse cualquier cosa que desee. </ Li><br /> <Li> Cuando todas las imágenes se cargan, se crea un sprite. El sprite se coloca en x = 0, y = 0. El activo utilizado por este Sprite es que con la etiqueta “fondo”. </ Li><br /> </ Ul><br /> <P> Vamos a ver el resultado: </ p><br /> <P> <img src = "http://fymm-rpg.net/wp-content/uploads/placeholder-300x168.png" alt = "Phaser 3 juego con el fondo recién colocado" /> </ p><br /> <P> No exactamente lo que quería ¿verdad? Después de todo, el fondo lleno imagen se ve de esta manera: </ p><br /> <P> <img src = "http://fymm-rpg.net/wp-content/uploads/placeholder-300x169.png" alt = "Phaser 3 juego con la escala aplicada para el fondo de pantalla completa" /> </ p ><br /> <P> Antes de resolver este problema vamos a ir primero sobre cómo se establecen las coordenadas de Phaser. </ P><br /> <H3> Coordenadas </ h3><br /> <P> El origen (0,0) en la Phaser es la parte superior de la esquina izquierda de la pantalla. El eje x es positivo a la derecha, y el eje Y es hacia abajo positivos: </ p><br /> <P> <img src = "http://fymm-rpg.net/wp-content/uploads/placeholder-300x183.png" alt = "sistema de coordenadas XY con 0,0 y 10,6 como puntos de" /> < / p><br /> <P> Sprites por defecto tienen su punto de origen en el centro, caja en x e y. Esta es una diferencia importante con Phaser 2, donde los sprites tenía lo que se llama un punto de anclaje en la esquina superior izquierda. </ P><br /> <P> Esto significa que cuando colocamos nuestra antecedentes sobre Phaser (0,0), que en realidad dice: colocar el centro del sprite en (0,0). Por lo tanto, el resultado que obtiene. </ P><br /> <P> Para colocar la esquina superior izquierda de nuestra sprites en la esquina superior izquierda de la pantalla podemos cambiar el origen del sprite, para ser Es esquina superior izquierda: </ p><br /> // ejecuta una vez, después de los activos eran loadedgameScene.create = function () {// fondo dejar bg = this.add.sprite (0, 0, 'fondo'); // cambio origen a la bg.setOrigin parte superior izquierda del sprite (0,0);}; 123 456 789 // ejecuta una vez, después de activos eran loadedgameScene.create = function () {// backgroundlet bg = this.add.sprite (0,0, 'fondo'); // cambio de origen hasta la parte superior izquierda de la spritebg.setOrigin (0,0);}; </p> <p> el fondo será ahora rendir en la posición que queremos que sea: < / p><br /> <P> <img src = "http://fymm-rpg.net/wp-content/uploads/placeholder-300x169.png" alt = "rindió el fondo basado en coordenadas X-Y" /> </ p><br /> <H3> El jugador </ h3><br /> <P> Es hora de crear un reproductor sencillo podemos controlar ya sea haciendo clic o tocando en el juego. Dado que se irán sumando más sprites, vamos a añadir estos a <em> precarga </ em>, así que no tenemos que modificarlo de nuevo más tarde: </ p><br /> // archivos de activos de carga para nuestra gamegameScene.preload = function () {// cargar imágenes this.load.image ( 'fondo', 'activos / background.png'); this.load.image ( 'jugador', 'activos / player.png'); this.load.image ( 'dragón', 'activos / dragon.png'); this.load.image ( 'tesoro', 'activos / treasure.png');}; // 123456789 archivos activos de carga para nuestra gamegameScene.preload = function () {// imagesthis.load.image carga ( 'fondo', 'activos / background.png'); this.load.image ( 'jugador', 'activos / player.png'); this.load.image ( 'dragón', 'activos / dragon.png'); this.Load .Imagen ( 'tesoro', 'activos / treasure.png');}; </p> <p> a continuación, añadir el reproductor de sprites y reducir su tamaño en un 50%, dentro de <em> crear </ em> </ p><br /> // jugador this.player = this.add.sprite (40, this.sys.game.config.height / 2, 'jugador'); // escala abajo this.player.setScale (0,5); 12 345 // playerthis.player = this.add.sprite (40, this.sys.game.config.height / 2, 'jugador'); downthis // escala. player.setScale (0,5); </p> <ul> <Li> Estamos poniendo nuestra sprites en x = 40. Para y, estamos colocando en el medio de la vista juego. Esto nos da acceso a nuestro objeto escena actual, this.sys.game nos da acceso al objeto de juego global. this.sys.game.config nos da la configuración que hemos definido al iniciar nuestro juego. </ li><br /> <Li> Aviso estamos ahorrando nuestro jugador al objeto escena actual (this.player). Esto nos permitirá acceder a esta variable de otros métodos en nuestra escena. </ Li><br /> <Li> que reducir nuestro jugador que utiliza el método setScale, que se aplica en este caso una escala de 0,5 a X e Y (también se puede acceder a las propiedades scaleX y scaleY sprites directamente). </ Li><br /> </ Ul><br /> <P> Nuestra Valkyrie está listo para la acción! Tenemos que desarrollar la capacidad siguiente de que nos movamos ella con el ratón o pantalla táctil. </ P><br /> <P> <img src = "http://fymm-rpg.net/wp-content/uploads/placeholder-300x168.png" alt = "Phaser 3 escena del juego con el jugador Sprite añade" /> </ p><br /> <H3> entrada Detectando </ h3><br /> <P> Phaser 3 ofrece muchas maneras de trabajar con la entrada del usuario y eventos. En este juego en particular que no se va a utilizar eventos, pero sólo comprueba que la “entrada activa” (ya sea por defecto, el ratón o el botón táctil izquierda) está activada. </ P><br /> <P> Si el jugador está presionando / en cualquier lugar de tocar en el juego, nuestra Valkyrie caminará hacia adelante. </ P><br /> <P> Para comprobar si hay entrada de esta manera tendrá que añadir un <em> actualización </ em> método a nuestro objeto de escena, que normalmente se llama 60 veces por segundo (que se basa en el método requestAnimationFrame, en menos dispositivos de la realización que se llamará menos a menudo lo que no asume 60 en su lógica del juego): </ p><br /> // ejecutadas en cada cuadro (60 veces por segundo) gameScene.update = function () {// cheque de entrada activa si (this.input.activePointer.isDown) {// jugador camina}}; 123456789 // ejecutado en cada marco (60 veces por segundo) gameScene.update = function () {// cheque por inputif activa (this.input.activePointer.isDown) {// jugador camina}}; </p> <p> puede verificar que esto funciona mediante la colocación de una <em> console.log </ em> ingreso en ese país. </ p><br /> <Ul><br /> <Li> this.input nos da acceso al objeto de entrada para la escena. Diferentes escenas tienen su propio objeto de entrada y pueden tener diferentes configuraciones de entrada. </ Li><br /> <Li> Este código será cierto cuando el usuario presiona el botón izquierdo (hace clic en el área de juego) o toca la pantalla. </ Li><br /> </ Ul><br /> <H3> Desplazamiento del reproductor </ h3><br /> <P> Cuando la entrada está activa vamos a aumentar la posición X del jugador: </ p><br /> // cheque de entrada activa si (this.input.activePointer.isDown) {// jugador camina this.player.x + = this.playerSpeed; } 123 456 // cheque por inputif activa (this.input.activePointer.isDown) {// jugador walksthis.player.x + = this.playerSpeed;} </p> <p> <em> this.playerSpeed ​​</ em> es un refugio parámetro nos 't sin embargo declaró. El lugar para hacerlo será el <em> init </ em> método, que se llama antes de que el método <em> precarga </ em>. Añadir lo siguiente antes de la definición de la precarga (la orden de la declaración real no es importante, sino que hará que nuestro código sea más clara). Estamos añadiendo otros parámetros, así que utilizaremos más adelante: </ p><br /> // algunos parámetros para nuestra escena (nuestras propias variables de los clientes - no son parte de la API Phaser) gameScene.init = function () {this.playerSpeed ​​= 1,5; this.enemyMaxY = 280; this.enemyMinY = 80;} // 123456 algunos parámetros para nuestra escena (nuestras propias variables del cliente - estos no son parte de la API Phaser) gameScene.init = function () {this.playerSpeed ​​= 1,5; this.enemyMaxY = 280; this.enemyMinY = 80;!} </p> <p> Ahora podemos controlar nuestro jugador y lo mueve todo el camino hasta el final de la zona visible </ p><br /> <H3> Búsqueda del tesoro </ h3><br /> <P> Lo bueno es un juego sin un objetivo claro (toma que Minecraft!). Vamos a añadir un cofre del tesoro al final del nivel. Cuando los solapamientos posición de jugador con la del tesoro, vamos a reiniciar la escena. </ P><br /> <P> Dado que ya precargados todos los activos, saltar directamente a la parte de la creación de sprites. Observe cómo nos posicionamos en el pecho X 80 píxeles hacia la izquierda del borde de la pantalla: </ p><br /> // meta this.treasure = this.add.sprite (this.sys.game.config.width - 80, this.sys.game.config.height / 2, 'tesoro'); this.treasure.setScale (0,6); 123 // goalthis.treasure = this.add.sprite (this.sys.game.config.width-80, this.sys.game.config.height / 2, 'tesoro') ; this.treasure.setScale (0,6); </p> <p> En este tutorial no estamos utilizando un sistema de física tales como Arcade (que viene con Phaser). En su lugar, estamos comprobando colisión mediante el uso de un método de utilidad que viene en Phaser, lo que nos permite determinar si dos rectángulos se superponen. </ P><br /> <P> Vamos a poner este control en <em> actualización </ em>, ya que es algo que queremos estar poniendo a prueba para en todo momento: </ p><br /> // tesoro colisión si (Phaser.Geom.Intersects.RectangleToRectangle (this.player.getBounds (), this.treasure.getBounds ())) {this.gameOver (); } 1234 // tesoro collisionif (Phaser.Geom.Intersects.RectangleToRectangle (this.player.getBounds (), this.treasure.getBounds ())) {this.gameOver ();} </p> <ul> <Li> El método getBounds de un sprite nos da las coordenadas del rectángulo en el formato correcto. </ Li><br /> <Li> Phaser.Geom.Intersects.RectangleToRectangle devolverá true si los dos rectángulos pasaron solapamiento </ li><br /> </ Ul><br /> <P> Vamos a declarar nuestro <em> gameover </ em> método (este es nuestro propio método, se le puede llamar como quiera - que no es parte de la API). Lo que hacemos en este método es el reinicio de la escena, para que pueda jugar de nuevo: </ p><br /> // fin de la gamegameScene.gameOver = function () {// reiniciar la escena this.scene.restart ();} 123 456 // fin de la gamegameScene.gameOver = function () {// reinicie el scenethis.scene.restart () ;} </p> <h3> un grupo de dragones </ h3><br /> <P> La vida no es fácil y si nuestro Valkyrie quiere su oro, que va a tener que luchar por ella. ¿Qué mejor que los enemigos malvados dragones amarillos! </ P><br /> <P> Lo que haremos a continuación es crear un grupo de dragones en movimiento. Nuestros enemigos van a tener un movimiento de vaivén - el tipo de cosas que uno esperaría ver en un clon de Frogger </ p><br /> <P> En Phaser, un grupo es un objeto que le permite crear y trabajar con múltiples sprites al mismo tiempo. Vamos a empezar por la creación de nuestros enemigos en sí, <em> crear </ em> </ p><br /> // grupo de enemigos this.enemies = this.add.group ({clave: 'dragón', repetición: 5, setXY: {x: 110, y: 100, stepX: 80, Stepy: 20}}); 1234567891011 / / grupo de enemiesthis.enemies = this.add.group ({clave: 'dragón', repetición: 5, setXY: {x: 110, y: 100, stepX: 80, Stepy: 20}}); </p> <p> < img src = "http://fymm-rpg.net/wp-content/uploads/placeholder-300x167.png" alt = "Phaser 3 juego con seis, sprites en pantalla gigante dragón" /> </ p><br /> <Ul><br /> <Li> Estamos creando 5 (propiedad de repetición), sprites usando el activo con el dragón etiqueta. </ Li><br /> <Li> La primera de ellas se coloca en (110, 100). </ Li><br /> <Li> A partir de ese primer punto, nos movemos 80 en x (stepX) y 20 en Y (Stepy), para cada sprite de adicional. </ Li><br /> <Li> En el futuro, los miembros de un grupo se llama “niños”. </ Li><br /> </ Ul><br /> <P> Los dragones son demasiado grandes. escala de defraudarlos: </ p><br /> // enemigos escala Phaser.Actions.ScaleXY (this.enemies.getChildren (), -0,5, -0,5); 12 // escala enemiesPhaser.Actions.ScaleXY (this.enemies.getChildren (), - 0,5, -0,5); </p> <ul> <Li> Phaser.Actions.ScaleXY es una utilidad que reduce la escala de 0,5, a todos los sprites que se pasan en. </ Li><br /> <Li> getChildren no nos lleva a una matriz con todos los sprites que pertenecen a un grupo </ li><br /> </ Ul><br /> <P> Esto se ve mejor: </ p><br /> <P> <img src = "http://fymm-rpg.net/wp-content/uploads/placeholder-300x167.png" alt = "Phaser 3 juego con sprites dragón encogida a encajar" /> </ p><br /> <H3> enemigos Bouncing </ h3><br /> <P> El movimiento ascendente y descendente de los dragones seguirá a la lógica descrita a continuación. Cuando la fabricación de juegos y la aplicación de la mecánica, es en mi opinión siempre es bueno para delinear y entenderlas bien antes de intentar la aplicación: </ p><br /> <Ul><br /> <Li> Los enemigos tienen una velocidad, un máximo y un mínimo de Vale Y van a llegar (ya tenemos todo esto declarada en init). </ Li><br /> <Li> Queremos aumentar la posición de un enemigo hasta que se alcanza el valor máximo </ li><br /> <Li> A continuación, queremos invertir el movimiento, hasta que se alcanza el valor mínimo </ li><br /> <Li> Cuando se alcanza el valor mínimo, volver a subir .. </ li><br /> </ Ul><br /> <P> Ya que tenemos básicamente una gran variedad de enemigos, vamos a recorrer este array, en <em> actualización </ em>, y aplicar esta lógica movimiento para cada enemigo (nota: <em> velocidad </ em> hasn 't sido declarado todavía, así que asumirá cada enemigo tiene una configuración del valor de esta propiedad): </ p><br /> // el movimiento enemigo dejó enemigos = this.enemies.getChildren (); dejar que numEnemies = enemies.length; para (dejar que i = 0; i <numEnemies; i ++) {// Mover enemigos enemigos [i] .y + = enemigos [i] .speed; // movimiento inverso si alcanzado los bordes si (enemigos [i] .y> = this.enemyMaxY && enemigos [i] .speed> 0) {enemigos [i] .speed * = -1; } Else if (enemigos [i] .y <= this.enemyMinY && enemigos [i] .speed <0) {enemigos [i] .speed * = -1; }} 12345678910111213141516 // enemigas enemigos movementlet = this.enemies.getChildren (); permiten numEnemies = enemies.length; para (leti = 0; i <numEnemies; i ++) {enemiesenemies // movimiento [i] .y + = enemigos [i ] .speed; // movimiento inverso si alcanzado la edgesif (enemigos [i] .y> = this.enemyMaxY && enemigos [i] .speed> 0) {enemigos [i] .speed * = -1;} elseif (enemigos [ i] .y <= this.enemyMinY && enemigos [i] .speed <0) {enemigos [i] .speed * = -1;}} <p> Este código hará que los dragones se mueven hacia arriba y hacia abajo, siempre <em> </ em> se estableció velocidad. Vamos a hacerse cargo de eso ahora. En <em> Crear </ em>, después de escalar nuestros dragones, vamos a dar a cada uno una velocidad aleatorio entre 1 y 2: </ p><br /> // set acelera Phaser.Actions.Call (this.enemies.getChildren (), la función (enemigo) {enemy.speed = Math.random () * 2 + 1;}, este); 1234 // set speedsPhaser.Actions. this.enemies.getChildren llamada ((), función (enemigos) {enemy.speed = Math.random () * 2 + 1;}, this); </p> <ul> <Li> Phaser.Actions.Call nos permite llamar a un método en cada elemento de la matriz. Estamos pasando esto como el contexto (aunque no usarlo). </ Li><br /> </ Ul><br /> <P> Ahora nuestro movimiento hacia arriba y hacia abajo es completa! </ P><br /> <H3> chocan con los enemigos </ h3><br /> <P> Vamos a implementar esta utilizando el mismo enfoque que tomamos para el cofre del tesoro. La prueba de colisión se realizará por cada enemigo. Tiene sentido utilizar el mismo bucle for que ya hemos creado: </ p><br /> // los movimientos del enemigo y de la colisión permiten enemigos = this.enemies.getChildren (); dejar que numEnemies = enemies.length; para (dejar que i = 0; i <numEnemies; i ++) {// Mover enemigos enemigos [i] .y + = enemigos [i] .speed; // movimiento inverso si alcanzado los bordes si (enemigos [i] .y> = this.enemyMaxY && enemigos [i] .speed> 0) {enemigos [i] .speed * = -1; } Else if (enemigos [i] .y <= this.enemyMinY && enemigos [i] .speed <0) {enemigos [i] .speed * = -1; } // enemigo colisión si (Phaser.Geom.Intersects.RectangleToRectangle (this.player.getBounds (), enemigos [i] .getBounds ())) {this.gameOver (); descanso; }} 12345678910111213141516171819202122 // movimiento enemigo y collisionlet enemigos = this.enemies.getChildren (); permiten numEnemies = enemies.length; para (leti = 0; i <numEnemies; i ++) {// movimiento enemiesenemies [i] .y + = enemigos [i] .speed; // movimiento inverso si alcanzado los edgesif (enemigos [i] .y> = this.enemyMaxY && enemigos [i] .speed> 0) {enemigos [i] .speed * = -1;} elseif ( enemigos [i] .y <= this.enemyMinY && enemigos [i] .speed <0) {enemigos [i] .speed * = -1;} // enemigo collisionif (Phaser.Geom.Intersects.RectangleToRectangle (this.player. getBounds (), enemigos [i] .getBounds ())) {this.gameOver (); break;}} <h3> efecto movimiento de la cámara </ h3><br /> <P> Una característica realmente fresca de Phaser 3 es la de efectos de cámara. Nuestro juego se puede jugar, pero será mejor si podemos añadir algún tipo de efecto movimiento de la cámara. Vamos a sustituir <em> gameover </ em> por: </ p><br /> gameScene.gameOver = function () {// mover la cámara this.cameras.main.shake (500); // reinicio juego this.time.delayedCall (500, function () {this.scene.restart ();}, [], este);} 12345678910gameScene.gameOver = function () {// agite el camerathis.cameras.main akeand de .sh (500); // reinicio gamethis.time.delayedCall (500, function () {this.scene.restart ();}, [], este);} </p> <ul> <Li> La cámara se sacudió durante 500 milisegundos </ li><br /> <Li> Después de 500 ms que vuelve a empezar la escena mediante el uso de this.time.delayCall, lo que le permite ejecutar un método después de algún tiempo </ li><br /> </ Ul><br /> <P> <strong> Hay un problema con esta aplicación, se puede adivinar lo que i? </ Strong> </ p><br /> <P> Después de chocar con un enemigo, el <em> gameover </ em> método será llamado muchas veces durante los 500 ms. Necesitamos algún tipo de interruptor de modo que cuando se ejecuta en un dragón, se congela el juego. </ P><br /> <P> Añadir lo siguiente al final de <em> crear </ em> </ p><br /> // jugador está vivo this.isPlayerAlive = true; 12 // jugador es alivethis.isPlayerAlive = true; </p> <p> El código de abajo va en el comienzo mismo de <em> actualización </ em>, por lo que sólo se procesa si el jugador está vivo: </ p><br /> // sólo si el jugador está vivo si (this.isPlayerAlive!) {Return; } // 1234 sólo si el jugador es aliveif (this.isPlayerAlive!) {Return;} </p> <p> Nuestro <em> gameover </ em> Método: </ p><br /> gameScene.gameOver = function () {// bandera de jugador conjunto está muerto this.isPlayerAlive = false; // agite el this.cameras.main.shake cámara (500); // reinicio del juego this.time.delayedCall (500, function () {this.scene.restart ();}, [], este);}; 12345678910111213gameScene.gameOver = function () {// bandera de jugador conjunto es deadthis .isPlayerAlive = false; // sacuden el camerathis.cameras.main.shake (500); // reinicio gamethis.time.delayedCall (500, function () {this.scene.restart ();}, [], esto) ;};. </p> <p> Ahora, el método no se activará muchas veces en una fila </ p><br /> <H3> Desaparición gradual </ h3><br /> <P> Antes de decir adiós vamos a añadir un efecto de desvanecimiento, que comenzará a mitad de camino a través de la reorganización de la cámara: </ p><br /> gameScene.gameOver = function () {// bandera de jugador conjunto está muerto this.isPlayerAlive = false; // agite el this.cameras.main.shake cámara (500); // this.time.delayedCall cámara de fundido (250, function () {this.cameras.main.fade (250);}, [], este); // reinicio del juego this.time.delayedCall (500, function () {this.scene.restart ();}, [], este); }; 1234567891011121314151617181920gameScene.gameOver = function () {// bandera de jugador conjunto es deadthis.isPlayerAlive = false; // agite el camerathis.cameras.main.shake (500); // fade camerathis.time.delayedCall (250, función () {this.cameras.main.fade (250);}, [], este); // reinicio gamethis.time.delayedCall (500, function () {this.scene.restart ();}, [], este);}; </p> <ul> <Li> En el tiempo 250 ms estamos empezando nuestra efecto de fundido, el cual tendrá una duración de 250 ms. </ Li><br /> <Li> Este efecto dejará el negro juego, incluso después de reiniciar nuestra escena, por lo que necesitamos para llamar this.cameras.main.resetFX (); para volver a la normalidad, por eso, añadir esto a la parte inferior del método de crear, o la pantalla permanecerá en negro después de reiniciar la escena: </ li><br /> </ Ul><br /> // cámara de reposición effectsthis.cameras.main.resetFX (); // 12 de la cámara de reposición effectsthis.cameras.main.resetFX (); </p> <p> Eso es todo por este tutorial! Espero que hayas encontrado útil este recurso. </ P><br /> <P> <img src = "http://fymm-rpg.net/wp-content/uploads/phaser-3-tutorial-crossy-rpg.gif" alt = "dragón juego completo de cruce con el jugador y enemigo movimiento" / > </ p><br /> <H3> Mensajes relacionados </ h3><br /> <Img src = "http://fymm-rpg.net/wp-content/uploads/screen-shot-2018-03-26-at-1-20-53-pm-150x150.png" alt = "Phaser 3 , scroll infinito, avión juego de vuelo "/> <img src =" http://fymm-rpg.net/wp-content/uploads/screen-shot-2018-10-28-at-3-13-44-pm -150x150.png "alt = ""/> <img src =" http://fymm-rpg.net/wp-content/uploads/screen-shot-2018-10-28-at-3-13-44- pM-150x150.png" alt = ""/></p> </div><!-- .entry-content --> </div><!-- .post-inner --> <div class="section-inner"> </div><!-- .section-inner --> <div class="comments-wrapper section-inner"> <div id="respond" class="comment-respond"> <h2 id="reply-title" class="comment-reply-title">Deja una respuesta <small><a rel="nofollow" id="cancel-comment-reply-link" href="/172-2/#respond" style="display:none;">Cancelar la respuesta</a></small></h2><form action="http://fymm-rpg.net/wp-comments-post.php" method="post" id="commentform" class="section-inner thin max-percentage" novalidate><p class="comment-notes"><span id="email-notes">Tu dirección de correo electrónico no será publicada.</span> Los campos obligatorios están marcados con <span class="required">*</span></p><p class="comment-form-comment"><label for="comment">Comentario</label> <textarea id="comment" name="comment" cols="45" rows="8" maxlength="65525" required="required"></textarea></p><p class="comment-form-author"><label for="author">Nombre <span class="required">*</span></label> <input id="author" name="author" type="text" value="" size="30" maxlength="245" required='required' /></p> <p class="comment-form-email"><label for="email">Correo electrónico <span class="required">*</span></label> <input id="email" name="email" type="email" value="" size="30" maxlength="100" aria-describedby="email-notes" required='required' /></p> <p class="comment-form-url"><label for="url">Web</label> <input id="url" name="url" type="url" value="" size="30" maxlength="200" /></p> <p class="comment-form-cookies-consent"><input id="wp-comment-cookies-consent" name="wp-comment-cookies-consent" type="checkbox" value="yes" /> <label for="wp-comment-cookies-consent">Guardar mi nombre, correo electrónico y web en este navegador para la próxima vez que comente.</label></p> <p class="form-submit"><input name="submit" type="submit" id="submit" class="submit" value="Publicar el comentario" /> <input type='hidden' name='comment_post_ID' value='172' id='comment_post_ID' /> <input type='hidden' name='comment_parent' id='comment_parent' value='0' /> </p></form> </div><!-- #respond --> </div><!-- .comments-wrapper --> </article><!-- .post --> </main><!-- #site-content --> <div class="footer-nav-widgets-wrapper header-footer-group"> <div class="footer-inner section-inner"> <aside class="footer-widgets-outer-wrapper" role="complementary"> <div class="footer-widgets-wrapper"> <div class="footer-widgets column-one grid-item"> <div class="widget widget_search"><div class="widget-content"><form role="search" method="get" class="search-form" action="http://fymm-rpg.net/"> <label for="search-form-2"> <span class="screen-reader-text">Buscar:</span> <input type="search" id="search-form-2" class="search-field" placeholder="Buscar …" value="" name="s" /> </label> <input type="submit" class="search-submit" value="Buscar" /> </form> </div></div> <div class="widget widget_recent_entries"><div class="widget-content"> <h2 class="widget-title subheading heading-size-3">Entradas recientes</h2> <ul> <li> <a href="http://fymm-rpg.net/2020/09/20/hola-mundo/">¡Hola, mundo!</a> </li> </ul> </div></div><div class="widget widget_recent_comments"><div class="widget-content"><h2 class="widget-title subheading heading-size-3">Comentarios recientes</h2><ul id="recentcomments"><li class="recentcomments"><span class="comment-author-link"><a href='https://wordpress.org/' rel='external nofollow ugc' class='url'>Un comentarista de WordPress</a></span> en <a href="http://fymm-rpg.net/2020/09/20/hola-mundo/#comment-1">¡Hola, mundo!</a></li></ul></div></div> </div> <div class="footer-widgets column-two grid-item"> <div class="widget widget_archive"><div class="widget-content"><h2 class="widget-title subheading heading-size-3">Archivos</h2> <ul> <li><a href='http://fymm-rpg.net/2020/09/'>septiembre 2020</a></li> </ul> </div></div><div class="widget widget_categories"><div class="widget-content"><h2 class="widget-title subheading heading-size-3">Categorías</h2> <ul> <li class="cat-item cat-item-1"><a href="http://fymm-rpg.net/category/sin-categoria/">Sin categoría</a> </li> </ul> </div></div><div class="widget widget_meta"><div class="widget-content"><h2 class="widget-title subheading heading-size-3">Meta</h2> <ul> <li><a href="http://fymm-rpg.net/wp-login.php">Acceder</a></li> <li><a href="http://fymm-rpg.net/feed/">Feed de entradas</a></li> <li><a href="http://fymm-rpg.net/comments/feed/">Feed de comentarios</a></li> <li><a href="https://es.wordpress.org/">WordPress.org</a></li> </ul> </div></div> </div> </div><!-- .footer-widgets-wrapper --> </aside><!-- .footer-widgets-outer-wrapper --> </div><!-- .footer-inner --> </div><!-- .footer-nav-widgets-wrapper --> <footer id="site-footer" role="contentinfo" class="header-footer-group"> <div class="section-inner"> <div class="footer-credits"> <p class="footer-copyright">© 2020 <a href="http://fymm-rpg.net/">Rpg Dev</a> </p><!-- .footer-copyright --> <p class="powered-by-wordpress"> <a href="https://es.wordpress.org/"> Funciona con WordPress </a> </p><!-- .powered-by-wordpress --> </div><!-- .footer-credits --> <a class="to-the-top" href="#site-header"> <span class="to-the-top-long"> Ir arriba <span class="arrow" aria-hidden="true">↑</span> </span><!-- .to-the-top-long --> <span class="to-the-top-short"> Subir <span class="arrow" aria-hidden="true">↑</span> </span><!-- .to-the-top-short --> </a><!-- .to-the-top --> </div><!-- .section-inner --> </footer><!-- #site-footer --> <script src='http://fymm-rpg.net/wp-includes/js/comment-reply.min.js?ver=5.4.3'></script> <script src='http://fymm-rpg.net/wp-includes/js/wp-embed.min.js?ver=5.4.3'></script> <script> /(trident|msie)/i.test(navigator.userAgent)&&document.getElementById&&window.addEventListener&&window.addEventListener("hashchange",function(){var t,e=location.hash.substring(1);/^[A-z0-9_-]+$/.test(e)&&(t=document.getElementById(e))&&(/^(?:a|select|input|button|textarea)$/i.test(t.tagName)||(t.tabIndex=-1),t.focus())},!1); </script> </body> </html>