Skip to content

Commit

Permalink
perf: improve performance using confetti
Browse files Browse the repository at this point in the history
  • Loading branch information
Romaixn committed Aug 4, 2023
1 parent 7703a89 commit 4f2b2b5
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 56 deletions.
131 changes: 77 additions & 54 deletions src/Components/Confetti.jsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,73 @@
// CONFETTI COMPONENT BY ANDERSON MANCINI FIXED BY RHERAULT
// Thanks <3
// CONFETTI COMPONENT BY ANDERSON MANCINI AND ROMAIN HERAULT
// Based on: https://github.com/JamesChan21/threejs-confetti
// Based on: https://github.com/daniel-lundin/dom-confetti

import React, { useRef } from 'react'
import React, { useRef, useState, useEffect } from 'react'
import { useFrame } from '@react-three/fiber'
import * as THREE from 'three'
import { useState } from 'react'

export default function ExplosionConfetti({ isExploding }) {
/**
* @param {Object} options
* @param {Boolean | undefined} options.isExploding Enable exploding
* @param {Number | undefined} options.amount The amount of particles
* @param {Number | undefined} options.rate Increases or decreases the frequency for particles. Don't set it too high.
* @param {Number | undefined} options.radius The radius of each explosion.
* @param {Number | undefined} options.areaWidth The qrea width for explosion.
* @param {Number | undefined} options.areaHeight The qrea height for explosion.
* @param {Number | undefined} options.fallingHeight Height for the particles to fall from
* @param {Number | undefined} options.fallingSpeed The speed of particles
* @param {(Number)[] | undefined} options.colors Array of Hex color codes for particles. Example: [0x0000ff, 0xff0000, 0xffff00]
* @param {Number | String | undefined} options.duration Duration of the particles in Milliseconds. Set as 'forever' string for infinity explosion
* @param {Boolean | undefined} options.enableShadows Enable particle shadows. Set false for better performance.
*
*/

export default function ExplosionConfetti(
{
isExploding = false,
amount = 100,
rate = 3,
radius = 15,
areaWidth = 3,
areaHeight = 1,
fallingHeight = 10,
fallingSpeed = 8,
colors = ["#a864fd", "#29cdff", "#78ff44", "#ff718d", "#fdff6a"],
duration = 10000,
enableShadows = false
},
props
) {
const groupRef = useRef()
const [booms, setBooms] = useState([])

const options = {
amount: 200,
rate: 2,
radius: 15,
areaWidth: 5,
areaHeight: 3,
fallingHeight: 6,
fallingSpeed: 8,
colors: ["#a864fd", "#29cdff", "#78ff44", "#ff718d", "#fdff6a"]
}

options.rate = options.rate / 100
rate = rate / 100
const geometry = new THREE.PlaneGeometry(0.03, 0.03, 1, 1)

const explode = () => {
function explode() {
const boom = new THREE.Object3D()
boom.life = Math.random() * 5 + 5
boom.position.x = -(options.areaWidth / 2) + options.areaWidth * Math.random()
boom.position.y = options.fallingHeight + options.areaHeight - options.fallingSpeed
boom.position.z = -(options.areaWidth / 2) + options.areaWidth * Math.random()
boom.position.x = -(areaWidth / 2) + areaWidth * Math.random()
boom.position.y = fallingHeight + areaHeight - fallingSpeed
boom.position.z = -(areaWidth / 2) + areaWidth * Math.random()
groupRef.current.add(boom)
booms.push(boom)

for (let i = 0; i < options.amount; i++) {
for (let i = 0; i < amount; i++) {
const material = new THREE.MeshBasicMaterial({
color: options.colors[Math.floor(Math.random() * options.colors.length)],
color: colors[Math.floor(Math.random() * colors.length)],
side: THREE.DoubleSide
})
const particle = new THREE.Mesh(geometry, material)
particle.castShadow = false
particle.castShadow = enableShadows
boom.add(particle)

particle.life = 1

particle.destination = {}
particle.destination.x = (Math.random() - 0.5) * (options.radius * 2) * Math.random()
particle.destination.y = (Math.random() - 0.5) * (options.radius * 2) * Math.random()
particle.destination.z = (Math.random() - 0.5) * (options.radius * 2) * Math.random()
particle.destination.x = (Math.random() - 0.5) * (radius * 2) * Math.random()
particle.destination.y = (Math.random() - 0.5) * (radius * 2) * Math.random()
particle.destination.z = (Math.random() - 0.5) * (radius * 2) * Math.random()

particle.rotation.x = Math.random() * 360
particle.rotation.y = Math.random() * 360
Expand All @@ -61,7 +81,7 @@ export default function ExplosionConfetti({ isExploding }) {
particle.rotateSpeedZ = Math.random() * 0.8 - 0.4
}

boom.dispose = () => {
boom.dispose = function () {
for (let i = 0; i < boom.children.length; i++) {
const particle = boom.children[i]
particle.material.dispose()
Expand All @@ -73,43 +93,46 @@ export default function ExplosionConfetti({ isExploding }) {
}

useFrame(() => {
if (isExploding && Math.random() < options.rate) explode()
if (isExploding && Math.random() < rate) explode()

let particleAmount = 0

for (let i = 0; i < booms.length; i++) {
const boom = booms[i]
const boom = booms[i]

for (let k = 0; k < boom.children.length; k++) {
let particle = boom.children[k]
for (let k = 0; k < boom.children.length; k++) {
let particle = boom.children[k]

particle.destination.y -= THREE.MathUtils.randFloat(0.1, 0.3)
particle.life -= THREE.MathUtils.randFloat(0.005, 0.01)
particle.destination.y -= THREE.MathUtils.randFloat(0.1, 0.3)
particle.life -= THREE.MathUtils.randFloat(0.005, 0.01)

const speedX = (particle.destination.x - particle.position.x) / 200
const speedY = (particle.destination.y - particle.position.y) / 200
const speedZ = (particle.destination.z - particle.position.z) / 200
const speedX = (particle.destination.x - particle.position.x) / 200
const speedY = (particle.destination.y - particle.position.y) / 200
const speedZ = (particle.destination.z - particle.position.z) / 200

particle.position.x += speedX
particle.position.y += speedY
particle.position.z += speedZ
particle.position.x += speedX
particle.position.y += speedY
particle.position.z += speedZ

particle.rotation.y += particle.rotateSpeedY
particle.rotation.x += particle.rotateSpeedX
particle.rotation.z += particle.rotateSpeedZ
particle.rotation.y += particle.rotateSpeedY
particle.rotation.x += particle.rotateSpeedX
particle.rotation.z += particle.rotateSpeedZ

particle.material.opacity -= THREE.MathUtils.randFloat(0.005, 0.01)
particle.material.opacity -= THREE.MathUtils.randFloat(0.005, 0.01)

if (particle.position.y < -options.fallingHeight) {
particle.material.dispose()
particle.geometry.dispose()
boom.remove(particle)
particle = null
}
if (particle.position.y < -fallingHeight) {
particle.material.dispose()
particle.geometry.dispose()
boom.remove(particle)
particle = null
}
}

if (boom.children.length <= 0) {
boom.dispose()
setBooms(booms.filter((b) => b !== boom))
}
if (boom.children.length <= 0) {
boom.dispose()
setBooms(booms.filter((b) => b !== boom))
}
particleAmount += boom.children.length
}
})

Expand Down
3 changes: 1 addition & 2 deletions src/Experience.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,9 @@ const Experience = () => {
// rotation={[0, -Math.PI / 8, 0]}
azimuth={[-Math.PI / 2, Math.PI / 2]}
>

<group>
<Suspense fallback={<Fallback />}>
<Confetti isExploding={isExploding} />
<Confetti isExploding={isExploding} amount={200} rate={3} areaWidth={5} areaHeight={3} fallingHeight={6} />
<Physics debug={debugPhysics}>
<Center>
<Level />
Expand Down

1 comment on commit 4f2b2b5

@vercel
Copy link

@vercel vercel bot commented on 4f2b2b5 Aug 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.