setup()
setup() runs once when the sketch loads. It creates the canvas, centers the interactive emoji on screen using flexbox and CSS transforms, and loops through the upgrades array to generate a button for each one. Notice how p5.js elements (createDiv, createButton) let you build DOM elements that mix seamlessly with the canvas.
🔬 This loop creates one button per upgrade. What happens if you change the condition to i < upgrades.length - 1? Which upgrade disappears?
for (let i = 0; i < upgrades.length; i++) {
let upgrade = upgrades[i];
let currentCost = calculateUpgradeCost(upgrade);
let buttonText = `${upgrade.emoji} ${upgrade.name} (Level ${upgrade.level}) - Cost: ${nfc(currentCost, 0)} points`;
// Create the p5.Element button
upgrade.button = createButton(buttonText);
function setup() {
createCanvas(windowWidth, windowHeight);
// Tip: Use windowWidth/windowHeight for responsive canvas
// Create a container div for the main emoji and score
mainContainerDiv = createDiv('');
mainContainerDiv.style('position', 'absolute');
mainContainerDiv.style('left', '50%');
mainContainerDiv.style('top', '50%');
mainContainerDiv.style('transform', 'translate(-50%, -50%)'); // Center the container
mainContainerDiv.style('display', 'flex');
mainContainerDiv.style('flex-direction', 'column'); // Stack children vertically
mainContainerDiv.style('align-items', 'center'); // Center children horizontally
// Create the score display as a p5.Element (div)
scoreDiv = createDiv(`Emoji Points: ${nfc(score, 0)}`);
scoreDiv.parent(mainContainerDiv); // Make it a child of the main container
scoreDiv.style('font-size', '48px');
scoreDiv.style('margin-bottom', '20px'); // Add space between score and emoji
scoreDiv.style('user-select', 'none'); // Prevent text selection
scoreDiv.style('color', '#000'); // Ensure visibility against background
// Create the main clickable emoji as a p5.Element (div)
mainEmojiDiv = createDiv('😀'); // Changed emoji here
mainEmojiDiv.parent(mainContainerDiv); // Make it a child of the main container
mainEmojiDiv.style('font-size', '150px'); // Large emoji
mainEmojiDiv.style('cursor', 'pointer'); // Indicate it's clickable
mainEmojiDiv.style('user-select', 'none'); // Prevent text selection on click
mainEmojiDiv.mousePressed(clickEmoji); // Attach click handler
// Create upgrade buttons
// Position them on the right side of the canvas
let buttonX = width - 220;
let buttonY = 50;
let buttonHeight = 60;
let buttonSpacing = 10;
for (let i = 0; i < upgrades.length; i++) {
let upgrade = upgrades[i];
let currentCost = calculateUpgradeCost(upgrade);
let buttonText = `${upgrade.emoji} ${upgrade.name} (Level ${upgrade.level}) - Cost: ${nfc(currentCost, 0)} points`;
// Create the p5.Element button
upgrade.button = createButton(buttonText);
upgrade.button.position(buttonX, buttonY + i * (buttonHeight + buttonSpacing));
upgrade.button.style('width', '200px');
upgrade.button.style('height', `${buttonHeight}px`);
upgrade.button.style('font-size', '16px');
upgrade.button.style('cursor', 'pointer');
upgrade.button.style('background-color', '#fff');
upgrade.button.style('border', '2px solid #ccc');
upgrade.button.style('border-radius', '8px');
upgrade.button.style('text-align', 'left');
upgrade.button.style('padding-left', '10px');
upgrade.button.style('font-family', 'sans-serif'); // Ensure font supports emojis
// Attach a mousePressed handler, using an arrow function to capture the correct upgrade
upgrade.button.mousePressed(() => purchaseUpgrade(upgrade));
}
}
Line-by-line explanation (12 lines)
🔧 Subcomponents:
createCanvas(windowWidth, windowHeight);
Sets up a canvas that fills the entire browser window, using window dimensions instead of fixed pixels
mainContainerDiv.style('transform', 'translate(-50%, -50%)');
Uses CSS transform to perfectly center the emoji and score display on screen
for (let i = 0; i < upgrades.length; i++) {
Loops through the upgrades array and creates a button for each one, positioning them vertically
createCanvas(windowWidth, windowHeight);- Creates a canvas that matches the browser window size, allowing the sketch to fill the entire screen
mainContainerDiv = createDiv('');- Creates an empty div element that will act as a container holding the score and emoji together
mainContainerDiv.style('position', 'absolute');- Uses absolute positioning so the container can be positioned anywhere on screen independently of canvas
mainContainerDiv.style('left', '50%');- Moves the container to the horizontal center, aligning its left edge to 50% across the screen
mainContainerDiv.style('transform', 'translate(-50%, -50%)');- Shifts the container back by half its own width and height, centering it perfectly on screen
mainContainerDiv.style('display', 'flex');- Enables flexbox layout so child elements can be easily arranged and aligned
scoreDiv = createDiv(`Emoji Points: ${nfc(score, 0)}`); scoreDiv.parent(mainContainerDiv);- Creates the score display div and makes it a child of the main container so it gets centered too
mainEmojiDiv = createDiv('😀');- Creates a div element containing the smiley emoji—this will be the clickable game object
mainEmojiDiv.mousePressed(clickEmoji);- Attaches a click event handler so clicking the emoji calls the clickEmoji() function
for (let i = 0; i < upgrades.length; i++) {- Loops through each upgrade object in the upgrades array, from index 0 to 4
upgrade.button = createButton(buttonText);- Creates a button element for this upgrade and stores a reference to it in the upgrade object
upgrade.button.mousePressed(() => purchaseUpgrade(upgrade));- Attaches a click handler using an arrow function to ensure the correct upgrade object is passed to purchaseUpgrade()