From d6a9650c45fdc21204c538d96f86adabec81711d Mon Sep 17 00:00:00 2001 From: Maxim Molochkov Date: Sat, 27 Sep 2025 20:48:28 +0400 Subject: [PATCH] perf(excalibur): switch particle system from Actors to GraphicsGroup --- src/scripts/excalibur.js | 86 ++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 35 deletions(-) diff --git a/src/scripts/excalibur.js b/src/scripts/excalibur.js index 7617a5c..9148181 100644 --- a/src/scripts/excalibur.js +++ b/src/scripts/excalibur.js @@ -1,18 +1,26 @@ import * as ex from 'excalibur'; import Engine from './engine.js'; +const spriteImage = new ex.ImageSource('sprite.png'); + +const loader = new ex.Loader([spriteImage]); + export class Scene extends ex.Scene { + onInitialize() { + this.sprite = spriteImage.toSprite(); + } + onActivate(ctx) { - const engine = ctx.engine; this.engine = ctx.data.engine; this.clear(); // Particle creation - const particles = new Array(this.engine.count); + const particles = Array.from({ length: this.engine.count }); const rnd = [1, -1]; - const spriteImage = new ex.ImageSource('sprite.png'); - spriteImage.load(); + + const graphicsGroup = new ex.GraphicsGroup({ members: [] }); + for (let i = 0; i < this.engine.count; i++) { const size = 10 + Math.random() * 80; const x = Math.random() * this.engine.width; @@ -22,15 +30,11 @@ export class Scene extends ex.Scene { 3 * Math.random() * rnd[Math.floor(Math.random() * 2)], ]; - const particle = new ex.Actor({ - x: x, - y: y, - radius: size, - }); - if (this.engine.type === 'sprite') { - const sprite = ex.Sprite.from(spriteImage); - particle.graphics.use(sprite); + graphicsGroup.members.push({ + graphic: this.sprite, + offset: ex.vec(x, y), + }); } else { const circle = new ex.Circle({ x: x, @@ -46,26 +50,36 @@ export class Scene extends ex.Scene { : ex.Color.fromRGB(0, 0, 0), strokeWidth: this.engine.type === 'stroke' ? 1 : undefined, }); - particle.graphics.use(circle); + graphicsGroup.members.push({ + graphic: circle, + offset: ex.vec(x, y), + }); } - this.add(particle); - - particles[i] = { x, y, size: size, dx, dy, el: particle }; - - particle.on("postupdate", () => { - const r = particles[i]; - r.x -= r.dx; - r.y -= r.dy; - if (r.x + r.size < 0) r.dx *= -1; - else if (r.y + r.size < 0) r.dy *= -1; - if (r.x > engine.screen.drawWidth) r.dx *= -1; - else if (r.y > engine.screen.drawHeight) r.dy *= -1; - r.el.pos.x = r.x; - r.el.pos.y = r.y; - }); + + particles[i] = { x, y, size: size, dx, dy, el: graphicsGroup.members[i] }; } + + const screenElement = new ex.ScreenElement(); + + screenElement.graphics.use(graphicsGroup); + + this.add(screenElement); + + this.particles = particles; } - onPostUpdate() { + + onPostUpdate(engine) { + for (let i = 0; i < this.engine.count; i++) { + const r = this.particles[i]; + r.x -= r.dx; + r.y -= r.dy; + if (r.x + r.size < 0) r.dx *= -1; + else if (r.y + r.size < 0) r.dy *= -1; + if (r.x > engine.screen.drawWidth) r.dx *= -1; + else if (r.y > engine.screen.drawHeight) r.dy *= -1; + r.el.offset.setTo(r.x, r.y); + } + this.engine.fpsmeter.tick(); } } @@ -77,12 +91,12 @@ class ExcaliburEngine extends Engine { window.cancelAnimationFrame(this.request); if (this.game) { this.game.dispose(); - this.canvas = document.createElement("canvas"); - this.canvas.id = "canvas"; - this.canvas.className = "canvas"; + this.canvas = document.createElement('canvas'); + this.canvas.id = 'canvas'; + this.canvas.className = 'canvas'; this.canvas.width = this.width; this.canvas.height = this.height; - document.querySelector("main").appendChild(this.canvas); + document.querySelector('main').appendChild(this.canvas); } const game = new ex.Engine({ @@ -90,12 +104,14 @@ class ExcaliburEngine extends Engine { height: this.height, canvasElement: this.canvas, backgroundColor: ex.Color.fromRGB(26, 26, 26), - scenes: { scene: Scene } + suppressPlayButton: true, + physics: { enabled: false }, + scenes: { scene: Scene }, }); this.game = game; } render() { - this.game.start().then(() => { + this.game.start(loader).then(() => { this.game.goToScene('scene', { sceneActivationData: { engine: this } }); }); }