| 60 | } |
| 61 | |
| 62 | const animate = () => { |
| 63 | if (!ctx) return |
| 64 | ctx.clearRect(0, 0, canvas.width, canvas.height) |
| 65 | |
| 66 | particles.current = particles.current.filter((particle) => { |
| 67 | particle.x += particle.velocity.x |
| 68 | particle.y += particle.velocity.y |
| 69 | particle.velocity.y += 0.1 // gravity |
| 70 | particle.rotation += particle.rotationSpeed |
| 71 | |
| 72 | if (particle.y < canvas.height) { |
| 73 | ctx.save() |
| 74 | ctx.translate(particle.x, particle.y) |
| 75 | ctx.rotate(particle.rotation) |
| 76 | ctx.font = `${particle.size}px Arial` |
| 77 | ctx.textAlign = 'center' |
| 78 | ctx.textBaseline = 'middle' |
| 79 | ctx.fillText(particle.emoji, 0, 0) |
| 80 | ctx.restore() |
| 81 | return true |
| 82 | } |
| 83 | return false |
| 84 | }) |
| 85 | |
| 86 | if (particles.current.length > 0) { |
| 87 | requestAnimationFrame(animate) |
| 88 | } else { |
| 89 | setIsExploding(false) |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | animate() |
| 94 | |