Guardar y cargar el estado del juego es una característica fundamental para ofrecer una buena experiencia al jugador. Permite pausar y continuar partidas, guardar progresos y mantener configuraciones personalizadas. En esta lección aprenderás los conceptos clave, técnicas y ejemplos prácticos para implementar guardado y carga de estado en tus juegos con Phaser.


Conceptos Clave

  • Estado del juego: Conjunto de variables y datos que representan el progreso y la configuración actual del juego (puntuación, nivel, posición de personajes, inventario, etc.).
  • Persistencia: Capacidad de almacenar datos más allá de la sesión actual del juego, permitiendo recuperarlos después de cerrar y volver a abrir el juego.
  • Almacenamiento local (localStorage): Mecanismo del navegador para guardar datos de manera sencilla y persistente en el dispositivo del usuario.
  • Serialización: Proceso de convertir objetos y estructuras de datos en un formato que pueda ser almacenado (por ejemplo, JSON).

Métodos Comunes para Guardar Estado

Método Ventajas Desventajas Uso en Phaser
localStorage Fácil de usar, persistente, sin servidor Limitado (~5MB), solo texto Muy común
sessionStorage Similar a localStorage, pero temporal Se borra al cerrar el navegador Menos usado
Servidor remoto Sin límite de espacio, multi-dispositivo Requiere backend y autenticación Juegos multijugador
Cookies Persistente, pero muy limitado Espacio muy reducido, inseguro Poco recomendable

En este módulo nos centraremos en localStorage, por ser el método más sencillo y ampliamente soportado para juegos web hechos con Phaser.


¿Qué Debo Guardar?

Algunos ejemplos de datos que puedes querer guardar:

  • Puntuación actual y máxima
  • Nivel alcanzado
  • Posición y estado de los personajes
  • Inventario de objetos
  • Configuración de sonido y controles

Guardando el Estado del Juego con localStorage

  1. Serializar el Estado

Para guardar el estado, primero debes convertir tus datos a una cadena de texto (usualmente JSON):

const gameState = {
  score: 1500,
  level: 3,
  player: {
    x: 120,
    y: 250,
    health: 80
  },
  inventory: ['llave', 'poción']
};

const gameStateString = JSON.stringify(gameState);

Explicación:

  • JSON.stringify() convierte el objeto gameState en una cadena de texto que puede almacenarse fácilmente.

  1. Guardar en localStorage

localStorage.setItem('miJuego_estado', gameStateString);

Explicación:

  • localStorage.setItem(clave, valor) guarda la cadena bajo la clave especificada.
  • En este caso, la clave es 'miJuego_estado'.

  1. Cargar el Estado Guardado

const savedStateString = localStorage.getItem('miJuego_estado');
if (savedStateString) {
  const savedState = JSON.parse(savedStateString);
  // Ahora puedes usar savedState para restaurar el juego
}

Explicación:

  • localStorage.getItem(clave) recupera la cadena guardada.
  • JSON.parse() convierte la cadena de vuelta a un objeto JavaScript.

  1. Integración Básica en Phaser

Supón que quieres guardar el estado cuando el jugador presiona la tecla "G" y cargarlo con la tecla "C":

class MyGameScene extends Phaser.Scene {
  constructor() {
    super('MyGameScene');
    this.player = null;
    this.score = 0;
    this.level = 1;
  }

  create() {
    // ... inicialización de jugador, enemigos, etc.

    this.input.keyboard.on('keydown-G', () => {
      this.saveGameState();
    });

    this.input.keyboard.on('keydown-C', () => {
      this.loadGameState();
    });
  }

  saveGameState() {
    const state = {
      score: this.score,
      level: this.level,
      player: {
        x: this.player.x,
        y: this.player.y
      }
    };
    localStorage.setItem('miJuego_estado', JSON.stringify(state));
    console.log('Juego guardado');
  }

  loadGameState() {
    const saved = localStorage.getItem('miJuego_estado');
    if (saved) {
      const state = JSON.parse(saved);
      this.score = state.score;
      this.level = state.level;
      this.player.setPosition(state.player.x, state.player.y);
      console.log('Juego cargado');
    } else {
      console.log('No hay estado guardado');
    }
  }
}

