File

src/app/models/babylonjs-confetti.ts

Constructor

constructor(cabri: CabriIntegration | BabylonGabaritIntegration, amountParticles: number, animationDuration: number, animationName: ParticleAnimName, startPosition: Vector3 | Vector3)
Parameters :
  • cabri

    CabriIntegration

  • startPosition

    Vectors of starting position

  • amountParticles

    amount of particles into the scene

  • animationDuration

    duration in miliseconds

Methods

Private init
init()
Returns: void
Public runParticles
runParticles()

Start animation

Returns: void
Private recycleParticle
recycleParticle(particle: SolidParticle)

Particles during the animation

Returns: void
explosionAnim
explosionAnim(particle: SolidParticle)

Confetti explosion anim

Parameters :
  • particle

    SolidParticle

Returns: void
basketAnim
basketAnim(particle: SolidParticle)

Confetti basketball anim

Parameters :
  • particle

    SolidParticle

Returns: void

Properties

amountParticles
amountParticles: number
animationDuration
animationDuration: number
animationName
animationName: ParticleAnimName
cabri
cabri: CabriIntegration | BabylonGabaritIntegration
cameraType
cameraType: Camera | Camera
currentSPS
currentSPS: SolidParticleSystem
mesh
mesh: Mesh
observer
observer: Observer<any> | Observer<any>
position
position: Vector3 | Vector3
import { Camera, Observer, Vector3 } from "@babylonjs/core";
import { Mesh, Vector3 as Vector3Cabri, SolidParticleSystem, SolidParticle, Observer as ObserverCabri, Camera as CameraCabri } from "babylon4.1";
import { AppUtils } from "../app-utils";
import { BabylonGabaritIntegration } from "./babylon-gabarit-integration";
import { CabriIntegration } from "./cabri-integration";
declare var BABYLON;

export enum ParticleAnimName {
	explosion,
	basket
}
export class BabylonJsConfetti {
	cabri: CabriIntegration | BabylonGabaritIntegration;
	mesh: Mesh;
	position: Vector3Cabri | Vector3;
	amountParticles: number;
	// gravity = -0.03;
	currentSPS: SolidParticleSystem;
	observer: Observer<any> | ObserverCabri<any>;
	animationDuration: number;
	animationName: ParticleAnimName;
	cameraType: Camera | CameraCabri;

	/**
	 * https://doc.babylonjs.com/features/featuresDeepDive/particles/solid_particle_system/sps_intro
	 *
	 * @param cabri CabriIntegration
	 * @param startPosition Vectors of starting position
	 * @param amountParticles amount of particles into the scene
	 * @param animationDuration duration in miliseconds
	 */
	constructor(
		cabri: CabriIntegration | BabylonGabaritIntegration,
		amountParticles: number,
		animationDuration: number,
		animationName: ParticleAnimName,
		startPosition?: Vector3 | Vector3Cabri
	) {
		this.cabri = cabri;
		if (startPosition) {
			this.position = startPosition;
		} else {
			this.position = new Vector3(0, 0, 0);
		}
		if (this.cabri.scene.activeCameras) {
			const sceneHudCameraExist = this.cabri.scene.activeCameras.some(camera => {
				return camera.name?.toLowerCase().startsWith("hud");
			});
			this.cameraType = sceneHudCameraExist ? this.cabri.cameraHud : this.cabri.camera;
		} else {
			// security
			this.cameraType = this.cabri.cameraHud;
		}
		this.animationName = animationName;
		this.animationDuration = animationDuration;
		this.amountParticles = amountParticles;
		this.currentSPS = this.init();
		this.currentSPS.setParticles();
	}

	private init() {
		const SPS = new BABYLON.SolidParticleSystem("SPS", this.cabri.scene) as SolidParticleSystem;
		const tetra = BABYLON.MeshBuilder.CreatePlane("tetra", { size: 0.16 });
		SPS.addShape(tetra, this.amountParticles);
		tetra.dispose();
		this.mesh = SPS.buildMesh();

		this.mesh.layerMask = this.cameraType.layerMask;
		SPS.initParticles = () => {
			for (let p = 0; p < SPS.nbParticles; p++) {
				this.recycleParticle(SPS.particles[p]);
			}
		};
		SPS.initParticles();
		return SPS;
	}

