itch.io is community of indie game creators and players

Devlogs

DMSC Devlog: Week 5 - Special Delivery!

This week’s assignment, originally from March, set me up with bug-fixing puzzles I’m still wrangling with now. The premise: program a robot (affectionately termed “Alfie”) that delivers boxes across the screen and bounces off obstacles. It’s an assignment about collision, and on paper the core of the puzzle is distinguishing “box” from “obstacle”.

Step 1 is to represent Alfie’s movement as a vector. Up to now, we had used individual X and Y variables to represent an object’s position and rates of change, as with Week 2’s iceberg. Switching to vectors allows us to not only store each X and Y coordinate pair as its own p5.Vector object, but also leverage the library’s built-in vector functions, making programming changes in velocity (and, later, acceleration) way easier.

this.position = createVector(width - width/10, height/2);
this.velocity = createVector(random(-1,-0.3), random(-3,3));

Step 2 is to create basic collision between two objects. Using circles for our objects’ hitboxes simplifies this process greatly, as the distance between their centers only has to be less than the sum of their radii for them to be touching. To make Alfie carry one box at a time, we only attach a box to his coordinates if he isn’t holding another box and if the box hasn’t been delivered yet.

if (alfie.position.dist(box.position) < alfie.radius + (box.width/2) && alfie.holding == false) {
    if (box.held == false && box.delivered == false) {
      alfie.holding = true;
      box.held = true;
    }
  }
// ...
// To help Alfie get stuck less, this preemptively checks if he'll collide with an obstacle on the next frame
let positionNext = p5.Vector.add(alfie.position,alfie.velocity);
if (positionNext.dist(obstacle.position) < this.r+i.r) {
    this.position.add(this.velocity)
  }

Now we just have him change direction if he hits something else and we’re set, right?

Well, we can’t just reverse course if we hits a round obstacle. We need to distinguish hitting the side of an object (reversing the velocity’s X coordinate) from hitting the top or bottom (reversing the Y coordinate). That means Alfie would need to check the angle of collision with an obstacle to determine where he goes next, and since we’re already doing all this work, we might as well reflect the angle of his velocity over the angle of collision to make it feel satisfying.

Step 3 is translating all this code to collision with multiple objects. Both types of collision need to check Alfie’s position relative to what he collides with, and in my pursuit of efficiency, I figured I could decrease the number of arrays I needed to write if I bundled the loop that checks every object’s relative position into the loop that draws every relative object.

// In the draw function
for (i=0;i<obstructs.length;i++) {
  alfie.collision(obstructs[i]);
}
// and in Alfie's collision function
  let iDirection = p5.Vector.sub(this.position, i.position);
  let vMag = this.velocity.mag();
  if (this.position.dist(i.position) < this.r + i.r) {
    print("collide!");
  }

It’s rough-looking, hard to bugfix, and can’t be translated to sketches with multiple Alfies. But it’s satisfying!

Step 4 is making the obstacles move. This introduced a slew of problems into the way I coded Alfie’s changing direction: I had to adapt if he hit an obstacle at too wide an angle, or two obstacles at once, or obstacles that overlapped, or an obstacle and a wall at the same time to keep him from doing mating dances around whatever he touched. It took WEEKS before I tried the lerp() function and got a reliable fix I could adapt to other projects, and I’m still having issues getting some vector functionality to work. So, this is where I’ve left Alfie. He’s been through a lot and a quarter of his code is commented out (see it here!), but he’s given me a lot of learning experience, and I look forward to what his framework turns into later.

-Rafi

Read comments (1)