Explicación paso a paso:

  • Se definen métodos saveGameState y loadGameState en la escena.
  • Se usan eventos de teclado para disparar el guardado y la carga.
  • Al guardar, se toma el estado relevante y se almacena en localStorage.
  • Al cargar, se recupera el estado y se actualizan las variables y la posición del jugador.

Ejercicio Práctico

Objetivo:
Implementa el guardado y la carga de la puntuación y la posición del jugador en un juego sencillo de Phaser.

Instrucciones

  1. Crea una escena con un sprite de jugador que pueda moverse con las flechas.
  2. Añade una variable de puntuación que aumente cada vez que el jugador presione la barra espaciadora.
  3. Implementa las funciones para guardar y cargar el estado usando localStorage.
  4. Usa las teclas "G" para guardar y "C" para cargar.

Código Base

class MainScene extends Phaser.Scene {
  constructor() {
    super('MainScene');
    this.player = null;
    this.score = 0;
    this.scoreText = null;
  }

  preload() {
    this.load.image('player', 'ruta/a/tu/sprite.png');
  }

  create() {
    this.player = this.add.sprite(100, 100, 'player');
    this.scoreText = this.add.text(10, 10, 'Puntuación: 0', { fontSize: '16px', fill: '#fff' });

    this.cursors = this.input.keyboard.createCursorKeys();

    this.input.keyboard.on('keydown-SPACE', () => {
      this.score += 10;
      this.scoreText.setText('Puntuación: ' + this.score);
    });

    this.input.keyboard.on('keydown-G', () => this.saveGameState());
    this.input.keyboard.on('keydown-C', () => this.loadGameState());
  }

  update() {
    if (this.cursors.left.isDown) this.player.x -= 2;
    if (this.cursors.right.isDown) this.player.x += 2;
    if (this.cursors.up.isDown) this.player.y -= 2;
    if (this.cursors.down.isDown) this.player.y += 2;
  }

  saveGameState() {
    const state = {
      score: this.score,
      player: { x: this.player.x, y: this.player.y }
    };
    localStorage.setItem('miJuego_estado', JSON.stringify(state));
    this.scoreText.setText('Puntuación: ' + this.score + ' (Guardado)');
  }

  loadGameState() {
    const saved = localStorage.getItem('miJuego_estado');
    if (saved) {
      const state = JSON.parse(saved);
      this.score = state.score;
      this.player.setPosition(state.player.x, state.player.y);
      this.scoreText.setText('Puntuación: ' + this.score + ' (Cargado)');
    } else {
      this.scoreText.setText('No hay estado guardado');
    }
  }
}

Solución y Consejos

  • Solución: El código anterior cumple con todos los requisitos del ejercicio.
  • Errores comunes:
    • Olvidar convertir el objeto a JSON antes de guardarlo.
    • No comprobar si existe un estado guardado antes de intentar cargarlo.
    • No actualizar la interfaz de usuario después de cargar el estado.
  • Consejo: Siempre maneja posibles errores usando condicionales y muestra mensajes claros al usuario.

Resumen

  • Guardar y cargar el estado del juego es esencial para la experiencia del usuario.
  • localStorage es la forma más sencilla y efectiva de implementar persistencia en juegos web con Phaser.
  • Serializa tus datos con JSON.stringify y recupéralos con JSON.parse.
  • Integra el guardado y la carga en los eventos del juego para una experiencia fluida.
  • Practica implementando estas funciones en tus propios proyectos.

¡Ahora estás listo para organizar y persistir el progreso de tus jugadores! En el siguiente módulo, aprenderás sobre características avanzadas de jugabilidad como efectos de partículas y animaciones.

Phaser - Desarrollo de Juegos con JavaScript

Módulo 1: Introducción al Desarrollo de Juegos y Phaser

Módulo 2: Fundamentos de Phaser

Módulo 3: Sprites y Animación

Módulo 4: Física e Interactividad en el Juego

Módulo 5: Mundo del Juego y Cámara

Módulo 6: Audio e Interfaz de Usuario

Módulo 7: Arquitectura del Juego y Gestión de Estados

Módulo 8: Características Avanzadas de Jugabilidad

Módulo 9: Despliegue y Optimización

Módulo 10: Proyecto Final

© Copyright 2024. Todos los derechos reservados