	/**
	 * Start animation
	 */
	public async runParticles() {
		let gravity: number;
		this.currentSPS.updateParticle = particle => {
			// gravity = ;
			gravity = this.animationName === ParticleAnimName.basket ? -0.005 : -0.001;
			if (this.cameraType.position.z > 0) {
				particle.velocity.z += gravity;
			} else {
				particle.velocity.y += gravity;
			}
			particle.position.addInPlace(particle.velocity); // update particle new position
			particle.rotation.addInPlace(particle.velocity);
			return particle;
		};
		this.observer = this.cabri.scene.onAfterRenderObservable.add(async () => {
			this.currentSPS.setParticles();
		});

		await AppUtils.timeOut(this.animationDuration);

		const ease = new BABYLON.CubicEase();
		ease.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEINOUT);

		const fade = BABYLON.Animation.CreateAndStartAnimation("fm1", this.mesh, "visibility", 60, 60, this.mesh.visibility, 0, 0, ease);

		fade.onAnimationEnd = () => {
			if (this.cabri.scene) {
				// verify if scene existe maybe we already leave the page at the end of the activity
				this.cabri.scene.onAfterRenderObservable.remove(this.observer as any);
			}
			this.currentSPS.dispose();
		};
		fade.disposeOnEnd = true;
	}

	/**
	 * Particles during the animation
	 */
	private recycleParticle(particle: SolidParticle) {
		if (this.animationName === ParticleAnimName.explosion) {
			this.explosionAnim(particle);
		} else if (this.animationName === ParticleAnimName.basket) {
			this.basketAnim(particle);
		}
	}

	/**
	 * Confetti explosion anim
	 *
	 * @param particle SolidParticle
	 */
	explosionAnim(particle: SolidParticle) {
		const speed = 0.4;
		particle.position.x = this.position.x;
		particle.position.y = this.position.y;
		particle.position.z = this.position.z;
		particle.rotation.x = BABYLON.Scalar.RandomRange(-Math.PI, Math.PI);
		particle.rotation.y = BABYLON.Scalar.RandomRange(-Math.PI, Math.PI);
		particle.rotation.z = BABYLON.Scalar.RandomRange(-Math.PI, Math.PI);
		const hexColorsAccepted = ["#a864fd", "#29cdff", "#78ff44", "#ff718d", "#fdff6a", "#02FEFF", "#6D2EF1"];
		particle.color = BABYLON.Color3.FromHexString(hexColorsAccepted[Math.floor(Math.random() * hexColorsAccepted.length)]);
		particle.velocity.x = BABYLON.Scalar.RandomRange(-0.3 * speed, 0.3 * speed);

		if (this.cameraType.position.z > 0) {
			particle.velocity.z = BABYLON.Scalar.RandomRange(0.01, 0.12);
		} else {
			particle.velocity.y = BABYLON.Scalar.RandomRange(0.01, 0.12);
		}
	}

	/**
	 * Confetti basketball anim
	 *
	 * @param particle SolidParticle
	 */
	basketAnim(particle: SolidParticle) {
		const speed = 0.3;
		particle.position.x = this.position.x;
		particle.position.y = this.position.y;
		particle.position.z = this.position.z;
		particle.rotation.x = BABYLON.Scalar.RandomRange(-Math.PI, Math.PI);
		particle.rotation.y = BABYLON.Scalar.RandomRange(-Math.PI, Math.PI);
		particle.rotation.z = BABYLON.Scalar.RandomRange(-Math.PI, Math.PI);
		particle.color = new BABYLON.Color3(Math.random(), Math.random(), Math.random());
		particle.velocity.x = BABYLON.Scalar.RandomRange(-0.5 * speed, 0.5 * speed);
		particle.velocity.y = BABYLON.Scalar.RandomRange(0.25 * speed, speed - 0.07);
		particle.velocity.z = BABYLON.Scalar.RandomRange(-0.5 * speed, 0.5 * speed);
	}
}

results matching ""

    No results matching ""