Skip to main content

Step 4: Add Auto-Clickers

Now let's add a way to earn cookies automatically! Players can buy "auto-clickers" that generate cookies every second, creating an idle game mechanic.

New Variables for Upgrades

Add these new variables to track the upgrade system:

let score = 0;
let cookieSize = 150;
let floatingTexts = [];
let autoClickers = 0; // Add this
let autoClickerCost = 10; // Add this

What these do:

  • autoClickers - How many auto-clickers the player has purchased
  • autoClickerCost - Current price to buy the next auto-clicker (starts at 10)

Creating the Upgrade Button

We'll use rectangle coordinates to track our button. Add these variables:

let score = 0;
let cookieSize = 150;
let floatingTexts = [];
let autoClickers = 0;
let autoClickerCost = 10;
// Button properties
let buttonX;
let buttonY;
let buttonWidth = 200;
let buttonHeight = 60;

In setup(), calculate the button position:

function setup() {
createCanvas(800, 600);

// Position button at bottom center
buttonX = width/2 - buttonWidth/2;
buttonY = height - 120;
}

Breaking it down:

  • buttonX = width/2 - buttonWidth/2 centers the button horizontally
    • width/2 is the center of the canvas
    • Subtract half the button width to align its left edge
  • buttonY = height - 120 positions it near the bottom (120 pixels from bottom)

Auto-Generating Cookies

In your draw() function, add code to automatically generate cookies:

function draw() {
background(240);

// Auto-generate cookies every second
if (frameCount % 60 === 0 && autoClickers > 0) {
score += autoClickers;
}

// ... rest of your code
}

Breaking it down:

The Modulo Operator

if (frameCount % 60 === 0 && autoClickers > 0) {
score += autoClickers;
}
  • frameCount is a p5.js variable that counts frames since the program started
  • % is the modulo operator - it gives the remainder after division
  • frameCount % 60 === 0 is true every 60 frames (once per second at 60 FPS)
  • autoClickers > 0 checks that we actually have auto-clickers
  • score += autoClickers adds the number of auto-clickers to the score
tip

How modulo works:

  • Frame 59: 59 % 60 = 59 (not equal to 0)
  • Frame 60: 60 % 60 = 0 ✓ (trigger!)
  • Frame 61: 61 % 60 = 1 (not equal to 0)
  • Frame 120: 120 % 60 = 0 ✓ (trigger again!)

It's like a repeating timer!

Drawing the Button

Add this to your draw() function to display the button:

function draw() {
background(240);

// Auto-generate cookies
if (frameCount % 60 === 0 && autoClickers > 0) {
score += autoClickers;
}

// ... cookie drawing and floating text code ...

// Draw upgrade button
if (score >= autoClickerCost) {
fill(50, 200, 50); // Green if affordable
} else {
fill(150); // Gray if too expensive
}
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 auto-clicker count
fill(0);
textSize(20);
text('Auto-clickers: ' + autoClickers + ' (+' + autoClickers + '/sec)', width/2, 100);

// ... score display code ...
}

Breaking it down:

Conditional Button Color

if (score >= autoClickerCost) {
fill(50, 200, 50); // Green if affordable
} else {
fill(150); // Gray if too expensive
}
  • Checks if player has enough points
  • Green button = can buy
  • Gray button = cannot afford yet
  • This gives visual feedback to the player

Drawing the Button

rect(buttonX, buttonY, buttonWidth, buttonHeight, 10);
  • rect() draws a rectangle
  • Position: buttonX, buttonY (calculated in setup)
  • Size: buttonWidth, buttonHeight (200 x 60)
  • 10 is the corner radius for rounded corners

Centered Text

textAlign(CENTER, CENTER);
text('Buy Auto-Clicker', width/2, buttonY + 20);
text('Cost: ' + autoClickerCost, width/2, buttonY + 40);
  • textAlign(CENTER, CENTER) centers text both horizontally and vertically
  • buttonY + 20 and buttonY + 40 position text lines inside the button

Buying Auto-Clickers

Update your mousePressed() function to handle button clicks:

