Step 5: Polish and Special Effects
Let's add the final touches to make our game look and feel amazing! We'll add particles, improve visuals, and display helpful stats.
Adding a Cookie Emoji
Replace the plain brown circle with a cookie emoji for a better look:
function draw() {
background(240);
// ... auto-clicker code ...
// Cookie animation
if (cookieSize < 150) {
cookieSize += 2;
}
// Draw cookie background
fill('#D2691E');
circle(width/2, height/2 - 50, cookieSize);
// Draw cookie emoji on top
textSize(cookieSize * 0.8); // Scale emoji with cookie size
textAlign(CENTER, CENTER);
text('🍪', width/2, height/2 - 50);
// ... rest of code ...
}
Breaking it down:
cookieSize * 0.8makes the emoji 80% of the cookie size- This scales the emoji when the cookie shrinks on click
textAlign(CENTER, CENTER)centers the emoji perfectly
Adding Click Particles
Create a particle burst effect when clicking the cookie! First, add a particles array:
let score = 0;
let cookieSize = 150;
let floatingTexts = [];
let autoClickers = 0;
let autoClickerCost = 10;
let buttonX, buttonY;
let buttonWidth = 200;
let buttonHeight = 60;
let particles = []; // Add this
Creating Particle Objects
Update your mousePressed() to create particles when clicking the cookie:
function mousePressed() {
let d = dist(mouseX, mouseY, width/2, height/2 - 50);
if (d < 75) {
score++;
cookieSize = 135;
floatingTexts.push({
x: mouseX,
y: mouseY,
alpha: 255,
yOffset: 0
});
// Create particles burst!
for (let i = 0; i < 8; i++) {
let angle = (i / 8) * TWO_PI; // Spread evenly in circle
particles.push({
x: mouseX,
y: mouseY,
vx: cos(angle) * 3, // Velocity X
vy: sin(angle) * 3, // Velocity Y
alpha: 255,
size: random(4, 8)
});
}
}
// ... button click code ...
}
Breaking it down:
The Particle Loop
for (let i = 0; i < 8; i++) {
let angle = (i / 8) * TWO_PI;
- Creates 8 particles per click
angle = (i / 8) * TWO_PIcalculates evenly spaced angles around a circleTWO_PIis a p5.js constant equal to 2π (360 degrees)
Angle distribution:
- Particle 0:
(0/8) × 2π = 0°(right) - Particle 1:
(1/8) × 2π = 45°(diagonal) - Particle 2:
(2/8) × 2π = 90°(up) - Particle 3:
(3/8) × 2π = 135°(diagonal) - And so on... creates perfect circle pattern!
Particle Properties
particles.push({
x: mouseX,
y: mouseY,
vx: cos(angle) * 3,
vy: sin(angle) * 3,
alpha: 255,
size: random(4, 8)
});
x, y- Starting position (where you clicked)vx, vy- Velocity (speed and direction)cos(angle)gives horizontal directionsin(angle)gives vertical direction- Multiplied by 3 for speed
alpha- Opacity (starts fully visible)size- Random size between 4 and 8 pixels
Animating Particles
Add this to your draw() function:
function draw() {
background(240);
// ... auto-clicker and cookie code ...
// Update and draw particles
for (let i = particles.length - 1; i >= 0; i--) {
let p = particles[i];
// Move particle
p.x += p.vx;
p.y += p.vy;
// Fade out
p.alpha -= 8;
// Draw particle
fill(218, 165, 32, p.alpha); // Golden color
noStroke();
circle(p.x, p.y, p.size);
// Remove when invisible
if (p.alpha <= 0) {
particles.splice(i, 1);
}
}
// ... rest of code ...
}
Breaking it down:
Moving the Particle
p.x += p.vx;
p.y += p.vy;
- Adds velocity to position each frame
- Particles move outward from click point
- Direction determined by angle, speed by velocity magnitude
Drawing the Particle
fill(218, 165, 32, p.alpha);
noStroke();
circle(p.x, p.y, p.size);
fill(218, 165, 32, p.alpha)- golden color with fading alphanoStroke()- removes the outline for smoother look- Draws small circle at particle position
Adding Hover Effects
Make the button more interactive with hover effects:
function draw() {
background(240);
// ... previous code ...
// Check if mouse is over button
let overButton = mouseX > buttonX && mouseX < buttonX + buttonWidth &&
mouseY > buttonY && mouseY < buttonY + buttonHeight;
// Draw upgrade button with hover effect
if (score >= autoClickerCost) {
if (overButton) {
fill(60, 220, 60); // Brighter green on hover
} else {
fill(50, 200, 50); // Normal green
}
} else {
fill(150); // Gray when can't afford
}
// Add subtle shadow effect
if (overButton && score >= autoClickerCost) {
strokeWeight(4);
stroke(30, 100, 30);
} else {
noStroke();
}
rect(buttonX, buttonY, buttonWidth, buttonHeight, 10);
// ... button text ...
}
What this does:
- Checks if mouse is over the button
- Makes button brighter green on hover (if affordable)
- Adds a dark green border on hover for depth
Displaying Cookies Per Second
Show how fast the player is earning:
function draw() {
background(240);
// ... code ...
// Display main score with emoji
fill(0);
textSize(36);
textAlign(CENTER);
text('🍪 ' + score + ' cookies', width/2, 50);
// Display auto-clicker info
textSize(20);
if (autoClickers > 0) {
text('Auto-clickers: ' + autoClickers + ' (+' + autoClickers + '/sec)', width/2, 100);
} else {
fill(150); // Gray text when no auto-clickers
text('No auto-clickers yet', width/2, 100);
}
// ... rest of code ...
}
Adding Milestones
Celebrate player achievements with milestone messages:
function draw() {
background(240);
// ... all previous code ...
// Display milestone messages
fill(255, 200, 0); // Gold color
textSize(18);
textAlign(CENTER);
if (score >= 100 && score < 110) {
text('🎉 100 cookies! You\'re a cookie master!', width/2, 150);
} else if (score >= 500 && score < 510) {
text('🌟 500 cookies! Incredible!', width/2, 150);
} else if (score >= 1000 && score < 1010) {
text('👑 1000 COOKIES! LEGENDARY!', width/2, 150);
}
}
Breaking it down:
- Shows special message when player reaches milestones
- Uses range check (e.g.,
score >= 100 && score < 110) so message shows briefly - Different emojis for different achievements
Complete Polished Code
let score = 0;
let cookieSize = 150;
let floatingTexts = [];
let autoClickers = 0;
let autoClickerCost = 10;
let buttonX, buttonY;
let buttonWidth = 200;
let buttonHeight = 60;
let particles = [];
function setup() {
createCanvas(800, 600);
buttonX = width/2 - buttonWidth/2;
buttonY = height - 120;
}
function draw() {
background(240, 230, 220); // Warm background
// Auto-generate cookies
if (frameCount % 60 === 0 && autoClickers > 0) {
score += autoClickers;
}
// Cookie animation
if (cookieSize < 150) {
cookieSize += 2;
}
// Draw cookie with emoji
fill('#D2691E');
circle(width/2, height/2 - 50, cookieSize);
textSize(cookieSize * 0.8);
textAlign(CENTER, CENTER);
text('🍪', width/2, height/2 - 50);
// Update floating texts
for (let i = floatingTexts.length - 1; i >= 0; i--) {
let txt = floatingTexts[i];
txt.yOffset += 2;
txt.alpha -= 5;
fill(50, 200, 50, txt.alpha);
textSize(24);
textAlign(CENTER);
text('+1', txt.x, txt.y - txt.yOffset);
if (txt.alpha <= 0) {
floatingTexts.splice(i, 1);
}
}
// Update and draw particles
for (let i = particles.length - 1; i >= 0; i--) {
let p = particles[i];
p.x += p.vx;
p.y += p.vy;
p.alpha -= 8;
fill(218, 165, 32, p.alpha);
noStroke();
circle(p.x, p.y, p.size);
if (p.alpha <= 0) {
particles.splice(i, 1);
}
}
// Button hover detection
let overButton = mouseX > buttonX && mouseX < buttonX + buttonWidth &&
mouseY > buttonY && mouseY < buttonY + buttonHeight;
// Draw button with hover effect
if (score >= autoClickerCost) {
if (overButton) {
fill(60, 220, 60);
strokeWeight(4);
stroke(30, 100, 30);
} else {
fill(50, 200, 50);
noStroke();
}
} else {
fill(150);
noStroke();
}
rect(buttonX, buttonY, buttonWidth, buttonHeight, 10);
// Button text
fill(255);
textSize(16);
textAlign(CENTER, CENTER);
text('Buy Auto-Clicker', width/2, buttonY + 20);
text('Cost: ' + autoClickerCost, width/2, buttonY + 40);
// Display score
fill(0);
textSize(36);
textAlign(CENTER);
text('🍪 ' + score + ' cookies', width/2, 50);
// Display auto-clickers
textSize(20);
if (autoClickers > 0) {
text('Auto-clickers: ' + autoClickers + ' (+' + autoClickers + '/sec)', width/2, 100);
} else {
fill(150);
text('No auto-clickers yet', width/2, 100);
}
// Milestone messages
fill(255, 200, 0);
textSize(18);
if (score >= 100 && score < 110) {
text('🎉 100 cookies! You\'re a cookie master!', width/2, 150);
} else if (score >= 500 && score < 510) {
text('🌟 500 cookies! Incredible!', width/2, 150);
} else if (score >= 1000 && score < 1010) {
text('👑 1000 COOKIES! LEGENDARY!', width/2, 150);
}
}
function mousePressed() {
let d = dist(mouseX, mouseY, width/2, height/2 - 50);
if (d < 75) {
score++;
cookieSize = 135;
floatingTexts.push({
x: mouseX,
y: mouseY,
alpha: 255,
yOffset: 0
});
// Create particle burst
for (let i = 0; i < 8; i++) {
let angle = (i / 8) * TWO_PI;
particles.push({
x: mouseX,
y: mouseY,
vx: cos(angle) * 3,
vy: sin(angle) * 3,
alpha: 255,
size: random(4, 8)
});
}
}
// Button click
if (mouseX > buttonX && mouseX < buttonX + buttonWidth &&
mouseY > buttonY && mouseY < buttonY + buttonHeight) {
if (score >= autoClickerCost) {
score -= autoClickerCost;
autoClickers++;
autoClickerCost = Math.floor(autoClickerCost * 1.5);
}
}
}
Test Your Game!
You now have a complete, polished cookie clicker game! Try it and enjoy:
- ✅ Beautiful cookie emoji that shrinks on click
- ✅ Particle burst effects on every click
- ✅ Floating +1 text feedback
- ✅ Hover effects on the button
- ✅ Auto-clicker system with scaling costs
- ✅ Milestone celebrations
- ✅ Clear stats display
Ideas for Further Enhancement
More Upgrade Types
let multipliers = 0;
let multiplierCost = 100;
// Make each click worth more!
Sound Effects
// In mousePressed() when clicking cookie
if (d < 75) {
// Play sound (requires p5.sound library)
// clickSound.play();
}
Save System
function saveGame() {
localStorage.setItem('cookieScore', score);
localStorage.setItem('cookieAutoClickers', autoClickers);
}
function loadGame() {
score = parseInt(localStorage.getItem('cookieScore')) || 0;
autoClickers = parseInt(localStorage.getItem('cookieAutoClickers')) || 0;
}
Different Cookie Types
let cookieEmojis = ['🍪', '🥠', '🧁', '🍩'];
let currentCookie = 0;
// Unlock new cookie types at milestones!
What You Learned
- How to use
cos()andsin()to create circular patterns - How to use
TWO_PIfor angle calculations - How to create particle systems with velocity
- How to detect mouse hover on rectangles
- How to add visual polish with colors, emojis, and effects
- How to create milestone systems for player engagement
- How to use
random()for variety - How to combine multiple effects for satisfying game feel
Congratulations! 🎉
You've built a complete cookie clicker game from scratch! You've learned fundamental game development concepts:
- User input handling
- Animation systems
- Upgrade mechanics
- Visual feedback
- Game economy balancing
Keep experimenting and adding your own features! 🍪