Componentes y sistemas personalizados
El comportamiento del juego se agrega escribiendo tus propios componentes (datos) y sistemas (lógica). Consulta Arquitectura para una visión general de ECS.
Componentes personalizados
Un componente es una clase simple que contiene datos y no contiene lógica. Una convención habitual es aceptar un objeto de opciones parcial en el constructor y asignarlo, de modo que el componente pueda crearse con o sin valores iniciales:
import { Vector2 } from "angry-pixel";
export class Player {
public health: number = 100;
public speed: number = 200;
public direction: Vector2 = new Vector2();
constructor(options?: Partial<Player>) {
Object.assign(this, options);
}
}
Las clases de componentes se suelen mantener en src/component/. Se asocian a las entidades mediante arquetipos o el Entity Manager. Consulta Agregar entidades a la escena.
Sistemas personalizados
Un sistema contiene lógica que opera sobre las entidades a través de sus componentes. La forma recomendada de crear uno es extender la clase abstracta GameSystem, que proporciona los gestores principales del motor mediante inyección de dependencias.
import { GameSystem, Transform } from "angry-pixel";
import { Player } from "../component/Player";
export class PlayerSystem extends GameSystem {
onUpdate() {
this.entityManager.search(Player, (player, entity) => {
const transform = this.entityManager.getComponent(entity, Transform);
transform.position.x += player.speed * this.timeManager.deltaTime;
});
}
}
Las clases de sistemas se suelen mantener en src/system/.
Gestores inyectados
GameSystem expone estos miembros:
| Miembro | Descripción |
|---|---|
entityManager | Crea, consulta y modifica entidades y componentes. Consulta El Entity Manager. |
assetManager | Carga y obtiene recursos. Consulta El Asset Manager. |
sceneManager | Carga escenas y gestiona las transiciones. Consulta El Scene Manager. |
timeManager | Tiempo del juego y delta time. Consulta El Time Manager. |
inputManager | Entrada de teclado, ratón, gamepad y táctil. Consulta El Input Manager. |
collisionRepository | Consulta datos de colisiones y física. Consulta Física. |
gameConfig | El objeto de configuración del juego. |
Métodos del ciclo de vida
Un sistema puede implementar los siguientes métodos. Para la mayoría de los sistemas solo se necesita onUpdate:
| Método | Cuándo se ejecuta |
|---|---|
onSceneLoaded | Cuando la escena termina de cargarse, después de que se hayan creado sus entidades. |
onUpdate | Una vez por frame, mientras el sistema está activado. |
onSceneDestroyed | Cuando se destruye la escena, antes de que se eliminen sus entidades. |
Registrar un sistema
Un sistema se ejecuta solo después de agregarse al array systems en el método setup de una escena:
import { Scene } from "angry-pixel";
import { PlayerSystem } from "../system/PlayerSystem";
export class MainScene extends Scene {
setup() {
this.systems = [PlayerSystem];
}
}
Los sistemas se ejecutan en el orden del array.
Fase de ejecución
Por defecto, un sistema se ejecuta en la fase de lógica de juego. Un decorador puede asignarlo a una fase distinta:
| Decorador | Fase | Para |
|---|---|---|
@gameLogicSystem() | Lógica de juego | Jugabilidad, IA, procesamiento de entrada (el valor por defecto). |
@gamePhysicsSystem() | Física | Actualizaciones relacionadas con la física, que se ejecutan a la frecuencia de la física. |
@gamePreRenderSystem() | Pre-renderizado | Trabajo que debe ocurrir antes del renderizado, como ordenar sprites o posicionar la cámara. |
import { GameSystem, gamePhysicsSystem } from "angry-pixel";
@gamePhysicsSystem()
export class MovementSystem extends GameSystem {
onUpdate() {
// se ejecuta en la fase de física
}
}
Inyectar dependencias personalizadas
Un sistema puede recibir dependencias personalizadas mediante inyección de dependencias. Registra la dependencia en el juego (consulta La clase Game) y luego inyéctala con el decorador inject usando el nombre con el que se registró:
import { GameSystem, inject } from "angry-pixel";
import { ScoreService } from "../service/ScoreService";
export class ScoreSystem extends GameSystem {
@inject("ScoreService") private readonly scoreService: ScoreService;
onUpdate() {
// usar this.scoreService
}
}
Los gestores integrados están disponibles bajo los identificadores SYMBOLS, por ejemplo @inject(SYMBOLS.EntityManager). Un sistema que no extiende GameSystem puede implementar la interfaz System directamente e inyectar solo las dependencias que necesite.