function mousePressed() {
// Check if cookie is clicked
let d = dist(mouseX, mouseY, width/2, height/2);

if (d < 75) {
score++;
cookieSize = 135;

floatingTexts.push({
x: mouseX,
y: mouseY,
alpha: 255,
yOffset: 0
});
}

// Check if upgrade button is clicked
if (mouseX > buttonX && mouseX < buttonX + buttonWidth &&
mouseY > buttonY && mouseY < buttonY + buttonHeight) {

// Check if player can afford it
if (score >= autoClickerCost) {
score -= autoClickerCost; // Deduct the cost
autoClickers++; // Add one auto-clicker
autoClickerCost = Math.floor(autoClickerCost * 1.5); // Increase price
}
}
}

Breaking it down:

Button Click Detection

if (mouseX > buttonX && mouseX < buttonX + buttonWidth &&
mouseY > buttonY && mouseY < buttonY + buttonHeight) {

This checks if the mouse is inside the button rectangle:

  • mouseX > buttonX - mouse is to the right of left edge
  • mouseX < buttonX + buttonWidth - mouse is to the left of right edge
  • mouseY > buttonY - mouse is below top edge
  • mouseY < buttonY + buttonHeight - mouse is above bottom edge
  • All four must be true = click is inside button

Purchase Logic

if (score >= autoClickerCost) {
score -= autoClickerCost;
autoClickers++;
autoClickerCost = Math.floor(autoClickerCost * 1.5);
}
  • Check if player has enough cookies
  • Subtract the cost from score
  • Add one auto-clicker
  • Increase the price by 50% (multiply by 1.5)
  • Math.floor() rounds down to whole number
info

Why increase the price? This is called "exponential scaling" - each upgrade gets more expensive. This creates balanced progression and prevents players from buying everything too quickly!

Complete Code

let score = 0;
let cookieSize = 150;
let floatingTexts = [];
let autoClickers = 0;
let autoClickerCost = 10;
let buttonX, buttonY;
let buttonWidth = 200;
let buttonHeight = 60;

function setup() {
createCanvas(800, 600);
buttonX = width/2 - buttonWidth/2;
buttonY = height - 120;
}

function draw() {
background(240);

// Auto-generate cookies every second
if (frameCount % 60 === 0 && autoClickers > 0) {
score += autoClickers;
}

// Cookie animation
if (cookieSize < 150) {
cookieSize += 2;
}

// Draw cookie
fill('#D2691E');
circle(width/2, height/2 - 50, cookieSize);

// 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);
}
}

// Draw upgrade button
if (score >= autoClickerCost) {
fill(50, 200, 50);
} else {
fill(150);
}
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 stats
fill(0);
textSize(32);
textAlign(CENTER);
text('Score: ' + score, width/2, 50);

textSize(20);
text('Auto-clickers: ' + autoClickers + ' (+' + autoClickers + '/sec)', width/2, 100);
}

function mousePressed() {
// Cookie click
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
});
}

// 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 It Out!

Run the game and try it:

  1. ✅ Click cookie until you have 10 points
  2. ✅ Button turns green when you can afford it
  3. ✅ Click button to buy first auto-clicker
  4. ✅ Watch score increase by 1 every second
  5. ✅ Notice button now costs 15 (increased by 50%)
  6. ✅ Buy more auto-clickers and watch cookies accumulate faster!

How the Price Scaling Works

Purchase #1: Cost = 10 × 1.5 = 15
Purchase #2: Cost = 15 × 1.5 = 22 (rounded from 22.5)
Purchase #3: Cost = 22 × 1.5 = 33
Purchase #4: Cost = 33 × 1.5 = 49 (rounded from 49.5)
Purchase #5: Cost = 49 × 1.5 = 73 (rounded from 73.5)

Each purchase gets significantly more expensive, creating balanced progression!

What You Learned

  • How to use frameCount and modulo (%) to create timed events
  • How to detect clicks on rectangular buttons
  • How to implement conditional visual feedback (button color changes)
  • How to create an upgrade system with increasing costs
  • How to use Math.floor() for integer rounding
  • How to balance game economy with exponential cost scaling
  • How to use textAlign(CENTER, CENTER) for perfectly centered text