Organizar el código es fundamental para cualquier proyecto de software, y en el desarrollo de juegos con Phaser no es la excepción. Una buena organización facilita el mantenimiento, la escalabilidad y la colaboración en equipo. En esta sección aprenderás cómo estructurar tu código de manera eficiente utilizando las mejores prácticas de la industria.


Conceptos Clave

  • Modularidad: Separar el código en archivos y módulos independientes según su funcionalidad.
  • Reutilización: Escribir funciones y clases reutilizables para evitar duplicación.
  • Legibilidad: Mantener el código claro y fácil de entender.
  • Escalabilidad: Permitir que el proyecto crezca sin volverse inmanejable.
  • Separación de responsabilidades: Cada parte del código debe tener una función clara y específica.

Estructura Recomendada de Carpetas y Archivos

Una estructura típica para un proyecto Phaser puede ser la siguiente:

Carpeta/Archivo Descripción
index.html Archivo principal HTML que carga el juego
src/ Código fuente del juego
src/main.js Punto de entrada del juego
src/scenes/ Escenas del juego (menú, juego, game over, etc.)
src/objects/ Clases de objetos personalizados (jugador, enemigos)
src/utils/ Funciones y utilidades generales
assets/ Imágenes, sonidos y otros recursos
package.json Dependencias y scripts del proyecto (si usas npm)

Ejemplo de Organización de Código

Supongamos que tienes un juego simple con una escena de menú y una escena de juego. Así podrías organizarlo:

/mi-juego/
│
├── index.html
├── src/
│   ├── main.js
│   ├── scenes/
│   │   ├── MenuScene.js
│   │   └── GameScene.js
│   ├── objects/
│   │   └── Player.js
│   └── utils/
│       └── helpers.js
└── assets/
    ├── images/
    └── sounds/

Ejemplo Práctico: Separando Escenas y Objetos

  1. Archivo principal (main.js)

import MenuScene from './scenes/MenuScene.js';
import GameScene from './scenes/GameScene.js';

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    scene: [MenuScene, GameScene],
    physics: {
        default: 'arcade',
        arcade: { debug: false }
    }
};

const game = new Phaser.Game(config);

Explicación:
Aquí importamos las escenas y las agregamos al arreglo scene en la configuración de Phaser. Esto permite que Phaser gestione las transiciones entre escenas.


  1. Escena de Menú (scenes/MenuScene.js)

export default class MenuScene extends Phaser.Scene {
    constructor() {
        super({ key: 'MenuScene' });
    }

    create() {
        this.add.text(300, 250, 'Presiona ESPACIO para Jugar', { fontSize: '24px', fill: '#fff' });
        this.input.keyboard.once('keydown-SPACE', () => {
            this.scene.start('GameScene');
        });
    }
}

Explicación:
Esta clase define la escena del menú. Al presionar la barra espaciadora, se inicia la escena del juego.


  1. Escena de Juego (scenes/GameScene.js)

import Player from '../objects/Player.js';

export default class GameScene extends Phaser.Scene {
    constructor() {
        super({ key: 'GameScene' });
    }

    create() {
        this.player = new Player(this, 400, 300);
    }

    update() {
        this.player.update();
    }
}

Explicación:
Aquí se instancia el jugador usando una clase personalizada y se llama a su método update en cada frame.


  1. Objeto Jugador (objects/Player.js)

export default class Player extends Phaser.Physics.Arcade.Sprite {
    constructor(scene, x, y) {
        super(scene, x, y, 'player');
        scene.add.existing(this);
        scene.physics.add.existing(this);
        this.setCollideWorldBounds(true);
        this.cursors = scene.input.keyboard.createCursorKeys();
    }

    update() {
        this.setVelocity(0);

        if (this.cursors.left.isDown) {
            this.setVelocityX(-160);
        } else if (this.cursors.right.isDown) {
            this.setVelocityX(160);
        }

        if (this.cursors.up.isDown) {
            this.setVelocityY(-160);
        } else if (this.cursors.down.isDown) {
            this.setVelocityY(160);
        }
    }
}

Explicación:
La clase Player hereda de Phaser.Physics.Arcade.Sprite y encapsula toda la lógica del jugador, incluyendo el movimiento.


Ejercicio Práctico

Ejercicio:
Organiza el siguiente código en archivos separados siguiendo la estructura recomendada. El código consiste en una escena de menú y una escena de juego donde aparece un jugador que puede moverse.

// Código base (todo en un archivo)
class MenuScene extends Phaser.Scene {
    // ...
}

class GameScene extends Phaser.Scene {
    // ...
}

class Player extends Phaser.Physics.Arcade.Sprite {
    // ...
}

const config = {
    // ...
};

const game = new Phaser.Game(config);

Instrucciones:

  1. Crea una carpeta src/ con subcarpetas scenes/ y objects/.
  2. Mueve cada clase a su propio archivo.
  3. Ajusta los imports y exports para que el código funcione correctamente.

Solución

  1. src/scenes/MenuScene.js

    export default class MenuScene extends Phaser.Scene {
        // ...
    }
    
  2. src/scenes/GameScene.js

    import Player from '../objects/Player.js';
    export default class GameScene extends Phaser.Scene {
        // ...
    }
    
  3. src/objects/Player.js

    export default class Player extends Phaser.Physics.Arcade.Sprite {
        // ...
    }
    
  4. src/main.js

    import MenuScene from './scenes/MenuScene.js';
    import GameScene from './scenes/GameScene.js';
    
    const config = {
        // ...
        scene: [MenuScene, GameScene],
    };
    
    const game = new Phaser.Game(config);
    

Errores comunes:

  • Olvidar ajustar las rutas de importación (por ejemplo, usar ./objects/Player.js en vez de solo Player.js).
  • No exportar las clases con export default.
  • No importar las escenas en el archivo principal.

Consejo:
Utiliza nombres descriptivos para tus archivos y carpetas. Mantén cada archivo enfocado en una sola responsabilidad.


Resumen

En esta sección aprendiste:

  • La importancia de organizar el código en proyectos de juegos.
  • Cómo estructurar carpetas y archivos en un proyecto Phaser.
  • Cómo separar escenas y objetos en módulos independientes.
  • Cómo importar y exportar clases para mantener el código limpio y escalable.

Una buena organización te permitirá trabajar de manera más eficiente y facilitará la colaboración en proyectos más grandes. En la siguiente sección, aprenderás a gestionar múltiples escenas y cómo navegar entre ellas de forma efectiva.

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