278 lines
9.6 KiB
JavaScript
278 lines
9.6 KiB
JavaScript
/**
|
|
* Cosmic Garden - Particle System
|
|
* Creates visual particle effects for clicks and achievements
|
|
*/
|
|
|
|
const Particles = {
|
|
/**
|
|
* Create sparkle particles on click
|
|
*/
|
|
createClickParticles(x, y, count = 8) {
|
|
const colors = ['#ffd700', '#9b59b6', '#3498db', '#2ecc71', '#ffffff'];
|
|
|
|
for (let i = 0; i < count; i++) {
|
|
const particle = document.createElement('div');
|
|
particle.className = 'particle';
|
|
|
|
// Random properties
|
|
const angle = (Math.PI * 2 * i) / count + (Math.random() - 0.5);
|
|
const velocity = 50 + Math.random() * 50;
|
|
const size = 6 + Math.random() * 8;
|
|
const color = colors[Math.floor(Math.random() * colors.length)];
|
|
|
|
particle.style.cssText = `
|
|
left: ${x}px;
|
|
top: ${y}px;
|
|
width: ${size}px;
|
|
height: ${size}px;
|
|
background: ${color};
|
|
border-radius: 50%;
|
|
pointer-events: none;
|
|
position: fixed;
|
|
z-index: 998;
|
|
`;
|
|
|
|
document.body.appendChild(particle);
|
|
|
|
// Animate
|
|
const animation = particle.animate([
|
|
{
|
|
transform: 'translate(-50%, -50%) scale(1)',
|
|
opacity: 1
|
|
},
|
|
{
|
|
transform: `translate(calc(-50% + ${Math.cos(angle) * velocity}px), calc(-50% + ${Math.sin(angle) * velocity}px)) scale(0)`,
|
|
opacity: 0
|
|
}
|
|
], {
|
|
duration: 600 + Math.random() * 200,
|
|
easing: 'cubic-bezier(0, 0.9, 0.57, 1)'
|
|
});
|
|
|
|
animation.onfinish = () => particle.remove();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Create achievement unlock effect
|
|
*/
|
|
createAchievementEffect(x, y) {
|
|
const colors = ['#ffd700', '#ff6b6b', '#4ecdc4', '#45b7d1', '#96ceb4'];
|
|
|
|
// Burst of particles
|
|
for (let i = 0; i < 20; i++) {
|
|
const particle = document.createElement('div');
|
|
particle.className = 'particle achievement-particle';
|
|
|
|
const angle = (Math.PI * 2 * i) / 20;
|
|
const velocity = 80 + Math.random() * 60;
|
|
const size = 8 + Math.random() * 12;
|
|
const color = colors[Math.floor(Math.random() * colors.length)];
|
|
|
|
particle.style.cssText = `
|
|
left: ${x}px;
|
|
top: ${y}px;
|
|
width: ${size}px;
|
|
height: ${size}px;
|
|
background: ${color};
|
|
border-radius: 50%;
|
|
pointer-events: none;
|
|
position: fixed;
|
|
z-index: 998;
|
|
box-shadow: 0 0 10px ${color};
|
|
`;
|
|
|
|
document.body.appendChild(particle);
|
|
|
|
const animation = particle.animate([
|
|
{
|
|
transform: 'translate(-50%, -50%) scale(1)',
|
|
opacity: 1
|
|
},
|
|
{
|
|
transform: `translate(calc(-50% + ${Math.cos(angle) * velocity}px), calc(-50% + ${Math.sin(angle) * velocity}px)) scale(0.5)`,
|
|
opacity: 0.8
|
|
},
|
|
{
|
|
transform: `translate(calc(-50% + ${Math.cos(angle) * velocity * 1.5}px), calc(-50% + ${Math.sin(angle) * velocity * 1.5}px)) scale(0)`,
|
|
opacity: 0
|
|
}
|
|
], {
|
|
duration: 1000,
|
|
easing: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)'
|
|
});
|
|
|
|
animation.onfinish = () => particle.remove();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Create building purchase effect
|
|
*/
|
|
createBuildingEffect(x, y) {
|
|
const colors = ['#2ecc71', '#27ae60', '#1abc9c'];
|
|
|
|
for (let i = 0; i < 12; i++) {
|
|
const particle = document.createElement('div');
|
|
particle.className = 'particle building-particle';
|
|
|
|
const angle = (Math.PI * 2 * i) / 12;
|
|
const velocity = 60 + Math.random() * 40;
|
|
const size = 5 + Math.random() * 6;
|
|
const color = colors[Math.floor(Math.random() * colors.length)];
|
|
|
|
particle.style.cssText = `
|
|
left: ${x}px;
|
|
top: ${y}px;
|
|
width: ${size}px;
|
|
height: ${size}px;
|
|
background: ${color};
|
|
border-radius: 2px;
|
|
pointer-events: none;
|
|
position: fixed;
|
|
z-index: 998;
|
|
`;
|
|
|
|
document.body.appendChild(particle);
|
|
|
|
const animation = particle.animate([
|
|
{
|
|
transform: 'translate(-50%, -50%) rotate(0deg) scale(1)',
|
|
opacity: 1
|
|
},
|
|
{
|
|
transform: `translate(calc(-50% + ${Math.cos(angle) * velocity}px), calc(-50% + ${Math.sin(angle) * velocity}px)) rotate(${360 + Math.random() * 180}deg) scale(0)`,
|
|
opacity: 0
|
|
}
|
|
], {
|
|
duration: 700,
|
|
easing: 'ease-out'
|
|
});
|
|
|
|
animation.onfinish = () => particle.remove();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Create ambient floating stars in the background
|
|
*/
|
|
createAmbientStars(count = 15) {
|
|
for (let i = 0; i < count; i++) {
|
|
const star = document.createElement('div');
|
|
star.className = 'ambient-star';
|
|
|
|
const size = 2 + Math.random() * 3;
|
|
const left = Math.random() * 100;
|
|
const delay = Math.random() * 5;
|
|
const duration = 3 + Math.random() * 2;
|
|
|
|
star.style.cssText = `
|
|
width: ${size}px;
|
|
height: ${size}px;
|
|
left: ${left}%;
|
|
top: ${Math.random() * 100}%;
|
|
animation-delay: ${delay}s;
|
|
animation-duration: ${duration}s;
|
|
`;
|
|
|
|
document.getElementById('game-container').appendChild(star);
|
|
}
|
|
}
|
|
/**
|
|
* Create prestige reset effect - cosmic explosion
|
|
*/
|
|
createPrestigeEffect(x, y) {
|
|
const colors = ['#ffd700', '#9b59b6', '#3498db', '#ffffff', '#e74c3c'];
|
|
|
|
// Outer ring burst
|
|
for (let i = 0; i < 30; i++) {
|
|
const particle = document.createElement('div');
|
|
particle.className = 'particle prestige-particle';
|
|
|
|
const angle = (Math.PI * 2 * i) / 30;
|
|
const velocity = 100 + Math.random() * 80;
|
|
const size = 10 + Math.random() * 15;
|
|
const color = colors[Math.floor(Math.random() * colors.length)];
|
|
|
|
particle.style.cssText = `
|
|
left: ${x}px;
|
|
top: ${y}px;
|
|
width: ${size}px;
|
|
height: ${size}px;
|
|
background: ${color};
|
|
border-radius: 50%;
|
|
pointer-events: none;
|
|
position: fixed;
|
|
z-index: 998;
|
|
box-shadow: 0 0 15px ${color}, 0 0 30px ${color};
|
|
`;
|
|
|
|
document.body.appendChild(particle);
|
|
|
|
const animation = particle.animate([
|
|
{
|
|
transform: 'translate(-50%, -50%) scale(1)',
|
|
opacity: 1
|
|
},
|
|
{
|
|
transform: `translate(calc(-50% + ${Math.cos(angle) * velocity}px), calc(-50% + ${Math.sin(angle) * velocity}px)) scale(1.5)`,
|
|
opacity: 0.8
|
|
},
|
|
{
|
|
transform: `translate(calc(-50% + ${Math.cos(angle) * velocity * 2}px), calc(-50% + ${Math.sin(angle) * velocity * 2}px)) scale(0)`,
|
|
opacity: 0
|
|
}
|
|
], {
|
|
duration: 1500,
|
|
easing: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)'
|
|
});
|
|
|
|
animation.onfinish = () => particle.remove();
|
|
}
|
|
|
|
// Inner sparkle burst
|
|
for (let i = 0; i < 15; i++) {
|
|
const sparkle = document.createElement('div');
|
|
sparkle.className = 'particle';
|
|
|
|
const angle = Math.random() * Math.PI * 2;
|
|
const velocity = 50 + Math.random() * 50;
|
|
const size = 4 + Math.random() * 6;
|
|
|
|
sparkle.style.cssText = `
|
|
left: ${x}px;
|
|
top: ${y}px;
|
|
width: ${size}px;
|
|
height: ${size}px;
|
|
background: #ffd700;
|
|
border-radius: 50%;
|
|
pointer-events: none;
|
|
position: fixed;
|
|
z-index: 998;
|
|
box-shadow: 0 0 10px #ffd700;
|
|
`;
|
|
|
|
document.body.appendChild(sparkle);
|
|
|
|
const animation = sparkle.animate([
|
|
{
|
|
transform: 'translate(-50%, -50%) scale(1)',
|
|
opacity: 1
|
|
},
|
|
{
|
|
transform: `translate(calc(-50% + ${Math.cos(angle) * velocity}px), calc(-50% + ${Math.sin(angle) * velocity}px)) scale(0)`,
|
|
opacity: 0
|
|
}
|
|
], {
|
|
duration: 800,
|
|
easing: 'ease-out'
|
|
});
|
|
|
|
animation.onfinish = () => sparkle.remove();
|
|
}
|
|
},
|
|
};
|
|
|
|
// Make globally accessible
|
|
window.Particles = Particles;
|