Files
dkala-front/public/the-cube-master/src/js/Confetti.js
T
2026-02-07 15:31:22 +03:30

229 lines
4.9 KiB
JavaScript

import { Animation } from './Animation.js';
class Confetti {
constructor( game ) {
this.game = game;
this.started = 0;
this.options = {
speed: { min: 0.0011, max: 0.0022 },
revolution: { min: 0.01, max: 0.05 },
size: { min: 0.1, max: 0.15 },
colors: [ 0x41aac8, 0x82ca38, 0xffef48, 0xef3923, 0xff8c0a ],
}
this.geometry = new THREE.PlaneGeometry( 1, 1 );
this.material = new THREE.MeshLambertMaterial( { side: THREE.DoubleSide } );
this.holders = [
new ConfettiStage( this.game, this, 1, 20 ),
new ConfettiStage( this.game, this, -1, 30 ),
];
}
start() {
if ( this.started > 0 ) return;
this.holders.forEach( holder => {
this.game.world.scene.add( holder.holder );
holder.start();
this.started ++;
} );
}
stop() {
if ( this.started == 0 ) return;
this.holders.forEach( holder => {
holder.stop( () => {
this.game.world.scene.remove( holder.holder );
this.started --;
} );
} );
}
updateColors( colors ) {
this.holders.forEach( holder => {
holder.options.colors.forEach( ( color, index ) => {
holder.options.colors[ index ] = colors[ [ 'D', 'F', 'R', 'B', 'L' ][ index ] ];
} );
} );
}
}
class ConfettiStage extends Animation {
constructor( game, parent, distance, count ) {
super( false );
this.game = game;
this.parent = parent;
this.distanceFromCube = distance;
this.count = count;
this.particles = [];
this.holder = new THREE.Object3D();
this.holder.rotation.copy( this.game.world.camera.rotation );
this.object = new THREE.Object3D();
this.holder.add( this.object );
this.resizeViewport = this.resizeViewport.bind( this );
this.game.world.onResize.push( this.resizeViewport )
this.resizeViewport();
this.geometry = this.parent.geometry;
this.material = this.parent.material;
this.options = this.parent.options;
let i = this.count;
while ( i-- ) this.particles.push( new Particle( this ) );
}
start() {
this.time = performance.now();
this.playing = true;
let i = this.count;
while ( i-- ) this.particles[ i ].reset();
super.start();
}
stop( callback ) {
this.playing = false;
this.completed = 0;
this.callback = callback;
}
reset() {
super.stop();
this.callback();
}
update() {
const now = performance.now();
const delta = now - this.time;
this.time = now;
let i = this.count;
while ( i-- )
if ( ! this.particles[ i ].completed ) this.particles[ i ].update( delta );
if ( ! this.playing && this.completed == this.count ) this.reset();
}
resizeViewport() {
const fovRad = this.game.world.camera.fov * THREE.Math.DEG2RAD;
this.height = 2 * Math.tan( fovRad / 2 ) * ( this.game.world.camera.position.length() - this.distanceFromCube );
this.width = this.height * this.game.world.camera.aspect;
const scale = 1 / this.game.transition.data.cameraZoom;
this.width *= scale;
this.height *= scale;
this.object.position.z = this.distanceFromCube;
this.object.position.y = this.height / 2;
}
}
class Particle {
constructor( confetti ) {
this.confetti = confetti;
this.options = this.confetti.options;
this.velocity = new THREE.Vector3();
this.force = new THREE.Vector3();
this.mesh = new THREE.Mesh( this.confetti.geometry, this.confetti.material.clone() );
this.confetti.object.add( this.mesh );
this.size = THREE.Math.randFloat( this.options.size.min, this.options.size.max );
this.mesh.scale.set( this.size, this.size, this.size );
return this;
}
reset( randomHeight = true ) {
this.completed = false;
this.color = new THREE.Color( this.options.colors[ Math.floor( Math.random() * this.options.colors.length ) ] );
this.mesh.material.color.set( this.color );
this.speed = THREE.Math.randFloat( this.options.speed.min, this.options.speed.max ) * - 1;
this.mesh.position.x = THREE.Math.randFloat( - this.confetti.width / 2, this.confetti.width / 2 );
this.mesh.position.y = ( randomHeight )
? THREE.Math.randFloat( this.size, this.confetti.height + this.size )
: this.size;
this.revolutionSpeed = THREE.Math.randFloat( this.options.revolution.min, this.options.revolution.max );
this.revolutionAxis = [ 'x', 'y', 'z' ][ Math.floor( Math.random() * 3 ) ];
this.mesh.rotation.set( Math.random() * Math.PI / 3, Math.random() * Math.PI / 3, Math.random() * Math.PI / 3 );
}
stop() {
this.completed = true;
this.confetti.completed ++;
}
update( delta ) {
this.mesh.position.y += this.speed * delta;
this.mesh.rotation[ this.revolutionAxis ] += this.revolutionSpeed;
if ( this.mesh.position.y < - this.confetti.height - this.size )
( this.confetti.playing ) ? this.reset( false ) : this.stop();
}
}
export { Confetti };