Últimos retoques y código completo
Antes de finalizar, vamos a darle al juego otro aspecto visual en cuanto a menús, fuentes, etc.
Para ello, descárgate las imágenes necesarias haciendo clic AQUÍ y cópialas en la carpeta juegoknights/img.
Además, vamos a aprovechar para implementar el resto de estados y resolver algunos bugs:




- Apagar sonidos al cambiar de estado
- Cambiar los controles desde el menú de opciones
- Salir del juego desde el menú de opciones
index.html
<!DOCTYPE html>
<html>
<head>
<title>Juego Phaser</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="css/style.css">
<script type="text/javascript" src="js/phaser.min.js"></script>
<script type="text/javascript" src="js/estadoInicio.js"></script>
<script type="text/javascript" src="js/estadoOpciones.js"></script>
<script type="text/javascript" src="js/estadoJugar.js"></script>
<script type="text/javascript" src="js/estadoSalir.js"></script>
<script type="text/javascript" src="js/script.js"></script>
</head>
<body>
</body>
</html>
style.css
body{
text-align: center;
background-color: #000;
}
canvas{
margin: 3em auto;
}
script.js
//Variable juego
var juego = new Phaser.Game(800, 600);
//Controles por defecto (que se pueden cambir en opciones)
var controles = "flechas";
//Creador de estados
juego.state.add('EstadoInicio', MiJuego.EstadoInicio);
juego.state.add('EstadoOpciones', MiJuego.EstadoOpciones);
juego.state.add('EstadoJugar', MiJuego.EstadoJugar);
juego.state.add('EstadoSalir', MiJuego.EstadoSalir);
//Inicio el estado por defecto
juego.state.start('EstadoInicio');
estadoInicio.js
//Variable MiJuego
var MiJuego = {};
//Inicializo la función EstadoInicio vacía
MiJuego.EstadoInicio = function (juego) {
};
//Este es el prototipo o "plantilla" que se cargará cada vez que inicialice una nueva función MiJuego.EstadoInicio
MiJuego.EstadoInicio.prototype = {
preload: function () {
//Imagen de fondo y título
this.load.image('fondo', 'img/fondo.png');
this.load.image('titulo', 'img/titulo.png');
//Imagenes para los botones
this.load.spritesheet('botonInicio', 'img/botonInicio.png', 104, 19);
this.load.spritesheet('botonOpciones', 'img/botonOpciones.png', 137, 19);
this.load.spritesheet('botonJugar', 'img/botonJugar.png', 104, 19);
this.load.spritesheet('botonSalir', 'img/botonSalir.png', 104, 19);
},
create: function () {
//Dibujo el fondo y el título
juego.add.sprite(0, 0, 'fondo');
juego.add.sprite(171, 225, 'titulo');
//Creo el menú de botones
crearMenu();
},
};
function crearMenu(){
//Creo un grupo para el menú
menu = juego.add.group();
//Añado los cuatro botones al menú
this.botonInicio = juego.make.button(105, 30, 'botonInicio', cambiarEstado, this, 2, 1, 0); //over, out, pressed
menu.add(this.botonInicio);
this.botonOpciones = juego.make.button(260, 31, 'botonOpciones', cambiarEstado, this, 2, 1, 0);
menu.add(this.botonOpciones);
this.botonJugar = juego.make.button(450, 31, 'botonJugar', cambiarEstado, this, 2, 1, 0);
menu.add(this.botonJugar);
this.botonSalir = juego.make.button(600, 31, 'botonSalir', cambiarEstado, this, 2, 1, 0);
menu.add(this.botonSalir);
//Fijo los botones para que no se muevan al moverse la cámara
menu.fixedToCamera = true;
}
function cambiarEstado(item){
//Cambio el estado al hacr clic en un botón
this.estado = 'Estado'+item.key.substr(5);
juego.state.start(this.estado);
//Si no es EstadoJugar paro la música
if (this.estado !== "EstadoJugar"){
juego.sound.stopAll();
}
}
estadoOpciones.js
MiJuego.EstadoOpciones = function (juego) {
};
MiJuego.EstadoOpciones.prototype = {
preload: function () {
//Fondo y textos
this.load.image('fondo', 'img/fondo.png');
this.load.image('controles', 'img/controles.png');
this.load.spritesheet('flechas', 'img/flechas.png', 125, 18);
this.load.spritesheet('aswd', 'img/aswd.png', 84, 17);
},
create: function () {
//Dibujo el fondo
juego.add.sprite(0, 0, 'fondo');
//Menú Botones
crearMenu();
//Texto
juego.add.sprite(300, 225, 'controles');
//Menú opciones
opciones = juego.add.group();
//Añado los dos botones al menú
this.botonFlechas = juego.make.button(250, 300, 'flechas', cambiarControles, this, 2, 1, 0); //over, out, pressed
opciones.add(this.botonFlechas);
this.botonAswd = juego.make.button(450, 300, 'aswd', cambiarControles, this, 2, 1, 0); //over, out, pressed
opciones.add(this.botonAswd);
}
};
function cambiarControles(item){
//Cambio los controles al hacer clic en un botón y vuelvo al estado jugar
controles = item.key;
juego.state.start("EstadoJugar");
}
estadoSalir.js
MiJuego.EstadoSalir = function (juego) {
};
MiJuego.EstadoSalir.prototype = {
preload: function () {
//Fondo y textos
this.load.image('fondo', 'img/fondo.png');
this.load.image('texto', 'img/textoConfirmacion.png');
this.load.spritesheet('si', 'img/si.png', 22, 17);
this.load.spritesheet('no', 'img/no.png', 40, 16);
},
create: function () {
//Dibujo el fondo
juego.add.sprite(0, 0, 'fondo');
//Menú Botones
crearMenu();
//Texto
juego.add.sprite(142, 225, 'texto');
//Menú salir
salir = juego.add.group();
//Añado los dos botones al menú
this.botonSi = juego.make.button(300, 300, 'si', accionSalir, this, 2, 1, 0); //over, out, pressed
salir.add(this.botonSi);
this.botonNo = juego.make.button(450, 300, 'no', accionSalir, this, 2, 1, 0); //over, out, pressed
salir.add(this.botonNo);
}
};
function accionSalir(item){
//Salgo a inicio o vuelvo al juego
if (item.key == 'si'){
juego.state.start("EstadoInicio");
}
else{
juego.state.start("EstadoJugar");
}
}
estadoJugar.js
MiJuego.EstadoJugar = function (juego) {
};
MiJuego.EstadoJugar.prototype = {
preload: function () {
//Imágenes para los mapas
this.load.image('piedra', 'img/piedra.png');
this.load.image('metal', 'img/metal.png');
this.load.image('madera', 'img/madera.png');
//Archivo JSON de mapa
this.load.tilemap('mapa', 'maps/mapaknights.json', null, Phaser.Tilemap.TILED_JSON);
//Imágenes adicionales
juego.load.spritesheet('gema', 'img/gemas.png', 16, 15);
this.load.image('trampa', 'img/trampa.png');
this.load.image('plataforma', 'img/plataforma.png');
this.load.image('pastilla', 'img/pastilla.png');
//Imágenes información
this.load.image('textoVidas', 'img/textoVidas.png');
this.load.image('textoGemas', 'img/textoGemas.png');
//Jugador
juego.load.spritesheet('blueKnight', 'img/blueKnight.png', 50, 50);
//Dirección
this.direccion = "Derecha";
this.direccionPlataforma = 1;
//Potencia
this.potencia = -150;
//Cantidad
this.cantidadGemas = 15;
this.infoGema = new Array();
//Vidas
this.vidas = 2;
this.infoVida = new Array();
//Movimiento
this.movimiento = 1;
//Audios
this.load.audio('musica', 'audio/musica.mp3');
this.load.audio('gema', 'audio/gema.mp3');
this.load.audio('vida', 'audio/vida.mp3');
this.load.audio('ganar', 'audio/ganar.mp3');
this.load.audio('morir', 'audio/morir.mp3');
},
create: function () {
//Establezco los límites del juego (el tamaño de los mapas en este caso)
juego.world.setBounds(0, 0, 1600, 640);
juego.stage.smoothed = true;
//Habilitamos el sistema de física Arcade de Phaser (velocidad, movimientos, colisiones, etc)
juego.physics.startSystem(Phaser.Physics.ARCADE);
//Mapa
this.mapa = this.add.tilemap('mapa');
//Tilesets para el mapa
this.mapa.addTilesetImage('piedra');
this.mapa.addTilesetImage('madera');
this.mapa.addTilesetImage('metal');
//Capas
this.fondo = this.mapa.createLayer('fondo');
this.adornos = this.mapa.createLayer('adornos');
this.lamparas = this.mapa.createLayer('lamparas');
this.suelo = this.mapa.createLayer('suelo');
this.paredes = this.mapa.createLayer('paredes');
//Gemas
this.gemas = juego.add.group();
this.gemas.enableBody = true;
this.mapa.createFromObjects('gemas', 'gema', 'gema', 0, true, false, this.gemas);
this.gemas.callAll('animations.add', 'animations', 'girar', [0, 1, 2, 3, 4, 5, 6], 10, true);
this.gemas.callAll('animations.play', 'animations', 'girar');
//Trampas
this.trampas = juego.add.group();
this.trampas.enableBody = true;
this.mapa.createFromObjects('trampas', 'trampa', 'trampa', 0, true, false, this.trampas);
//Blue Knight
this.blueKnight = juego.add.sprite(50, juego.world.height - 100, 'blueKnight');
juego.physics.arcade.enable(this.blueKnight);
this.blueKnight.anchor.setTo(0.5,0.5);
this.blueKnight.body.gravity.y = 800;
this.blueKnight.body.bounce.y = 0.2;
this.blueKnight.body.setCircle(25,0,0);
this.blueKnight.scale.set(0.75);
//Animaciones derecha
this.blueKnight.animations.add('andarDerecha', [1, 2, 3, 4, 5, 6], 10, true);
this.blueKnight.animations.add('ataque1Derecha', [7, 8], 10, true);
this.blueKnight.animations.add('ataque2Derecha', [9, 10], 10, true);
this.blueKnight.animations.add('ataqueAbajoDerecha', [11, 12], 10, true);
this.blueKnight.animations.add('saltarDerecha', [13, 14], 10, true);
this.blueKnight.animations.add('agacharseDerecha', [15, 16], 10, true);
this.blueKnight.animations.add('ganarDerecha', [17, 18], 10, true);
this.blueKnight.animations.add('vidaDerecha', [19, 20, 21, 22], 10, true);
this.blueKnight.animations.add('morirDerecha', [23, 24, 25, 26, 27], 5, false);
//Animaciones izquierda
this.blueKnight.animations.add('andarIzquierda', [29, 30, 31, 32, 33, 34], 10, true);
this.blueKnight.animations.add('ataque1Izquierda', [35, 36], 10, true);
this.blueKnight.animations.add('ataque2Izquierda', [37, 38], 10, true);
this.blueKnight.animations.add('ataqueAbajoIzquierda', [39, 40], 10, true);
this.blueKnight.animations.add('saltarIzquierda', [41, 42], 10, true);
this.blueKnight.animations.add('agacharseIzquierda', [43, 44], 10, true);
this.blueKnight.animations.add('ganarIzquierda', [45, 46], 10, true);
this.blueKnight.animations.add('vidaIzquierda', [47, 48, 49, 50], 10, true);
this.blueKnight.animations.add('morirIzquierda', [51, 52, 53, 54, 55], 5, false);
//Inicializo el movimiento de los cursores
if (controles == 'flechas'){
this.cursoresBlue = juego.input.keyboard.addKeys({
left: Phaser.KeyCode.LEFT,
right: Phaser.KeyCode.RIGHT,
up: Phaser.KeyCode.UP,
down: Phaser.KeyCode.DOWN,
});
}
else{
this.cursoresBlue = juego.input.keyboard.addKeys({
left: Phaser.KeyCode.A,
right: Phaser.KeyCode.D,
up: Phaser.KeyCode.W,
down: Phaser.KeyCode.S,
});
}
//Cámara
juego.camera.follow(this.blueKnight);
//Pastilla para resaltar el menú
this.pastilla = juego.add.sprite(100, 20, 'pastilla');
this.pastilla.alpha = 0.5;
this.pastilla.fixedToCamera = true;
//Menú
crearMenu();
//Colisiones del suelo
this.mapa.setCollisionByExclusion([0],true,'suelo');
this.suelo.enableBody = true;
//Colisiones de las paredes
this.mapa.setCollisionByExclusion([0],true,'paredes');
this.paredes.enableBody = true;
//Plataforma oculta
this.plataforma = juego.add.sprite(1200, 300, 'plataforma');
juego.physics.arcade.enable(this.plataforma);
this.plataforma.body.immovable = true;
this.plataforma.visible = false;
//Audio de fondo
this.audioMusica = juego.add.audio('musica');
this.audioMusica.loopFull(0.2);
this.audioMusica.play();
//Audios de acciones
this.audioGema = juego.add.audio('gema');
this.audioVida = juego.add.audio('vida');
this.audioGanar = juego.add.audio('ganar');
this.audioMorir = juego.add.audio('morir');
//Menú info
this.info = juego.add.group();
this.info.fixedToCamera = true;
this.info.create(110, 65, 'textoVidas');
this.info.create(310, 65, 'textoGemas');
this.infoVidas();
this.infoGemas();
},
update: function () {
//Colisiones
this.colisionSuelo = juego.physics.arcade.collide(this.blueKnight, this.suelo);
this.colisionParedes = juego.physics.arcade.collide(this.blueKnight, this.paredes);
this.colisionPlataforma = juego.physics.arcade.collide(this.blueKnight, this.plataforma);
//Gemas
juego.physics.arcade.overlap(this.blueKnight, this.gemas, this.recogerGema, null, this);
//Trampas
juego.physics.arcade.overlap(this.blueKnight, this.trampas, this.caidaEnTrampa, null, this);
//Movimiento (Solo si no está en una trampa)
if (this.movimiento == 1){
this.movimientoBlue();
}
//Ganar
if (this.cantidadGemas == 0) {
this.ganar();
}
//Mover plataforma
if (this.cantidadGemas <= 7){
this.plataforma.visible = true;
this.movimientoPlataforma();
}
//Caer al vacío por abajo y morir
if (this.blueKnight.y >= 640){
this.caer();
}
},
movimientoBlue: function () {
//Reseteo la velocidad del jugador y frame quieto
this.blueKnight.body.velocity.x = 0;
//Mover a la izquierda
if (this.cursoresBlue.left.isDown) {
this.direccionBlue = "Izquierda";
this.blueKnight.body.velocity.x = -200;
this.blueKnight.animations.play('andar' + this.direccionBlue);
}
//Mover a la derecha
else if (this.cursoresBlue.right.isDown) {
this.direccionBlue = "Derecha";
this.blueKnight.body.velocity.x = 200;
this.blueKnight.animations.play('andar'+this.direccionBlue);
}
//Quedarse quieto
else {
this.blueKnight.animations.stop();
//Compruebo dirección para mostrar el frame correspondiente
if (this.direccionBlue == "Izquierda"){
this.blueKnight.frame = 28;
}
else{
this.blueKnight.frame = 0;
}
}
//Saltar
if (this.cursoresBlue.up.isDown && this.colisionSuelo && !this.colisionParedes){
this.blueKnight.animations.play('saltar'+this.direccionBlue);
this.blueKnight.body.velocity.y = this.potencia;
}
//Saltar plataforma
if (this.cursoresBlue.up.isDown && this.colisionPlataforma){
this.blueKnight.animations.play('saltar'+this.direccionBlue);
this.blueKnight.body.velocity.y = this.potencia;
}
//Agacharse
if (this.cursoresBlue.down.isDown){
this.blueKnight.animations.play('agacharse'+this.direccionBlue);
}
},
recogerGema: function (knight, gema) {
gema.kill();
this.audioGema.play(); //Reproduzco sonido
this.potencia -= 25;
this.cantidadGemas--;
this.infoGema[this.cantidadGemas].kill(); //Borro la info de gema
},
caidaEnTrampa: function (knight, trampa) {
//Le obligo a pararse
this.movimiento = 0;
this.blueKnight.body.velocity.x = 0;
//Animación de quitar vida
this.blueKnight.animations.play('vida' + this.direccionBlue);
this.audioVida.play(); //Reproduzco sonido
//Elimino trampa
trampa.kill();
//Quito vida (después de 1 segundo de animación)
juego.time.events.add(Phaser.Timer.SECOND * 1, this.quitarVida, this);
},
quitarVida: function () {
this.vidas --; //Resto una vida
if (this.vidas >= 0){ //Continuar con una vida menos
this.infoVida[this.vidas].kill(); //Borro la info de vida
this.movimiento = 1; //Permito seguir
}
else{ //Morir
this.audioMorir.play(); //Reproduzco sonido
this.audioMusica.fadeOut(4000); //Fade out música
this.blueKnight.animations.play('morir' + this.direccionBlue); //Animación morir
this.audioMorir.stop(); //Reproduzco sonido
}
},
movimientoPlataforma: function () {
//Alterno movimiento arriba y abajo
if (this.plataforma.y == 520){
this.direccionPlataforma = -1
}
if (this.plataforma.y == 200){
this.direccionPlataforma = 1
}
this.plataforma.y += this.direccionPlataforma;
},
ganar: function () {
//Le obligo a pararse
this.movimiento = 0;
this.blueKnight.body.velocity.x = 0;
this.audioGanar.play(); //Reproduzco sonido
this.audioMusica.fadeOut(4000); //Fade out música
this.audioGanar.stop(); //Reproduzco sonido
this.blueKnight.animations.play('ganar' + this.direccionBlue); //Animación de ganar
},
infoVidas: function () {
//Vidas
for (var i=0; i<this.vidas; i++){
var x = 20 * i;
this.infoVida[i] = this.info.create(180 + x, 50, 'blueKnight');
this.infoVida[i].scale.set(0.60);
}
},
infoGemas: function () {
//Gemas
for (var i=0; i<this.cantidadGemas; i++){
var x = 20 * i;
this.infoGema[i] = this.info.create(395 + x, 62, 'gema');
this.infoGema[i].scale.set(0.90);
}
},
caer: function () {
//Quito las vidas
this.vidas = 0;
this.infoVida[0].kill();
this.infoVida[1].kill();
//Muero
this.movimiento = 0;
this.audioMorir.play(); //Reproduzco sonido
this.audioMusica.fadeOut(2000); //Fade out música
this.audioMorir.stop(); //Reproduzco sonido
},
};
El resultado final del juego debería ser similar al siguiente:



