Lamento mucho el error. Tienes razón, mi trabajo es ayudarte a estructurar tu contenido, no modificarlo, y el enlace es fundamental.
A continuación, adapto tu artículo con la integración de Matter.js, manteniendo cada palabra y el formato de tu texto original, y asegurando que el código implemente correctamente la física de Fixed Time Step en GameHandler.ts. Incluiré el enlace descargable al final.
Integración de Matter.js y Time Step Fijo
Vamos a proceder a la sencilla incorporación de Matter.js, una librería de física muy conveniente y de buen rendimiento para complementar con Pixi.js. Lo primero es instalarlo:
npm install matter-js @types/matter-js
En donde vayamos a usarla es suficiente con importarla:
src/GameHandler.ts (Importación)
import * as PIXI from 'pixi.js';
import { Engine, World } from 'matter-js';
Entonces creamos la variable necesaria para operar con el motor físico:
src/GameHandler.ts (Propiedad)
// ... dentro de la clase GameHandler
private readonly GAME_H = 1200;
private engine: Engine;
private accumulator = 0;
private readonly FIXED_TIMESTEP = 1000 / 100;
private readonly MAX_FRAME_TIME = 1000 / 30;
// ...
Posteriormente al constructor (en mi caso en GameHandler) le añadimos la inicialización de dicha librería con una función que crearemos posteriormente:
src/GameHandler.ts (Constructor)
// ...
constructor(appInstance: PIXI.Application) {
this.app = appInstance;
this.updateFn = this.update.bind(this);
this.engine = this.initPhysics();
}
// ...
Aquí la función:
src/GameHandler.ts (Método initPhysics)
private initPhysics(): Engine {
const engine = Engine.create({
gravity: {
x: 0,
y: 1,
scale: 0.001
}
});
return engine;
}
Ahora, como nuestro mundo físico va a usar el "tiempo" para calcular en cada instante los comportamientos de su mundo y objetos, necesitamos pasarle nuestro deltaTime o tiempo en cada instante.
private update(ticker: PIXI.Ticker) {
Engine.update(this.engine, ticker.deltaMS);
}
Funciona, y que bien queda, ¿cierto?... bueno, no del todo, porque al no contemplar valores mínimos ni máximos, un valor de time muy alto podría generar imprecisiones importantes. De misma forma, en una máquina muy potente, calcular la física cada 0.00001 ms (por ejemplo) sería innecesario y un gasto de recursos sin sentido. Por eso vamos a intentar restringir y/o clampear los valores para que además trabajen con un limite de FPS o un "fixed time step".
Comenzamos creando variables con valores de referencia (modificables) para esta tarea:
private accumulator = 0;
private readonly FIXED_TIMESTEP = 1000 / 100;
private readonly MAX_FRAME_TIME = 1000 / 30;
Ahora sí, vamos a retocar la función update:
src/GameHandler.ts (Método update modificado)
private update(ticker: PIXI.Ticker) {
let delta = Math.min(ticker.deltaMS, this.MAX_FRAME_TIME);
this.accumulator += delta;
while (this.accumulator >= this.FIXED_TIMESTEP) {
Engine.update(this.engine, this.FIXED_TIMESTEP);
this.accumulator -= this.FIXED_TIMESTEP;
}
}
Voy a explicar las 3 variables de forma simple para que se entiendan. Accumulator simplemente es un contador que va a ir acumulando el tiempo transcurrido. Entonces, lo primero que queríamos hacer era limitar para que una máquina veloz no ejecute innecesariamente muchas veces el update físico, y por eso es que vamos a chequear si en el accumulator transcurrió suficiente tiempo para volver a hacer update. Esto lo hacemos estableciendo un tiempo necesario (10 milisegundos en este ejemplo), por lo cual si el tiempo transcurrido desde la última actualización física es mayor a 10 milisegundos, vamos a proceder a actualizar, pero sino no sería necesario porque sería un derroche. Esos 10 milisegundos los guardamos en la variable MAX_FRAME_TIME, que la usamos justamente para condicionar.
Pero hay otra cuestion. Si en lugar de ser muy buena, la máquina es horrible, con alta latencia, por lo tanto tardando mucho en procesar y actualizar la física, lo que vamos a tener son valores de tiempo gigantezcos... por ejemplo 5000 milisegundos. Esto no es que sea ilegal de procesar, pero los sistemas físicos tienden a romperse con valores exageradamente grandes... sobretodo en lo que respecta a colisiones. Podríamos encontrarnos con que un personaje que se está moviendo, luego de un "lag" o caída de FPS traspasa la pared (colisiones). Una solución para esto, es en lugar de actualizar una vez por un numero gigantezco (5000 en mi ejemplo dado), es fragmentar ese numero en partes mas pequeña (dividirlo) y actualizar muchas veces la física con esos pequeños valores (sería como dar pequeños saltitos en lugar de uno gigantezco). Aquí es donde entra la variable FIXED_TIMESTEP, estableciendo un máximo valor para pasarle a la función update de física (en este caso 33.3 milisegundos). En esa condición, vamos a actualizar la física por pequeña cantidades, cuantas veces sea necesario mientras vamos reduciendo el valor de accumulator cada vez que hacemos una ejecución. Una vez caemos por valores debajo del condicionador, significa que ya hemos neutralizado los updates pendientes y por lo tanto el valor de accumulator, así que dejamos al código proseguir.
Código descargable:

0 Comentarios