Week 5 - Smart Robot ALFIE


The best way to describe this week’s assignment for DMSWC is the following: Create a robot named Alfie (roomba equivalent) that picks up objects on one half of the canvas and deposits them on the other, all whilst avoiding central obstacles. I’ve started this devlog after two in-class attempts to tackle this assignment–I’ll explain how those went below.

STEP 1 - ADOPT & OVERCOME Definitely not the correct saying but I DON’T CARE!!! John and I took the class code example for the Alfie bot and began modifying it to fit the parameters of the assignment. It certainly gave us a great foundation, though there were a few things amiss about what we were working with:

  1. There was no collision with central obstacles. They also were poorly generated and not round
  2. Alfie picks up multiple payloads at once and deposits them over one another
  3. It could certainly look better This is what that first attempt was looking like.

STEP 2 - NOT MUCH HAS CHANGED Our second build was not much better at all since we were running down the clock in class and did not have much time for further fixes apart from our obstacles, BUT it was getting us closer to appropriately tackling the challenges. Here’s what that looked like: Hardly a change at all both visually and code-wise, however, it is the only other screenshot I have left from that class and I’d be remiss not to include it. As you can see, we are centering our (unfortunately rectangular) obstacles, however, they are lacking much randomness as we simply just locked them to be generated at x: 200.

STEP 3 - NEW LOOK In this part of the project, I diverged a bit from John and started to replace all the items drawn in the sketch with images. I really wanted Alfie to be a Roomba, and I figured that a natural habitat for one would be a big carpet. Subsequently, I started Googling stuff like “carpeted floor top view” and ultimately came across the retro arcade carpet so I decided to theme my payloads and obstacles after that. The payloads became little bits of popcorn and our obstacles coke cans. Additionally, I wanted to fix the random generation of our obstacles in the center of the canvas so I made the following change to the obstacle class John and I worked on:

class Obstacle {
  constructor(){
    this.position = createVector(random(width/3, 2*width/3), random(height));
    this.angle = random(TWO_PI); 
  }  

  display(){
    push();
    translate(this.position.x, this.position.y); 
    rotate(this.angle); 
    imageMode(CENTER); 
    image(coke, 0, 0);
    pop();
  }
}

Firstly, I’d like to explain the change made to this.position. The x value has been changed to random(width/3, 2width/3) to ensure that the cans are placed in the middle third of the canvas. “width/3” is the first third of our canvas, and “2width/3” is the last third, so fixing the x-value to

random(start, end)
random(width/3, 2*width/3)

will guarantee that the cans are only drawn in the center. Another simpler solution to this would have been to make x “random(200, 400)” but I like the implication that I can always make the canvas bigger and keep the obstacles centered. Regarding the y-value, it is kept as random(height) so no changes were made there.

this.angle = random(TWO_PI);

AND

display(){
    push();
    translate(this.position.x, this.position.y); 
    rotate(this.angle); 
    imageMode(CENTER); 
    image(coke, 0, 0);
    pop();
  }

These are the two other changes I made to the obstacle generation to rotate the cans so that they appear to have been dropped all over the floor. Setting this.angle to random(TWO_PI) means that we will be rotating our cans randomly somewhere between 0 and 360 degrees. In display, we have to push and pop said rotation so that we are only affecting the cans.

STEP 4 - ONE AT A TIME The next challenge John and I tackled was getting Alfie to pick up only one payload at a time. Prior to the changes we made, the bot would pick up several payloads and once and deposit them in the same position so they were drawn on top of one another. To remedy this, we declared a new variable, “this.carrying” in the Ball class and set it to null because we intend on repeatedly picking up boxes. Next, we added the following if statement to our Box class:

if (!this.pickedUp && robot.carrying === null && this.position.dist(robot.position) < 65) {
  this.pickedUp = true;
  robot.carrying = this;
}

This checks to see if a payload is already being picked up or carried, and if it is within the threshold of 65 pixels to the center of our Alfie Roomba. If all of those conditions are met, then Alfie picks up the payload.

STEP 5 - COLLISION There was much troubleshooting that went into creating collision between the cans and the roomba. Ultimately, the solution was as follows:

  checkCollision(obstacle) {
  let d = dist(this.position.x, this.position.y, obstacle.position.x, obstacle.position.y);
  if (d < (this.size/2 + obstacle.size/2)) {
    print("Collision!"); 
    this.velocity.x *= -1;
    this.velocity.y *= -1;
  }
}

‘d’ finds the distance between Alfie and the coke cans’ positions. The if statement says that if the distance between Alfie and the coke cans is less than the sum of their radii, then Alfie will bounce off of the coke can and travel in the opposite direction. While this image looks identical to the last build, I can assure you that collision is in fact working in this build. Here’s a link to it: https://editor.p5js.org/flemin/sketches/eE0pRCgF-

Get Drawing, Moving and Seeing with Code - Spring 2025