itch.io is community of indie game creators and players

Devlogs

Week 11 - Squirrel Eat Squirrel World

MY FINAL SQUIRREL EAT SQUIRREL

It’s a Squirrel-eat-Squirrel world out there and I’ve got to program it.

Squirrel Eat Squirrel is loosely based on the game Katamari Damacy. The player controls a small squirrel that must hop around the screen eating smaller squirrels and avoiding larger squirrels. Each time the player’s squirrel eats a squirrel that is smaller than it, it grows larger. If the player’s squirrel gets hit by a larger squirrel larger than it, it loses a life point. The player wins when the squirrel becomes a monstrously large squirrel called the Omega Squirrel. The player loses if their squirrel gets hit three times.

For this assignment, we need to meet the following basic requirements:

  • The game must work in fullscreen mode
  • The squirrel is controlled by the arrow keys
  • Each squirrel is procedurally generated
  • Both the Player and the Squirrel must have their own class
  • When two squirrels collide, true beauty happens. Just kidding. The larger one eats the smaller one and grows bigger
  • If the player collides with a larger squirrel, their squirrel loses a life (out of 3)
  • If the player loses all 3 of their lives, game over

There are also optional Advanced features we can implement into our game. I’ll list out the ones that I will attempt to incorporate into my work:

  • Procedurally generated grass
  • Procedurally generated flowers
  • Eating sound
  • Background music
class Player {
  constructor(x,y){
    this.x = x;
    this.y = y; 
    this.size = 20;
    this.speed = 4;
  }
  
  update(){
    let move = createVector(0,0);
   
    if (keyIsPressed) {
    if (keyCode === UP_ARROW) {
      move.y -= 1;
    }
    if (keyCode === LEFT_ARROW) {
      move.x -= 1;
    }
    if (keyCode === DOWN_ARROW) {
      move.y += 1;
    }
    if (keyCode === RIGHT_ARROW) {
      move.x += 1;
    }
  }
    
    
    move.setMag(this.speed);
    this.x += move.x;
    this.y += move.y;
  

  this.x = constrain(this.x, 0, width);
  this.y = constrain(this.y, 0, height);
  }
  
  display(){
    image(p1img, this.x, this.y, this.size, this.size);
  }
}

I’m having difficulty with diagonal movement–not sure how to the fix current issue of the player’s acceleration not stopping after two simultaneous key strokes. Going to leave it relatively rigid for now.

As for the canvas, I selected a green hex code similar to our screenshot of Sweigart’s game.

Before we get to coding the NPC enemy squirrels, I’d like to work on the procedural grass and flower generation. I’ll begin by creating a new ‘startGame()’ function:

function startGame(){
  player = new Player(width / 2, height / 2);
  grassSpawn = [];
  
  for (let i = 0; i < 50; i++) {
    grassSpawn.push({
      x: random(width),
      y: random(height),
      size: random(40, 80)
    });
  }
}

function draw() {
  background("#49ed3f");

  for (let spawn of grassSpawn) {
    image(grass, spawn.x, spawn.y, spawn.size, spawn.size);
  }
  
  player.update();
  player.display();
}

I’ve included my draw() in this excerpt as well to show how I am generating the grass procedurally in this sketch. Basically, I just have to repeat this process for our flowers and we should have our environment completed! The editing of this portion of my devlog is a little peculiar. The end result is actually going to be the image just below the title of this step!

function healthBar(x, y, w, h, maxBar, nowBar) {
  stroke(255);
  strokeWeight(2);

  for (let i = 0; i < maxBar; i++) {
    fill(i < nowBar ? color(255,0,0) : color(0));
    rect(x, y + i*(h + 4), w, h);
  }
}

‘maxBar’ is set to 3 and ‘nowBar’ is a variable dependent on the player’s current health. If the player collides with a larger enemy squirrel, that collision will result in one of the health bars being set to black.

STEP FIVE - Enemy Squirrels, Collision, and Splash Screens

