Crear juego con Javascript

En este artículo, vamos a adentrarnos en el desarrollo de videojuegos con uno de los lenguajes más utilizados en la actualidad, Javascript. Haremos uso del framework Phaser, con el que podremos crear juegos con html y javascript, que pueden ser ejecutados en navegadores, móviles y escritorios.

Estructura y puesta en marcha de nuestro proyecto

Puedes descargarte nuestro proyecto, dónde encontraras las imagenes y script utilizamos en este enlace: descargar proyecto.

Para comenzar, haremos uso del editor que queramos y un servidor local para correr nuestra aplicación como si fuera una web. La estructura que tendrá nuestro proyecto, será la siguiente:

  • Index.html: Este archivo estará en la raíz de nuestro proyecto y será dónde se cargará nuestro juego.
  • src: En esta carpeta, que también se encuentra en la raiz de nuestro proyecto, junto a index.html, guardaremos las imágenes y js que utilizaremos.
  • img: Contedra el background y los sprites (las imagens del personaje que vamos a crear) de nuestro juego.
  • js: En esta carpeta tendremos el archivo js del framework, junto al estado de nuestro juego y el archivo main.js que veremos más adelante.

Desarrollando nuestro juego

index.html

Como hemos dicho anteriormente, aquí es donde se cargará nuestro juego, para ello, lo único que vamos a hacer será añadir la referencia a los archivos .js que utilizaremos:

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Nigmagame</title>
</head>
<body>
    <script src="src/js/phaser.min.js"></script>
    <script src="src/js/main.js"></script>
    <script src="src/js/stateMain.js"></script>    
</body>
</html>

main.js

En este archivo, vamos a dirigir la estructura de nuestro juego, es decir, le daremos un ancho y un largo a nuestro juego, añadiremos los estados de éste y además le indicaremos el estado con el que arrancará la aplicación:

var game;

window.onload = function () {
    game = new Phaser.Game(960, 480, Phaser.AUTO);

    game.state.add("StateMain", StateMain);
    game.state.start("StateMain");
}

stateMain.js

Y en este archivo, es dónde comenzaremos con el desarrollo de nuestro juego, con la lógica de la pantalla. stateMain será nuestro estado principal, los juego se componen de estados (pantallas), como por ejemplo, el estado de menu, el estado de game over, etc. Al ser éste un artículo de introducción trabajaremos con un solo estado, que será el propio juego.

Para comenzar, crearemos StateMain que contendra una serie de funciones que utilizaremos para diferentes tareas en nuestro juego:

preload: se precargará el contenido de nuestro juego. (cargaremos las imágenes de nuestro background, de nuestro personaje…)

create: Haremos uso del contenido precargado para ponerlo en nuestro juego (background en el fondo, dónde colocamos a nuestra personaje al inicio, la física del juego, etc)

update: Esta función se ejecutará en cada frame del juego, añadiremos por ejemplo el control de nuestro personaje, indicándole que hace un botón en concreto… es decir, las interacciones de los objetos.

Y vamos a añadir, una función speed, antes de update, que utilizaremos en update. La función speed no es una función predefinida por el framework, si no que la hemos creado para darle una lógica al juego, y como ésta, podemos crear más funciones y con el nombre que queramos.

var StateMain={
    preload:function(){

    },
    create:function(){ 

    },
    speed:function(){

    },
    update:function(){

    }
}

función preload: Cargando nuestras imagenes

En la función preload, como ya hemos dicho, vamos a poner a nuestra disposición las imagenes que tendrá nuestro juego. Vamos a precargar el background y nuestro sprite.

preload:function(){
     game.load.image("background", "src/img/background.png");
     game.load.spritesheet("plane", "src/img/plane/plane.png", 445, 285, 2);
},

Para ello, hacemos uso de la variable game, que la creamos en nuestro archivo main.js.

  • En la primera linea, cargamos nuestro background y añadimos dos parametros, el primero sería el nombre que vamos a utilizar para llamar a esta imagen en el juego y el segundo sería la ruta dónde se encuentra nuestra imagen en el proyecto.
  • En la segunda linea, añadimos con la función spritesheet, el sprite de nuestro personaje, y su ruta, pero aparte, añadimos 3 parametros más. El pirmer parametro indica el ancho que tiene cada sprite en nuestra imagen, el segundo, la altura y el tercero, el número de sprite que tiene nuestra imagen.

Como podemos ver, en la imagen de nuestros sprite, tenemos dos sprites y le indicamos, que la dimensión de cada uno es de 445×285. 

Función create: Añadiendo nuestros sprites y sus propiedades

Antes de comenzar con esta función, que es dónde veremos más contenido, debemos entender como funciona la escena de nuestros juegos.

Al ser un juego en 2D, tenemos dos coordenadas, que serían X (ANCHO DE LA PANTALLA) e Y (ALTURA DE LA PANTALLA).

En la esquina superior izquierda, vemos 0, 0, esta sería la posición 0 X y 0 Y. Es decir, si queremos que nuestro personaje este más hacia la derecha, deberíamos aumentar su X y de la misma forma, si queremos que nuestro personaje este más abajo, deberíamos aumentar la Y.

