O que melonjs-performance faz?
Use esta habilidade quando um jogo melonJS estiver com baixo FPS, alocando muitos recursos ou precisando escalar para muitos objetos. Abrange: pool de objetos, batelada de chamadas de desenho, atlas, baking com CanvasRenderTarget, instanciamento, culling, alwaysUpdate, plugin de depuração e onde estão os custos reais. As ações são acionadas por palavras-chave como: performance, slow, frame rate, fps, lag, pool, pool.register, pool.pull, batching, draw calls, InstancedMesh, culling, alwaysUpdate, inViewport, CanvasRenderTarget, optimise, profiling, debug plugin, memory.
Pool de Objetos (Object Pooling)
- Objetivo: Reduzir alocações de memória e coleta de lixo (Garbage Collection) reutilizando objetos em vez de criá-los/destruí-los constantemente.
- Como usar:
- Registre a classe do objeto com
me.pool.register("meuObjeto", MinhaClasse). Exemplo:import { pool } from 'melonjs'; pool.register('bullet', BulletEntity); - Em vez de
new MinhaClasse(), usepool.pull('meuObjeto')para obter uma instância do pool. - Quando o objeto não for mais necessário, retorne-o ao pool chamando
obj.release()(ou método similar, que deve ser implementado na classe).
- Registre a classe do objeto com
- Benefício: Menos alocações, menor pressão no GC, frames mais estáveis.
Batelada de Chamadas de Desenho (Draw-Call Batching)
-
Contexto: Cada chamada de desenho (draw call) é cara. Agrupar objetos que compartilham a mesma textura/shader reduz o número de chamadas.
-
Como otimizar:
- Atlas de textura: Combine várias imagens pequenas em uma única textura grande (por exemplo, usando TexturePacker). Carregue o atlas com
me.loader.preload. - Instanciamento: Use
me.ObjectEntitycomrenderable.isPersistent = truee, se possível, utilizeme.Renderer.drawInstancedouInstancedMeshpara renderizar muitas cópias do mesmo sprite com uma única chamada de desenho. - CanvasRenderTarget: Para elementos estáticos (como um fundo), renderize uma vez em um
CanvasRenderTarget(textura de renderização) e depois desenhe essa textura como um único sprite.
Exemplo com CanvasRenderTarget:
import { CanvasRenderTarget, Vector2d } from 'melonjs'; let target = new CanvasRenderTarget(800, 600); // renderize objetos no target // depois, no loop principal, desenhe apenas o target: target.render(me.video.getRenderer(), 0, 0); - Atlas de textura: Combine várias imagens pequenas em uma única textura grande (por exemplo, usando TexturePacker). Carregue o atlas com
Culling e alwaysUpdate
- Culling: Desabilite o desenho e a atualização de objetos que estão fora do viewport (tela). Use a propriedade
inViewportou implemente lógica própria comme.viewport.isVisible().- Exemplo:
if (!me.viewport.isVisible(this.pos.x, this.pos.y, this.width, this.height)) { this.setVisible(false); return; // pula a atualização }
- Exemplo:
- alwaysUpdate: Por padrão, objetos que não estão no viewport não são atualizados (se
alwaysUpdate = false, que é o padrão). Se um objeto precisa ser atualizado mesmo fora da tela (ex: IA de inimigo distante), definathis.alwaysUpdate = true.- Atenção: Use com moderação – muitos objetos com
alwaysUpdate = truepodem consumir CPU desnecessariamente.
- Atenção: Use com moderação – muitos objetos com
Plugin de Depuração (Debug Plugin)
- Ativação: Ative o plugin de depuração durante o desenvolvimento para visualizar métricas:
import { debug } from 'melonjs'; me.debug.renderHitBox = true; me.debug.renderVelocity = true; // ou ative o painel de debug via starter template - Como usar: Inicie o jogo com a flag
--debugou pressione F12 para abrir o painel do plugin. Lá você verá:- FPS atual e histórico
- Número de objetos ativos (active objects)
- Memória (total, alocada, GC runs)
- Draw calls por frame
- Interpretação: FPS abaixo de 60 com alto número de draw calls (>100) sugere que batching é necessário. Picos de memória indicam alocações excessivas – considere pool de objetos.
Onde estão os verdadeiros gargalos?
- CPU: Profiling com
me.debugou ferramentas do navegador (Chrome DevTools). Procure funções que consomem muito tempo, como atualização de física, IA ou renderização individual de muitos objetos. - GPU: Baixo FPS com draw calls baixas pode indicar shaders complexos ou texturas grandes. Use o painel de debug para ver o número de draw calls e pixels preenchidos.
- Memória: Alocações frequentes (GC) causam pausas. Use o profiler de memória do navegador e verifique se objetos estão sendo criados/destruídos em loop – solução: pool de objetos.
Exemplo Integrado
Combinação de pool, batching e culling para uma cena de muitos projéteis:
import { pool, CanvasRenderTarget, viewport } from 'melonjs';
class Bullet extends me.Sprite {
constructor(x, y) {
super(x, y, { image: 'bullet' });
this.alive = false;
}
// ... métodos onActivate, onDeactivate
}
// Registrar
pool.register('bullet', Bullet);
// No loop de atualização:
function spawnBullet(x, y) {
let bullet = pool.pull('bullet', x, y);
me.game.world.addChild(bullet);
}
// Culling: verificar se está visível
bullet.update = function(dt) {
if (!viewport.isVisible(this)) {
this.release(); // retorna ao pool
return false;
}
// lógica de movimento
return true;
};
Notas Finais
- Sempre perfilar antes de otimizar. Adivinhações podem piorar o desempenho.
- Use o plugin de debug como primeira ferramenta.
- Comece com pool de objetos e batching – essas são as otimizações de maior impacto na maioria dos jogos melonJS.