I’ve made a new Bots class to house our procedurally generating enemies. I want them to range in size from ~25 to 60pixels, seeing as our player squirrel is 30 at the start of our game. I may up the largest size to 75 if the game needs to become more challenging. On top of all this, I am going to need to make our health bar responsive to any collisions with larger squirrels, and our squirrel grow when it collides with one that is smaller. I’d also like to add in the Minecraft eating sound effect I worked on here. Let’s get started!

class Bots {
  constructor(x, y, size){
    this.x = x;
    this.y = y;
    this.size = size;
    this.speed = random(0.5, 1);
    this.angle = random(TWO_PI)
  }
  
  update() {
    this.angle += random(-0.05, 0.05);
    this.x += cos(this.angle) * this.speed;
    this.y += sin(this.angle) * this.speed;
    
    if (this.x < 0) this.x = width;
    else if (this.x > width) this.x = 0;
    if (this.y < 0) this.y = height;
    else if (this.y > height) this.y = 0;
  }
  
  display() {
    push();
      translate(this.x, this.y);
      let f = (cos(this.angle) > 0) ? -1 : 1;
      scale(f, 1);
      image(npcimg, 0, 0, this.size, this.size);
    pop();
  }
}

COLLISION

spawnTimer++;
  if (spawnTimer >= spawnInt) {
    bots.push(new Bots(random(width), random(height), random(25, 90)));
    spawnTimer = 0;
    spawnInterval = max(30, spawnInt - 0.5);
  }

  if (player.invincible && millis() - player.invStart > GRACE_PERIOD) {
      player.invincible = false;
    }  
  
  for (let i = bots.length - 1; i >= 0; i--) {
    let b = bots[i];
    b.update();
    b.display();

    if (!player.invincible) {
    let d = dist(player.x, player.y, b.x, b.y);
    if (d < (player.size/2 + b.size/2)) {
      if (player.size < b.size) {
        health--;
        player.invincible = true;
        player.invStart = millis();
      } else {
        player.size *= 1.125;
        bots.splice(i, 1);
      }
    }
  }
}

In my draw() function, I’ve written collision detection for our player squirrel with any enemy players. I found that I died immediately after spawning a few times so I added in a grace period of 3 seconds for our squirrel friend whenever it spawns/takes damage. With this collision, whenever the distance between a player and enemy is less than the sum of half of both the player character and npc image sizes, they will collide. If that collision is triggered when the player is smaller than the enemy squirrel, then the player loses a life. If it’s triggered when they’re bigger, they grow slightly bigger. I suppose the only way to make this more sophisticated would be to make the player grow in proportion to the size of the enemy squirrel they consume, but I’m lazy.

MY SPLASH SCREEN and SFX code are pretty uninteresting to discuss–not too much new information to glean there. All you need to know is that when our player squirrel consumes a smaller squirrel, the eating sound will play, and when it is hurt, an “oof” sound will play. Each loop of the game also triggers a jazz song to play. I do not want to trigger damage audio per squirrel collision because I think that would be an auditory nightmare.

STEP SIX - Final Edit I forgot to give the enemy squirrels collision with one another + their respective growth if they do collide. My idea of tackling this would be to essentially emulate the rules for our player character, however, write it so that once an enemy squirrel reaches a size of 100, they burst into two squirrels equally sized at 50 each. Here’s what that fix looks like:

   for (let i = bots.length - 1; i >= 0; i--) {
      for (let j = bots.length - 1; j >= 0; j--) {
        if (i !== j && bots[i].collidesWith(bots[j])) {
          if (bots[i].size > bots[j].size) {
            bots[i].grow();
            bots.splice(j, 1);
            bots.push(new Bots(random(width), random(height), random(10, 60)));
          }
          break;
      }
    }
  }

IN ADDITION TO

collidesWith(other) {
  let d = dist(this.x, this.y, other.x, other.y);
  return d < (this.size/2 + other.size/2);
}

grow() {
  this.size *= 1.125;
  if (this.size >= 100) {
    this.size = 50;
    bots.push(new Bots(this.x + random(-20, 20), this.y + random(-20, 20), 50));
  }
}

This tackled my idea. Woohoo!

As a finishing touch, I wanted to add ‘yay’ and ‘boo’ sounds to the win and game over splash screens. That’s all for now!

Download Drawing, Moving and Seeing with Code - Spring 2025
Leave a comment