Skip to main content

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.

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.8 makes 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_PI calculates evenly spaced angles around a circle
  • TWO_PI is a p5.js constant equal to 2π (360 degrees)
tip

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 direction
    • sin(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 alpha
  • noStroke() - 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;
}
let cookieEmojis = ['🍪', '🥠', '🧁', '🍩'];
let currentCookie = 0;
// Unlock new cookie types at milestones!

What You Learned

  • How to use cos() and sin() to create circular patterns
  • How to use TWO_PI for 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! 🍪