This commit is contained in:
syuilo
2026-07-29 20:01:43 +09:00
parent b3c981d14a
commit 2d7e79f924
11 changed files with 153 additions and 24 deletions
@@ -20,6 +20,7 @@ export abstract class EngineBase<EVs extends EngineBaseEvents> extends EventEmit
protected engine: BABYLON.WebGPUEngine;
public scene: BABYLON.Scene;
abstract sr: BABYLON.SnapshotRenderingHelper;
protected fps: number | null = null;
protected disposed = false;
@@ -0,0 +1,121 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import * as BABYLON from '@babylonjs/core/pure.js';
import { cm, WORLD_SCALE } from 'misskey-world/src/utility.js';
import { randomRange, Timer } from './utility.js';
import type { EngineBase } from './EngineBase.js';
export class Firework {
private engine: EngineBase<any>;
private timer: Timer = new Timer();
constructor(engine: EngineBase<any>) {
this.engine = engine;
}
public launch(options: {
position: [number, number, number];
}) {
this.engine.sr.disableSnapshotRendering();
const texture = new BABYLON.Texture(`/client-assets/world/other/firework/flare-${Math.round(randomRange(1, 8))}.png`, this.engine.scene);
//const emitter = new BABYLON.TransformNode('emitter', this.engine.scene);
const emitter = BABYLON.MeshBuilder.CreateBox('emitter', { size: cm(10) }, this.engine.scene);
emitter.position = new BABYLON.Vector3(options.position[0], options.position[1], options.position[2]);
const ps = new BABYLON.ParticleSystem('', 128, this.engine.scene);
ps.particleTexture = texture;
ps.emitter = emitter;
ps.minEmitPower = cm(100);
ps.maxEmitPower = cm(500);
ps.minLifeTime = 0.5;
ps.maxLifeTime = 1;
ps.minSize = cm(3);
ps.maxSize = cm(30);
//ps.direction1 = new BABYLON.Vector3(0, 1, 0);
//ps.direction2 = new BABYLON.Vector3(0, 1, 0);
ps.emitRate = 20;
ps.blendMode = BABYLON.ParticleSystem.BLENDMODE_ADD;
//ps.color1 = new BABYLON.Color4(1, 1, 1, 0.3);
//ps.color2 = new BABYLON.Color4(1, 1, 1, 0.2);
ps.colorDead = new BABYLON.Color4(1, 1, 1, 0);
ps.start();
this.engine.sr.fixParticleSystem(ps);
const launchAnim = new BABYLON.Animation(
'',
'position',
60,
BABYLON.Animation.ANIMATIONTYPE_VECTOR3,
BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT,
);
launchAnim.setKeys([
{ frame: 0, value: new BABYLON.Vector3(options.position[0], options.position[1], options.position[2]) },
{ frame: 60, value: new BABYLON.Vector3(options.position[0], options.position[1] + cm(randomRange(1000, 3000)), options.position[2]) },
]);
emitter.animations.push(launchAnim);
const animating = Promise.withResolvers<void>();
const animationObserver = this.engine.scene.onAfterAnimationsObservable.add(() => {
});
this.engine.scene.beginAnimation(emitter, 0, 60, false, 1, () => { animating.resolve(); });
animating.promise.then(() => {
this.engine.scene.onAfterAnimationsObservable.remove(animationObserver);
ps.stop();
this.timer.setTimeout(() => {
ps.dispose();
emitter.dispose();
}, 1000);
this.explode({
position: [emitter.position.x, emitter.position.y, emitter.position.z],
texture,
});
});
//this.engine.sr.enableSnapshotRendering();
}
public explode(options: {
position: [number, number, number];
texture: BABYLON.Texture;
}) {
const ps = new BABYLON.ParticleSystem('', 128, this.engine.scene);
ps.particleTexture = options.texture;
ps.emitter = new BABYLON.Vector3(options.position[0], options.position[1], options.position[2]);
ps.minEmitPower = cm(2000);
ps.maxEmitPower = cm(4000);
ps.minLifeTime = 0.7;
ps.maxLifeTime = 1;
ps.addDragGradient(0, 0.1);
ps.addDragGradient(1, 0.8);
ps.gravity = new BABYLON.Vector3(0, -30, 0).scale(WORLD_SCALE);
ps.minSize = cm(20);
ps.maxSize = cm(40);
const sphereEmitter = ps.createSphereEmitter(cm(1));
//ps.direction1 = new BABYLON.Vector3(0, 1, 0);
//ps.direction2 = new BABYLON.Vector3(0, 1, 0);
ps.manualEmitCount = 100;
ps.blendMode = BABYLON.ParticleSystem.BLENDMODE_ADD;
ps.color1 = new BABYLON.Color4(1, 1, 1, 1);
ps.color2 = new BABYLON.Color4(1, 1, 1, 1);
ps.colorDead = new BABYLON.Color4(1, 1, 1, 0);
ps.start();
this.engine.sr.fixParticleSystem(ps);
this.timer.setTimeout(() => {
ps.dispose();
}, 2000);
}
public dispose() {
this.timer.dispose();
}
}
@@ -10,6 +10,7 @@ import Hls from 'hls.js';
import { findMaterial, GRAPHICS_QUALITY, Timer } from '../utility.js';
import { WorldEnvManager } from '../env.js';
import { RecyvlingTextGrid, createPlaneUvMapper, randomRange } from '../utility.js';
import { Firework } from '../Firework.js';
import type { WorldEngine } from '../engine.js';
export class LobbyEnvManager extends WorldEnvManager {
@@ -447,31 +448,37 @@ export class LobbyEnvManager extends WorldEnvManager {
this.engine.sr.updateMesh([...hourHands, ...minuteHands], false);
}, 1000);
const emitter = new BABYLON.TransformNode('emitter', this.engine.scene);
emitter.position = new BABYLON.Vector3(0, cm(-1000), 0);
const ps = new BABYLON.ParticleSystem('', 128, this.engine.scene);
ps.particleTexture = new BABYLON.Texture('/client-assets/world/envs/lobby/bubble.png');
ps.emitter = emitter;
ps.isLocal = true;
ps.minEmitBox = new BABYLON.Vector3(cm(-1000), 0, cm(-1000));
ps.maxEmitBox = new BABYLON.Vector3(cm(1000), 0, cm(1000));
ps.minEmitPower = cm(100);
ps.maxEmitPower = cm(500);
ps.minLifeTime = 30;
ps.maxLifeTime = 30;
ps.minSize = cm(30);
ps.maxSize = cm(300);
ps.direction1 = new BABYLON.Vector3(0, 1, 0);
ps.direction2 = new BABYLON.Vector3(0, 1, 0);
ps.emitRate = 1.5;
ps.blendMode = BABYLON.ParticleSystem.BLENDMODE_ADD;
ps.color1 = new BABYLON.Color4(1, 1, 1, 0.3);
ps.color2 = new BABYLON.Color4(1, 1, 1, 0.2);
ps.colorDead = new BABYLON.Color4(1, 1, 1, 0);
ps.preWarmCycles = Math.random() * 1000;
ps.start();
//const emitter = new BABYLON.TransformNode('emitter', this.engine.scene);
//emitter.position = new BABYLON.Vector3(0, cm(-1000), 0);
//const ps = new BABYLON.ParticleSystem('', 128, this.engine.scene);
//ps.particleTexture = new BABYLON.Texture('/client-assets/world/envs/lobby/bubble.png');
//ps.emitter = emitter;
//ps.isLocal = true;
//ps.minEmitBox = new BABYLON.Vector3(cm(-1000), 0, cm(-1000));
//ps.maxEmitBox = new BABYLON.Vector3(cm(1000), 0, cm(1000));
//ps.minEmitPower = cm(100);
//ps.maxEmitPower = cm(500);
//ps.minLifeTime = 30;
//ps.maxLifeTime = 30;
//ps.minSize = cm(30);
//ps.maxSize = cm(300);
//ps.direction1 = new BABYLON.Vector3(0, 1, 0);
//ps.direction2 = new BABYLON.Vector3(0, 1, 0);
//ps.emitRate = 1.5;
//ps.blendMode = BABYLON.ParticleSystem.BLENDMODE_ADD;
//ps.color1 = new BABYLON.Color4(1, 1, 1, 0.3);
//ps.color2 = new BABYLON.Color4(1, 1, 1, 0.2);
//ps.colorDead = new BABYLON.Color4(1, 1, 1, 0);
//ps.preWarmCycles = Math.random() * 1000;
//ps.start();
//this.engine.sr.fixParticleSystem(ps);
this.engine.sr.fixParticleSystem(ps);
this.timer.setInterval(() => {
const firework = new Firework(this.engine);
firework.launch({
position: [randomRange(cm(-2000), cm(2000)), cm(randomRange(1000, 3000)), randomRange(cm(-2000), cm(2000))],
});
}, 1000);
this.registerMeshes(this.meshes);
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB