the spider man

This sketch creates an interactive Spider-Man swinging game where the player guides Spider-Man through a scrolling city by shooting webs between buildings. The character swings on physics-based web dynamics, collecting points as buildings scroll past, with the game ending if Spider-Man falls off the bottom of the screen.

🧪 Try This!

Experiment with the code by making these changes:

  1. Make Spider-Man huge — Change Spider-Man's size property to see him as a giant blob—the visual scales immediately and movement feels different with a bigger collision area
  2. Start Spider-Man higher up — Change the starting y-coordinate in resetGame() to make Spider-Man begin near the top of the screen instead of mid-screen
  3. Make gravity weaker — Reduce the gravity constant so Spider-Man falls more slowly—this makes swinging feel floaty and gives more time to aim shots
  4. Make buildings taller — Increase the minimum building height so all buildings start taller, making the city skyline more dramatic
  5. Change Spider-Man's colors — Modify the RGB values in the color() calls to paint Spider-Man in different colors—try (0, 200, 200) for cyan and (100, 200, 0) for lime green
  6. Slow down the web swings — Increase the damping constant from 0.99 to 0.95 so velocity decays faster—swings will stop within a few frames instead of oscillating for a long time
Prefer the full editor? Open it there →

📖 About This Sketch

This sketch is a playable Spider-Man web-swinging game built with p5.js. The player presses the spacebar to shoot a web, attaches to buildings, and swings through a procedurally generated cityscape that scrolls horizontally. The visual appeal comes from the physics simulation of the pendulum swing, the randomly generated buildings at varying heights, and the challenge of timing web shots to stay alive. The code combines several core p5.js techniques: the animation loop for continuous movement, event handling for keyboard input, collision detection to connect webs to buildings, and vector math to simulate realistic pendulum physics.

The sketch is organized into distinct systems: an environment manager that generates and scrolls buildings, a physics engine that calculates Spider-Man's position and velocity, a game state tracker that monitors score and game-over conditions, and a rendering layer that draws all visuals each frame. By studying this code, you will learn how to build a complete interactive game with multiple game states, how to simulate pendulum physics using force vectors, and how to procedurally generate obstacles that challenge the player.

⚙️ How It Works

  1. When the sketch loads, setup() creates a full-window canvas and calls resetGame() to initialize Spider-Man at position (100, 100), empty the building array, and set score to zero.
  2. Every frame, draw() clears the background with sky blue and updates all game elements: buildings scroll left by subtracting gameSpeed from their x positions, and new buildings are generated when space opens up on the right side of the screen.
  3. Spider-Man is affected by gravity every frame (vy increases by 0.5), pulling him downward toward the bottom of the screen.
  4. When the player presses spacebar, keyPressed() either shoots a web forward (attaching to the nearest building's top or a random sky point) and sets isSwinging to true, or releases the current web if already swinging.
  5. While swinging, the physics engine calculates the distance from Spider-Man to the swing point and applies a tension force that pulls him toward it if he stretches beyond the initial web length, creating a pendulum motion damped by multiplying velocity by 0.99 each frame.
  6. Spider-Man's position updates based on accumulated velocity each frame; if he falls below the screen bottom, gameOver becomes true and the game freezes, displaying the final score.

🎓 Concepts You'll Learn

Game loop and frame updatesPhysics simulation with velocity and accelerationPendulum motion and spring forcesProcedural generation and object poolingCollision detection and spatial queriesGame state managementEvent handling and user interactionVector math and distance calculations

📝 Code Breakdown

setup()

setup() runs once when the sketch starts, before draw() ever runs. Use it to initialize your canvas, set drawing modes, and prepare any data structures. Think of it as 'the loading screen' before the game begins.

function setup() {
  createCanvas(windowWidth, windowHeight);
  rectMode(CORNER); // Buildings drawn from top-left corner
  ellipseMode(CENTER); // Spiderman drawn from center
  buildingMaxHeight = height - 100; // Set here after canvas is created
  resetGame();
}
Line-by-line explanation (5 lines)

🔧 Subcomponents:

initialization Canvas Setup createCanvas(windowWidth, windowHeight);

Creates a full-window canvas that responds to browser size

configuration Drawing Mode Configuration rectMode(CORNER); // Buildings drawn from top-left corner ellipseMode(CENTER); // Spiderman drawn from center

Sets how coordinates are interpreted: rectangles from corner, circles from center point

function-call Game State Reset resetGame();

Initializes Spider-Man, buildings, score, and all game variables

createCanvas(windowWidth, windowHeight);
Creates a canvas that fills the entire browser window—this is p5.js's drawing surface where everything appears
rectMode(CORNER);
Tells p5.js to interpret rectangle coordinates as the top-left corner rather than the center—useful for buildings aligned to the bottom
ellipseMode(CENTER);
Tells p5.js that circle/ellipse coordinates refer to their center point—makes it natural to move Spider-Man around by his center
buildingMaxHeight = height - 100;
Sets the maximum building height based on canvas height, calculated after the canvas exists—this ensures buildings never fill the entire screen
resetGame();
Calls the resetGame function to initialize Spider-Man's position, clear buildings, set score to zero, and prepare for gameplay

draw()

draw() is the heartbeat of your p5.js sketch—it runs 60 times per second (by default) and does three things: (1) update all positions and states, (2) check for collisions and game logic, (3) draw everything. Every interactive game, animation, or interactive visualization you build uses this loop.

🔬 Gravity is always adding to vertical velocity. What if you change spiderman.vy += gravity to spiderman.vy += gravity * 2? How does Spider-Man fall differently?

    // Apply gravity
    spiderman.vy += gravity;

    if (spiderman.isSwinging) {

🔬 This line calculates how hard the web pulls based on how far Spider-Man stretches. What happens if you multiply swingForce by 10 instead (change * swingForce to * swingForce * 10)? The web becomes a catapult!

      // Web tension force (pulls Spiderman towards the swingPoint if he stretches the web)
      if (currentDist > spiderman.webLength) {
        let forceMagnitude = (currentDist - spiderman.webLength) * swingForce;
function draw() {
  background(135, 206, 235); // Sky blue background

  if (!gameOver) {
    // === Update and Draw Buildings ===
    for (let i = buildings.length - 1; i >= 0; i--) {
      let b = buildings[i];
      b.x -= gameSpeed; // Move building left

      fill(100); // Gray buildings
      noStroke();
      rect(b.x, b.y, b.width, b.height);

      // Remove building if it goes off-screen
      if (b.x + b.width < 0) {
        buildings.splice(i, 1);
      }
    }

    // Add new buildings when space opens up
    if (buildings.length === 0 || width - buildings[buildings.length - 1].x > random(100, 300)) {
      addBuilding();
    }

    // === Update Spiderman ===
    // Apply gravity
    spiderman.vy += gravity;

    if (spiderman.isSwinging) {
      // Calculate vector from Spiderman to the swing point
      let dx = spiderman.swingPoint.x - spiderman.x;
      let dy = spiderman.swingPoint.y - spiderman.y;
      let currentDist = sqrt(dx * dx + dy * dy);

      // Web tension force (pulls Spiderman towards the swingPoint if he stretches the web)
      if (currentDist > spiderman.webLength) {
        let forceMagnitude = (currentDist - spiderman.webLength) * swingForce;
        spiderman.vx += (dx / currentDist) * forceMagnitude;
        spiderman.vy += (dy / currentDist) * forceMagnitude;
      }

      // Damping to simulate air resistance and prevent endless swinging
      spiderman.vx *= damping;
      spiderman.vy *= damping;
    }

    // Update Spiderman's position based on velocity
    spiderman.x += spiderman.vx;
    spiderman.y += spiderman.vy;

    // Boundary check: If Spiderman falls off the bottom of the screen, it's game over
    if (spiderman.y - spiderman.size / 2 >= height) {
      gameOver = true;
    }

    // Boundary check: Keep Spiderman within horizontal bounds (or let him scroll with the game)
    if (spiderman.x < spiderman.size / 2) {
      spiderman.x = spiderman.size / 2;
      spiderman.vx = 0;
    }
    // If Spidey goes too far right, scroll the city faster to catch up
    if (spiderman.x > width * 0.75) {
      // This is a simple way to keep Spidey roughly in frame
      spiderman.x = width * 0.75;
      gameSpeed = 5; // Temporarily speed up city scroll
    } else {
      gameSpeed = 3; // Reset to normal scroll speed
    }

    // === Draw Spiderman ===
    // Draw web if swinging
    if (spiderman.isSwinging && spiderman.swingPoint) {
      stroke(200); // White web
      strokeWeight(2);
      line(spiderman.x, spiderman.y, spiderman.swingPoint.x, spiderman.swingPoint.y);
    }

    // Draw Spiderman body (red)
    fill(spiderman.color);
    noStroke();
    ellipse(spiderman.x, spiderman.y, spiderman.size, spiderman.size);
    // Draw Spiderman "suit" details (blue)
    fill(spiderman.suitColor);
    ellipse(spiderman.x, spiderman.y, spiderman.size * 0.7, spiderman.size * 0.7);
    fill(0);
    textSize(12);
    textAlign(CENTER, CENTER);
    text("Spidey", spiderman.x, spiderman.y + spiderman.size / 2 + 10); // Label

    // === Score ===
    // Score increases with horizontal distance traveled
    score++;
    fill(0);
    textSize(24);
    textAlign(LEFT, TOP);
    text("Score: " + score, 10, 10);

  } else {
    // === Game Over Screen ===
    fill(0);
    textSize(48);
    textAlign(CENTER, CENTER);
    text("GAME OVER!", width / 2, height / 2 - 50);
    textSize(24);
    text("You swung " + score + " units through the city!", width / 2, height / 2);
    text("Press SPACE to Restart", width / 2, height / 2 + 50);
  }
}
Line-by-line explanation (24 lines)

🔧 Subcomponents:

for-loop Building Update Loop for (let i = buildings.length - 1; i >= 0; i--) {

Iterates backwards through the buildings array to safely remove off-screen buildings while updating and drawing the rest

conditional Off-Screen Building Removal if (b.x + b.width < 0) {

Checks if a building has scrolled completely off the left side of the canvas and removes it from the array

conditional Procedural Building Generation if (buildings.length === 0 || width - buildings[buildings.length - 1].x > random(100, 300)) {

Generates new buildings when the screen is empty or enough space has opened up, creating the endless scrolling effect

calculation Gravity Force spiderman.vy += gravity;

Increases vertical velocity every frame to simulate downward acceleration

conditional Swing Physics Engine if (spiderman.isSwinging) {

Calculates and applies pendulum-like forces when Spider-Man is attached to a web, pulling him toward the swing point

conditional Web Tension Force Calculation if (currentDist > spiderman.webLength) {

Only applies tension force if Spider-Man stretches beyond the initial web length, like a real pendulum reaching its limit

calculation Position Update from Velocity spiderman.x += spiderman.vx;

Moves Spider-Man based on accumulated velocity—this is how animation happens in the draw loop

conditional Fall Off Screen Detection if (spiderman.y - spiderman.size / 2 >= height) {

Triggers game over if Spider-Man falls below the bottom of the canvas

conditional Left Boundary Constraint if (spiderman.x < spiderman.size / 2) {

Stops Spider-Man from moving past the left edge and halts his horizontal velocity

conditional Right Boundary and Camera Follow if (spiderman.x > width * 0.75) {

Keeps Spider-Man roughly centered on screen by capping his rightward position and speeding up city scroll

conditional Web Line Rendering if (spiderman.isSwinging && spiderman.swingPoint) {

Draws a visible white line from Spider-Man to the swing point when active

calculation Spider-Man Rendering ellipse(spiderman.x, spiderman.y, spiderman.size, spiderman.size);

Draws Spider-Man as concentric circles (outer red body, inner blue suit) with a label

calculation Score Accumulation score++;

Increases score by 1 every frame, rewarding the player for survival time

background(135, 206, 235); // Sky blue background
Fills the entire canvas with light blue every frame, erasing the previous frame and creating a clean slate for new drawings
for (let i = buildings.length - 1; i >= 0; i--) {
Loops through the buildings array backwards (from last to first) so we can safely remove items during iteration without skipping any
b.x -= gameSpeed; // Move building left
Subtracts gameSpeed from each building's x position, making it scroll leftward and creating the illusion that the city moves while Spider-Man stays still
rect(b.x, b.y, b.width, b.height);
Draws the building as a gray rectangle at its current position—the x changes every frame so the rectangle animates across the screen
if (b.x + b.width < 0) {
Checks if the building's right edge has passed the left side of the canvas (completely off-screen)
buildings.splice(i, 1);
Removes the off-screen building from the array so we don't waste memory storing buildings no one can see
if (buildings.length === 0 || width - buildings[buildings.length - 1].x > random(100, 300)) {
Generates a new building either when no buildings exist OR when there's enough gap between the last building and the right edge—random spacing makes the game less predictable
spiderman.vy += gravity;
Increases downward velocity each frame to simulate gravity—Spider-Man will always be pulled toward the bottom unless the web holds him up
let dx = spiderman.swingPoint.x - spiderman.x;
Calculates the horizontal distance from Spider-Man to where the web is attached—positive means the swing point is to the right
let currentDist = sqrt(dx * dx + dy * dy);
Uses the Pythagorean theorem to find the straight-line distance between Spider-Man and the swing point
if (currentDist > spiderman.webLength) {
Only applies tension force if Spider-Man has stretched beyond the web's resting length—like a rubber band that only pulls back when extended
let forceMagnitude = (currentDist - spiderman.webLength) * swingForce;
Calculates how strong the restoring force should be: the farther Spider-Man stretches, the harder the web pulls him back
spiderman.vx += (dx / currentDist) * forceMagnitude;
Converts the force magnitude into a horizontal component and adds it to Spider-Man's horizontal velocity—the web pulls him toward the swing point
spiderman.vx *= damping;
Multiplies velocity by 0.99 to reduce it slightly each frame, simulating air resistance so the swing gradually dies out instead of oscillating forever
spiderman.x += spiderman.vx;
Adds accumulated horizontal velocity to Spider-Man's x position, moving him by the amount stored in vx
spiderman.y += spiderman.vy;
Adds accumulated vertical velocity to Spider-Man's y position—combined with gravity, this makes him fall or swing
if (spiderman.y - spiderman.size / 2 >= height) {
Checks if Spider-Man's bottom edge has hit or passed the bottom of the canvas—game ends on death
if (spiderman.x < spiderman.size / 2) {
Checks if Spider-Man's left edge has gone past the left boundary—clamps him to the edge and stops leftward motion
if (spiderman.x > width * 0.75) {
If Spider-Man reaches 75% across the screen, lock him there and speed up city scroll to catch up—keeps him roughly centered
line(spiderman.x, spiderman.y, spiderman.swingPoint.x, spiderman.swingPoint.y);
Draws a white line from Spider-Man to the swing point, making the web visible to the player
ellipse(spiderman.x, spiderman.y, spiderman.size, spiderman.size);
Draws Spider-Man's outer red circle body at his current position
ellipse(spiderman.x, spiderman.y, spiderman.size * 0.7, spiderman.size * 0.7);
Draws a smaller blue circle inside Spider-Man to represent the suit, creating a layered appearance
score++;
Adds 1 to the score every frame—at 60 frames per second, this rewards roughly 60 points per second of survival
text("Score: " + score, 10, 10);
Displays the current score in the top-left corner of the screen

addBuilding()

This function implements procedural generation—creating game objects on-demand instead of storing them all in memory. By spawning buildings only when needed and deleting them when they leave the screen, the game stays fast even if you play for hours.

🔬 The new building starts at x: width + random(50, 150), so it appears off-screen to the right. What happens if you change it to x: width + 500? Buildings appear much farther away before entering the screen.

  buildings.push({
    x: width + random(50, 150), // Start off-screen to the right
    y: height - bHeight,
    width: buildingWidth,
    height: bHeight
  });
function addBuilding() {
  let bHeight = random(buildingMinHeight, buildingMaxHeight);
  buildings.push({
    x: width + random(50, 150), // Start off-screen to the right
    y: height - bHeight,
    width: buildingWidth,
    height: bHeight
  });
}
Line-by-line explanation (6 lines)

🔧 Subcomponents:

calculation Random Building Height let bHeight = random(buildingMinHeight, buildingMaxHeight);

Generates a random height between min and max to make buildings look varied

calculation Building Object Construction buildings.push({

Creates a new building object with position, size, and adds it to the buildings array

let bHeight = random(buildingMinHeight, buildingMaxHeight);
Generates a random number between buildingMinHeight (150) and buildingMaxHeight (window height - 100), creating variety in the skyline
buildings.push({
Creates a new building object and adds it to the end of the buildings array
x: width + random(50, 150), // Start off-screen to the right
Places the building just beyond the right edge of the canvas (at width plus 50-150 pixels) so it scrolls into view
y: height - bHeight,
Positions the top of the building so it sits on the ground (height minus its own height places its top at the right spot)
width: buildingWidth,
Sets building width to the constant 80 pixels—all buildings have the same width for consistency
height: bHeight
Assigns the randomized height calculated earlier to the new building

keyPressed()

keyPressed() is called by p5.js automatically whenever a key is pressed. Use it to capture user input and trigger actions. This function demonstrates collision detection (checking if a ray hits a building), spatial searching (finding the nearest building), and state management (toggling between swinging and free-falling).

🔬 These lines control where you can shoot the web. What if you change targetY to random(0, height) so the web can attach anywhere vertically, even below the ground?

      let targetX = random(spiderman.x + 50, spiderman.x + 200); // Shoot forward
      let targetY = random(0, height / 3); // High up
function keyPressed() {
  if (key === ' ' && !gameOver) { // Spacebar to shoot/release web
    if (spiderman.isSwinging) {
      // Release web
      spiderman.isSwinging = false;
      spiderman.swingPoint = null;
      spiderman.webLength = 0;
    } else {
      // Shoot web (attach to a random point high up)
      // We'll try to attach to a building if one is suitable, otherwise just the sky
      let targetX = random(spiderman.x + 50, spiderman.x + 200); // Shoot forward
      let targetY = random(0, height / 3); // High up

      let bestBuilding = null;
      let minDistanceToBuilding = Infinity;

      // Find the nearest building within shooting range
      for (let b of buildings) {
        if (b.x < targetX && b.x + b.width > targetX) { // Target X is within building's horizontal range
          if (targetY < b.y) { // Target Y is above the building
            let distToTop = abs(targetY - b.y);
            if (distToTop < minDistanceToBuilding) {
              minDistanceToBuilding = distToTop;
              bestBuilding = b;
            }
          }
        }
      }

      if (bestBuilding) {
        // Attach to the top of the building
        spiderman.swingPoint = {
          x: targetX,
          y: bestBuilding.y
        };
      } else {
        // If no suitable building, attach to a random point high in the sky
        spiderman.swingPoint = {
          x: targetX,
          y: random(0, height / 3)
        };
      }

      // Calculate the initial web length
      spiderman.webLength = dist(spiderman.x, spiderman.y, spiderman.swingPoint.x, spiderman.swingPoint.y);
      spiderman.isSwinging = true;

      // Add a slight initial tangential push to help start the swing
      // (This is optional but makes it feel better)
      let angleToSwingPoint = atan2(spiderman.swingPoint.y - spiderman.y, spiderman.swingPoint.x - spiderman.x);
      spiderman.vx += cos(angleToSwingPoint + HALF_PI) * 3;
      spiderman.vy += sin(angleToSwingPoint + HALF_PI) * 3;
    }
  } else if (gameOver && key === ' ') {
    resetGame(); // Restart the game
  }
}
Line-by-line explanation (21 lines)

🔧 Subcomponents:

conditional Spacebar Input Detection if (key === ' ' && !gameOver) {

Checks if the spacebar was pressed while the game is still active

conditional Web Release Logic if (spiderman.isSwinging) {

If already swinging, releases the web and stops the swing

conditional Web Shoot Logic } else {

If not swinging, calculates where to attach the web and starts a new swing

conditional Building Hit Detection if (b.x < targetX && b.x + b.width > targetX) {

Checks if the target x-coordinate is within the building's horizontal range

conditional Above Building Check if (targetY < b.y) {

Verifies the target point is above the building's top (so the web can attach to the roof)

conditional Game Over Restart } else if (gameOver && key === ' ') {

If the game is over and spacebar is pressed, restart the game

if (key === ' ' && !gameOver) { // Spacebar to shoot/release web
Checks if the spacebar was pressed AND the game is not over—prevents restarting from this branch
if (spiderman.isSwinging) {
If Spider-Man is already attached to a web, this branch handles releasing it
spiderman.isSwinging = false;
Sets isSwinging to false, ending the physics calculations for the swing
spiderman.swingPoint = null;
Clears the swing point so the web line no longer has a target to draw to
let targetX = random(spiderman.x + 50, spiderman.x + 200); // Shoot forward
Picks a random x-coordinate ahead of Spider-Man (50-200 pixels forward) where the web will aim
let targetY = random(0, height / 3); // High up
Picks a random y-coordinate high up in the upper third of the screen where the web will aim
for (let b of buildings) {
Loops through every building to check if any of them lie at the target coordinates
if (b.x < targetX && b.x + b.width > targetX) { // Target X is within building's horizontal range
Checks if the target x-coordinate falls within the building's left and right edges
if (targetY < b.y) { // Target Y is above the building
Checks if the target y-coordinate is above the building's top edge (on the roof)
let distToTop = abs(targetY - b.y);
Calculates the vertical distance between the target and the building's top edge
if (distToTop < minDistanceToBuilding) {
If this building is closer to the target than any previous building, store it as the best match
if (bestBuilding) {
If a suitable building was found during the search, attach the web to its roof
spiderman.swingPoint = { x: targetX, y: bestBuilding.y };
Sets the swing point to the target x-coordinate at the top of the best building
} else { // If no suitable building, attach to a random point high in the sky spiderman.swingPoint = { x: targetX, y: random(0, height / 3) }; }
If no building was found, creates a swing point floating in the empty sky instead
spiderman.webLength = dist(spiderman.x, spiderman.y, spiderman.swingPoint.x, spiderman.swingPoint.y);
Calculates the initial straight-line distance from Spider-Man to the swing point—this becomes the web's resting length
spiderman.isSwinging = true;
Sets isSwinging to true, enabling the swing physics in the next draw() call
let angleToSwingPoint = atan2(spiderman.swingPoint.y - spiderman.y, spiderman.swingPoint.x - spiderman.x);
Calculates the angle from Spider-Man toward the swing point using arctangent
spiderman.vx += cos(angleToSwingPoint + HALF_PI) * 3;
Adds a tangential velocity component perpendicular to the web direction, giving Spider-Man an initial push to start swinging
spiderman.vy += sin(angleToSwingPoint + HALF_PI) * 3;
Adds the vertical component of the tangential push
} else if (gameOver && key === ' ') {
If the game is over and spacebar is pressed, restart the game
resetGame(); // Restart the game
Calls resetGame() to reset all variables and begin a new game

resetGame()

resetGame() is a key game design pattern: whenever you need to 'reset' or 'restart,' create a function that reinitializes all your data structures. This keeps your code DRY (Don't Repeat Yourself) and makes it trivial to add features like 'restart button' or 'new level'—just call resetGame() again.

function resetGame() {
  gameOver = false;
  score = 0;
  buildings = [];
  spiderman = {
    x: 100,
    y: 100,
    size: 40,
    vx: 0,
    vy: 0,
    isSwinging: false,
    swingPoint: null,
    webLength: 0,
    color: color(200, 0, 0), // Now called within p5.js context
    suitColor: color(0, 0, 200) // Now called within p5.js context
  };
  // Add some initial buildings
  addBuilding();
  addBuilding();
  addBuilding();
}
Line-by-line explanation (15 lines)

🔧 Subcomponents:

calculation Game State Reset gameOver = false; score = 0; buildings = [];

Clears all game variables to their starting state

calculation Spider-Man State Initialization spiderman = {

Creates a fresh Spider-Man object with starting position, size, and color

function-call Initial Building Generation addBuilding();

Generates three starting buildings so the player has something to interact with immediately

gameOver = false;
Sets the game-over flag to false, resuming the active game branch in draw()
score = 0;
Resets the score counter to zero for a fresh start
buildings = [];
Clears the buildings array completely, removing all old buildings from memory
spiderman = {
Overwrites the global spiderman object with a completely new one, resetting all properties
x: 100,
Sets Spider-Man's starting x-position 100 pixels from the left edge
y: 100,
Sets Spider-Man's starting y-position 100 pixels from the top edge
size: 40,
Sets Spider-Man's diameter to 40 pixels (a 40x40 circle)
vx: 0,
Resets horizontal velocity to zero so Spider-Man starts stationary
vy: 0,
Resets vertical velocity to zero so Spider-Man doesn't start with downward momentum
isSwinging: false,
Sets isSwinging to false so Spider-Man starts free-falling, ready for the first web shot
swingPoint: null,
Clears the swing point since Spider-Man isn't swinging yet
webLength: 0,
Resets web length to zero (will be calculated when a web is shot)
color: color(200, 0, 0), // Now called within p5.js context
Creates a red color for Spider-Man's body—RGB (200, 0, 0) is a bright red
suitColor: color(0, 0, 200) // Now called within p5.js context
Creates a blue color for Spider-Man's suit—RGB (0, 0, 200) is a bright blue
addBuilding();
Adds the first random building to start the game with buildings already on screen

windowResized()

windowResized() is a special p5.js function that fires automatically when the browser window is resized. Use it to keep your sketch responsive—recalculate positions, redraw textures, or reinitialize data based on the new dimensions. This sketch demonstrates good responsive design: it adapts gracefully to any window size.

function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
  buildingMaxHeight = height - 100; // Update for new window size
  // Re-initialize buildings for the new window size
  buildings = [];
  addBuilding();
  addBuilding();
  addBuilding();
}
Line-by-line explanation (4 lines)

🔧 Subcomponents:

function-call Canvas Resize resizeCanvas(windowWidth, windowHeight);

Updates the p5.js canvas to match the new window dimensions

calculation Building Height Constraint Update buildingMaxHeight = height - 100;

Recalculates the maximum building height based on the new canvas height

function-call Building Reinitialization buildings = [];

Clears old buildings and generates new ones for the resized window

resizeCanvas(windowWidth, windowHeight);
p5.js automatically calls windowResized() whenever the browser window is resized—this line updates the canvas to match the new size
buildingMaxHeight = height - 100;
Recalculates the maximum building height based on the new canvas height so buildings scale appropriately
buildings = [];
Clears all existing buildings since they were positioned for the old window size
addBuilding();
Generates three new buildings positioned for the new window size

📦 Key Variables

buildings array

Stores all active building objects {x, y, width, height} on screen; buildings are added when needed and removed when they scroll off-screen

let buildings = [];
buildingWidth number

Fixed width of all buildings in pixels—kept constant for visual consistency

const buildingWidth = 80;
buildingMinHeight number

Minimum possible height for generated buildings—ensures buildings are tall enough to be visible

const buildingMinHeight = 150;
buildingMaxHeight number

Maximum possible height for generated buildings, calculated based on canvas height minus padding—prevents buildings from covering the sky

let buildingMaxHeight;
gameSpeed number

How fast buildings scroll left each frame (pixels per frame)—increases when Spider-Man reaches the right side of screen

let gameSpeed = 3;
score number

Current game score, incremented by 1 every frame to reward survival time

let score = 0;
gameOver boolean

Tracks whether the game is active (false) or ended (true)—controls which branch of draw() runs

let gameOver = false;
spiderman object

Main player object containing position (x, y), size, velocity (vx, vy), swing state, and visual properties (color, suitColor)

let spiderman = { x: 100, y: 100, size: 40, vx: 0, vy: 0, isSwinging: false, swingPoint: null, webLength: 0, color: 0, suitColor: 0 };
gravity number

Downward acceleration applied to spiderman.vy every frame—simulates gravitational pull

const gravity = 0.5;
swingForce number

Magnitude multiplier for web tension force—controls how strongly the web pulls Spider-Man toward the swing point

const swingForce = 0.05;
damping number

Multiplier applied to velocity each frame (0.99 = 99% retention)—simulates air resistance and causes swings to decay

const damping = 0.99;

🔧 Potential Improvements (5)

Here are some ways this code could be enhanced:

BUG draw() - swing physics

If Spider-Man is swinging and the web stretches extremely far, the force calculation can create unrealistic acceleration spikes

💡 Clamp the web tension force to a maximum value: let forceMagnitude = min((currentDist - spiderman.webLength) * swingForce, 5); prevents over-acceleration

PERFORMANCE keyPressed() - building search

The loop searches all buildings every time spacebar is pressed—with hundreds of buildings, this becomes slow

💡 Only search buildings near the target x-coordinate by filtering: for (let b of buildings.filter(b => abs(b.x - targetX) < 200)) { ... } to limit the search scope

STYLE spiderman object

The spiderman object mixes physics properties (vx, vy) with rendering properties (color, suitColor) and state (isSwinging, webLength)—makes it harder to understand and modify

💡 Consider separating concerns into spiderman, physics, and visual objects, or add comments documenting each property's purpose

FEATURE score system

Score increments every frame regardless of game state—a player could rack up huge scores by pausing their browser

💡 Only increment score when actively swinging (if (spiderman.isSwinging) score++;) or add a time-based multiplier to reward risky close calls

BUG draw() - boundary check

When Spider-Man hits the left boundary, his velocity is set to 0 but buildings keep scrolling, potentially trapping him at the edge if he tries to swing away

💡 Instead of zeroing velocity, use spiderman.vx = max(spiderman.vx, 0) to allow only rightward movement from the left edge

🔄 Code Flow

Code flow showing setup, draw, addbuilding, keypressed, resetgame, windowresized

💡 Click on function names in the diagram to jump to their code

graph TD start[Start] --> setup[setup] setup --> canvas-creation[Canvas Setup] setup --> drawing-modes[Drawing Mode Configuration] setup --> game-initialization[Game State Reset] setup --> initial-buildings[Initial Building Generation] setup --> draw[draw loop] click setup href "#fn-setup" click canvas-creation href "#sub-canvas-creation" click drawing-modes href "#sub-drawing-modes" click game-initialization href "#sub-game-initialization" click initial-buildings href "#sub-initial-buildings" draw --> gravity-application[Gravity Force] draw --> swing-physics[Swing Physics Engine] draw --> web-tension[Web Tension Force Calculation] draw --> position-update[Position Update from Velocity] draw --> death-check[Fall Off Screen Detection] draw --> left-boundary[Left Boundary Constraint] draw --> right-boundary[Right Boundary and Camera Follow] draw --> web-drawing[Web Line Rendering] draw --> spiderman-drawing[Spider-Man Rendering] draw --> score-increment[Score Accumulation] draw --> building-loop[Building Update Loop] click draw href "#fn-draw" click gravity-application href "#sub-gravity-application" click swing-physics href "#sub-swing-physics" click web-tension href "#sub-web-tension" click position-update href "#sub-position-update" click death-check href "#sub-death-check" click left-boundary href "#sub-left-boundary" click right-boundary href "#sub-right-boundary" click web-drawing href "#sub-web-drawing" click spiderman-drawing href "#sub-spiderman-drawing" click score-increment href "#sub-score-increment" click building-loop href "#sub-building-loop" building-loop --> building-removal[Off-Screen Building Removal] building-loop --> building-generation[Procedural Building Generation] click building-removal href "#sub-building-removal" click building-generation href "#sub-building-generation" keypressed[keyPressed] --> spacebar-check[Spacebar Input Detection] keypressed --> web-release[Web Release Logic] keypressed --> web-shoot[Web Shoot Logic] keypressed --> building-search[Nearest Building Search] click keypressed href "#fn-keypressed" click spacebar-check href "#sub-spacebar-check" click web-release href "#sub-web-release" click web-shoot href "#sub-web-shoot" click building-search href "#sub-building-search" building-search --> building-collision[Building Hit Detection] building-search --> building-above[Above Building Check] click building-collision href "#sub-building-collision" click building-above href "#sub-building-above" resetgame[resetGame] --> state-reset[Game State Reset] resetgame --> spiderman-reset[Spider-Man State Initialization] click resetgame href "#fn-resetgame" click state-reset href "#sub-state-reset" click spiderman-reset href "#sub-spiderman-reset" windowresized[windowResized] --> canvas-resize[Canvas Resize] windowresized --> constraint-update[Building Height Constraint Update] windowresized --> building-reinit[Building Reinitialization] click windowresized href "#fn-windowresized" click canvas-resize href "#sub-canvas-resize" click constraint-update href "#sub-constraint-update" click building-reinit href "#sub-building-reinit"

❓ Frequently Asked Questions

What visual experience does the 'Spider Man' sketch create?

The 'Spider Man' sketch features a dynamic cityscape where buildings scroll horizontally across a sky blue background, simulating a vibrant urban environment.

How can users interact with the 'Spider Man' sketch?

Users can control Spider-Man's swinging mechanics and navigate through the city by clicking or tapping to attach his web to swing points.

What creative coding techniques are demonstrated in the 'Spider Man' sketch?

This sketch showcases concepts like object-oriented programming for character representation, physics simulation for gravity and swinging motion, and dynamic scene generation with scrolling buildings.

Preview

the spider man - p5.js creative coding sketch preview
Sketch Preview
Code flow diagram showing the structure of the spider man - Code flow showing setup, draw, addbuilding, keypressed, resetgame, windowresized
Code Flow Diagram