Step 5: Add Multiple Upgrades
Let's expand the upgrade system! Instead of just auto-clickers, we'll add multiple types of upgrades that enhance your clicking power or generate cookies in different ways.
Understanding the Upgrade System
An upgrade system needs to track:
- What upgrades exist - Their names, costs, effects
- How many of each - Player's current quantity of each upgrade
- Visual representation - Buttons to display and purchase upgrades
- Active effects - How each upgrade changes gameplay
Setting Up the Upgrade Object
Instead of separate variables for each upgrade, let's use an object to organize upgrades efficiently:
let upgrades = {
autoClicker: {
name: 'Auto-Clicker',
cost: 10,
owned: 0,
baseCost: 10,
effect: 1 // Cookies per second
},
clickBoost: {
name: 'Click Boost',
cost: 50,
owned: 0,
baseCost: 50,
effect: 1 // Extra cookies per click
},
speedBoost: {
name: 'Speed Boost',
cost: 100,
owned: 0,
baseCost: 100,
effect: 0.5 // Multiplier for auto-clicker speed
}
};
let cookiesPerClick = 1; // Affected by Click Boost
let clickMultiplier = 1; // Affected by Speed Boost
What this does:
name- Display name for the upgradecost- Current price to buy oneowned- How many player has purchasedbaseCost- Original price (for calculating new prices)effect- How much value this upgrade provides
Creating a Button Layout for Upgrades
Add button tracking for the upgrade buttons:
let upgradeButtons = {
autoClicker: { x: 50, y: 450, width: 150, height: 60 },
clickBoost: { x: 250, y: 450, width: 150, height: 60 },
speedBoost: { x: 450, y: 450, width: 150, height: 60 }
};
function setup() {
createCanvas(800, 600);
}
Drawing Upgrade Buttons
Add this code to your draw() function to display all upgrade buttons:
function draw() {
background(240, 230, 220);
// ... auto-generate and draw cookie code ...
// Draw all upgrade buttons
drawUpgradeButtons();
// ... score display code ...
}
function drawUpgradeButtons() {
// Loop through each upgrade and draw its button
for (let upgradeKey in upgrades) {
let upgrade = upgrades[upgradeKey];
let button = upgradeButtons[upgradeKey];
// Check if player can afford this upgrade
let canAfford = score >= upgrade.cost;
// Draw button background
if (canAfford) {
fill(100, 200, 100); // Green if affordable
} else {
fill(150); // Gray if too expensive
}
// Draw button
rect(button.x, button.y, button.width, button.height, 8);
// Draw text on button
fill(255);
textSize(14);
textAlign(CENTER, CENTER);
text(upgrade.name, button.x + button.width/2, button.y + 15);
text('Cost: ' + upgrade.cost, button.x + button.width/2, button.y + 35);
text('Owned: ' + upgrade.owned, button.x + button.width/2, button.y + 50);
}
}
Breaking it down:
for (let upgradeKey in upgrades)loops through each upgrade- We check if the player can afford it with
score >= upgrade.cost - Different colors provide visual feedback (green = affordable, gray = too expensive)
- We display the upgrade name, cost, and quantity owned
Handling Upgrade Purchases
In your mousePressed() function, add code to handle upgrade button clicks:
function mousePressed() {
// Check if cookie is clicked
let d = dist(mouseX, mouseY, width/2, height/2 - 50);
if (d < 75) {
// Click on cookie - apply click boost
score += cookiesPerClick;
cookieSize = 135;
// ... floating text and particle effects ...
}
// Check upgrade button clicks
for (let upgradeKey in upgrades) {
let button = upgradeButtons[upgradeKey];
if (mouseX > button.x && mouseX < button.x + button.width &&
mouseY > button.y && mouseY < button.y + button.height) {
purchaseUpgrade(upgradeKey);
}
}
}
function purchaseUpgrade(upgradeKey) {
let upgrade = upgrades[upgradeKey];
// Check if player can afford it
if (score >= upgrade.cost) {
score -= upgrade.cost;
upgrade.owned++;
// Apply upgrade effects based on type
if (upgradeKey === 'autoClicker') {
// Auto-clickers add to passive income
} else if (upgradeKey === 'clickBoost') {
cookiesPerClick += upgrade.effect;
} else if (upgradeKey === 'speedBoost') {
clickMultiplier += upgrade.effect;
}
// Calculate new cost (increases with exponential growth)
upgrade.cost = Math.floor(upgrade.baseCost * Math.pow(1.15, upgrade.owned));
}
}
Breaking it down:
Math.pow(1.15, upgrade.owned)calculates exponential cost growth- Each upgrade owned multiplies the cost by 1.15 (15% increase)
- This prevents the game from becoming too easy as the player progresses
- Different upgrade types have different effects
Applying Upgrade Effects in the Main Loop
Modify your auto-generation code to account for upgrades:
function draw() {
background(240, 230, 220);
// Auto-generate cookies from auto-clickers
if (frameCount % 60 === 0 && upgrades.autoClicker.owned > 0) {
let autoClickerIncome = upgrades.autoClicker.owned * upgrades.autoClicker.effect;
// Apply speed boost multiplier
autoClickerIncome *= (1 + upgrades.speedBoost.owned * 0.5);
score += autoClickerIncome;
}
// ... rest of your code ...
}
Displaying Upgrade Statistics
Add this code to show the player their current upgrade benefits:
function draw() {
background(240, 230, 220);
// ... auto-generate and draw cookie code ...
// Display upgrade stats
fill(0);
textSize(16);
textAlign(LEFT);
let statsX = 20;
let statsY = 150;
text('Cookies per click: ' + cookiesPerClick, statsX, statsY);
text('Speed multiplier: ' + (1 + upgrades.speedBoost.owned * 0.5).toFixed(2) + 'x',
statsX, statsY + 25);
let totalPassiveIncome = upgrades.autoClicker.owned * upgrades.autoClicker.effect *
(1 + upgrades.speedBoost.owned * 0.5);
text('Passive income: +' + Math.floor(totalPassiveIncome) + '/sec',
statsX, statsY + 50);
// ... rest of your code ...
}
Complete Example: All Upgrades Together
Here's a complete working example with three upgrades:
// Global variables
let score = 0;
let cookieSize = 150;
let cookieImage;
let floatingTexts = [];
let particles = [];
let cookiesPerClick = 1;
let upgrades = {
autoClicker: {
name: 'Auto-Clicker',
cost: 10,
owned: 0,
baseCost: 10,
effect: 1
},
clickBoost: {
name: 'Click Boost',
cost: 50,
owned: 0,
baseCost: 50,
effect: 1
},
speedBoost: {
name: 'Speed Boost',
cost: 100,
owned: 0,
baseCost: 100,
effect: 0.5
}
};
let upgradeButtons = {
autoClicker: { x: 50, y: 450, width: 150, height: 60 },
clickBoost: { x: 250, y: 450, width: 150, height: 60 },
speedBoost: { x: 450, y: 450, width: 150, height: 60 }
};
function preload() {
cookieImage = loadImage('https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT-0fda82kJu_k4skgYTqbZFam6J6zaK6bw2A&s');
}
function setup() {
createCanvas(800, 600);
}
function draw() {
background(240, 230, 220);
// Auto-generate cookies
if (frameCount % 60 === 0 && upgrades.autoClicker.owned > 0) {
let autoClickerIncome = upgrades.autoClicker.owned * upgrades.autoClicker.effect;
autoClickerIncome *= (1 + upgrades.speedBoost.owned * 0.5);
score += autoClickerIncome;
}
// Cookie animation
if (cookieSize < 150) {
cookieSize += 2;
}
// Draw the cookie
push();
imageMode(CENTER);
image(cookieImage, width/2, height/2 - 50, cookieSize, cookieSize);
pop();
// Update and draw 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('+' + txt.amount, 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);
}
}
// Draw upgrade buttons
drawUpgradeButtons();
// Display score
fill(0);
textSize(36);
textAlign(CENTER);
text(score + ' cookies', width/2, 50);
// Display upgrade stats
textSize(16);
textAlign(LEFT);
text('Per click: ' + cookiesPerClick, 20, 150);
text('Speed: ' + (1 + upgrades.speedBoost.owned * 0.5).toFixed(2) + 'x', 20, 180);
}
function drawUpgradeButtons() {
for (let upgradeKey in upgrades) {
let upgrade = upgrades[upgradeKey];
let button = upgradeButtons[upgradeKey];
let canAfford = score >= upgrade.cost;
if (canAfford) {
fill(100, 200, 100);
} else {
fill(150);
}
rect(button.x, button.y, button.width, button.height, 8);
fill(255);
textSize(14);
textAlign(CENTER, CENTER);
text(upgrade.name, button.x + button.width/2, button.y + 15);
text('Cost: ' + upgrade.cost, button.x + button.width/2, button.y + 35);
text('Owned: ' + upgrade.owned, button.x + button.width/2, button.y + 50);
}
}
function mousePressed() {
// Check if cookie is clicked
let d = dist(mouseX, mouseY, width/2, height/2 - 50);
if (d < 75) {
score += cookiesPerClick;
cookieSize = 135;
floatingTexts.push({
x: mouseX,
y: mouseY,
amount: cookiesPerClick,
alpha: 255,
yOffset: 0
});
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)
});
}
}
// Check upgrade button clicks
for (let upgradeKey in upgrades) {
let button = upgradeButtons[upgradeKey];
if (mouseX > button.x && mouseX < button.x + button.width &&
mouseY > button.y && mouseY < button.y + button.height) {
purchaseUpgrade(upgradeKey);
}
}
}
function purchaseUpgrade(upgradeKey) {
let upgrade = upgrades[upgradeKey];
if (score >= upgrade.cost) {
score -= upgrade.cost;
upgrade.owned++;
if (upgradeKey === 'clickBoost') {
cookiesPerClick += upgrade.effect;
}
upgrade.cost = Math.floor(upgrade.baseCost * Math.pow(1.15, upgrade.owned));
}
}
Tips for Extending This System
Add More Upgrades
Add new upgrades by extending the upgrades object:
let upgrades = {
// ... existing upgrades ...
goldenCookie: {
name: 'Golden Cookie',
cost: 500,
owned: 0,
baseCost: 500,
effect: 0.1 // 10% score boost chance
}
};
Create a Shop Layout
Use a scrollable menu or grid layout for many upgrades:
let upgradeButtons = {
// Row 1
autoClicker: { x: 50, y: 450, width: 150, height: 60 },
// Row 2
clickBoost: { x: 50, y: 520, width: 150, height: 60 },
// And so on...
};
Synergies Between Upgrades
Make upgrades interact:
function purchaseUpgrade(upgradeKey) {
let upgrade = upgrades[upgradeKey];
if (score >= upgrade.cost) {
score -= upgrade.cost;
upgrade.owned++;
// Synergy: speedBoost makes autoClickers more efficient
if (upgradeKey === 'speedBoost' && upgrades.autoClicker.owned > 0) {
score += 10; // Bonus cookies when synergy is triggered
}
upgrade.cost = Math.floor(upgrade.baseCost * Math.pow(1.15, upgrade.owned));
}
}
Next Steps
Once you have the basic upgrade system working:
- Experiment with costs - Adjust
baseCostand growth rates - Add visual effects - Highlight recently purchased upgrades
- Create descriptions - Add tooltips explaining what each upgrade does
- Balance gameplay - Adjust effects so progression feels rewarding