Ahora que sabemos esto, podemos comenzar a ver nuestra función create:

game.physics.startSystem(Phaser.Physics.ARCADE);

Primero, añadiriamos esta línea, que activa la fisica en nuestro juego, para que nuestro juego tenga gravedad.

this.background = game.add.tileSprite(0, 0,game.width, game.height, 'background');

Añadimos el background, diciendole que ocupe el ancho y el alto de la pantalla, y por ultimo el nombre de nuestro background definido en la función preload.

this.plane = game.add.sprite(50,0, "plane");

Creamos una variable plane, para poder acceder a las propiedades de nuestro personaje, le añadimos la coordenada X e Y donde queramos que aparezca y el nombre que le añadimos en preload.

this.plane.scale.setTo(0.4)

Ahora, con esta propiedad, escalamos nuestra imagen de nuestro personaje para que se más pequeña, por ejemplo, 0.5 sería la mitad de su tamaño real.

this.plane.animations.add('fly', [0,1], 1, true);

Aqui, le añadimos una animación, que será la que vaya cambiando con el 1º y 2º sprite para dar un efecto de rotación de la hélice de la avioneta.

  • El primer parametro es el nombre de la animacion que crearemos.
  • Después un array la posición de la imagen, donde 0 es la primera y 1 la segunda.
  • El tercer parametro es la velocidad de frame que queremos que vaya cambiando.
  • Y por último, si queremos que la imagen vaya cambiando en bucle.
this.plane.animations.play('fly');

en esta linea activamos la animación para que empiece desde el principio.

this.background.autoScroll(-100, 0);

 con la función autoscroll lo que hacemos es que la imagen del background tenga un efecto de movimiento y lo que hacemos es restarle -100 a X.

game.physics.enable([this.plane], Phaser.Physics.ARCADE);

En esta linea, indicamos que queremos que le afecte la gravedad a nuestro sprite.

función speed: añadiendo movimiento a nuestro personaje

Como hemos dicho antes, esta función no es del framework, si no que la hemos creado nosotros, y como ésta podemos crear más con en nombre que queramos.

Bien, speed la vamos a utilizar en la función update, para que nuestro personaje pueda volar, para ello vamos a añadirle esta linea a nuestra función speed:

this.plane.body.velocity.y = -300;

Como vemos, lo que hará esta función, es modificar la velocidad de la Y en nuestro personaje. Cuando arranquemos el juego, nuestro personaje por la gravedad irá hacia abajo, esto significa que su posición Y se irá incrementando, con esta función lo que hacemos es que nuestro personaje haga una especie de salto cuando se active.

Ahora vamos a aprender como activarla en nuestro juego, en la función update.

Funcion update: La lógica de nuestro juego

Esta función se va a ejecutar por frame en nuestro juego, por lo que se ejecutará todo en bucle, una y otra vez en milésimas de segundos.

Añadimos estás lineas de código:

if(game.input.activePointer.isDown){
   this.speed();
}
this.plane.body.gravity.y = 500;

En la condición del if, le estamos indicando, que si hacemos un click con nuestro ratón, se ejecutará la función speed y en la siguiente linea, le damos una gravedad en la posición Y de 500.

¡De esta forma ya podríamos probar nuestro juego!

Pero podemos mejorarlo un poco más, ya que cuando llega tanto arriba como abajo, nuestro personaje desaparece.

Pequeñas mejoras en nuestro juego.

Vamos a bloquear a nuestro personaje tanto la parte superior de arriba como la de abajo, para que siempre este visible en pantalla, 

Para ello añadiremos estas variables a nuestra función create:

this.bottom= game.height-120;
this.top = 0;

y en la función update, modificaremos nuestro código anterior, por este:

update:function(){
        if(game.input.activePointer.isDown){
            this.speed();
        }
        if(this.plane.y < this.top){
            this.plane.y = this.top;
            this.plane.body.gravity.y = 0;
        }
        if(this.plane.y > this.bottom){
            this.plane.y = this.bottom;
            this.plane.body.gravity.y = 0;
        }else{
            this.plane.body.gravity.y = 500;
        }
    }

Aquí, veremos nuevas condiciones:

  • La primera, es la que ya hemos explicado anterormente, si clickamos, se ejecuta la función speed.
  • la segunda, contra la posición y de nuestro personaje y si es menos que la variable top (que hemos incializado a 0), significaría que nuestro personaje esta apunto de salirse de la pantalla hacía arriba, entonces lo bloquemaos dandole la posición 0 todo el tiempo, hasta que se deje de cumplir la condicion (es decir, que este por debajo del limite)
  • La tercera condición, bloquea al personaje para que no pueda irse más abajo del juego, de la misma forma inicializamos su posición Y a la de la variable bottom, pero esta, queda más arriba que el limite ya que le hemos restado 160 en su inicialización. También le inicializamos su gravedad a 0.
  • Y la 4 condición sería si se encontrase dentro de la pantalla, dónde su gravedad será la que debe tener en todo el juego.

Si os ha gustado este artículo de introducción, hacédnoslo saber y seguiremos con este framework!!