Uncaught TypeError: Cannot read property 'collide' of undefined (sketch: line 19)

Hello,

I am trying to spend some time to figure out how to track and remove elements from an object array, and “thought” I had a pretty good understanding of what I needed to do. I am getting the above error on occasion runs of my code and believe I must be referencing a non-existent index in my array, but for the life of me can’t figure out why. I thought by counting backwards in my for loops and checking that I wasn’t comparing the same array index that I would have covered my bases… Alas no and I am feeling my lack of understanding.

var bubbles = [];

function setup() {
  createCanvas(400, 400);
  for (let i = 0; i < 5; i++) {
    bubbles[i] = new Bubble();
  }
}

function draw() {
  background(220);
  if (bubbles.length > 1) {
    for (let i = bubbles.length - 1; i >= 0; i--) {
      bubbles[i].update();
      bubbles[i].display();

      for (let j = bubbles.length - 1; j >= 0; j--) {
        if (i != j) {
          bubbles[i].collide(bubbles[j]);
        }
      }
    }
  }
}

function Bubble() {
  this.x = random(width);
  this.y = random(height);
  this.size = 20;
  this.display = function() {
    circle(this.x, this.y, this.size);
  }
  this.update = function() {
    this.x += random(-1, 1);
    this.y += random(-1, 1);
  }
  this.collide = function(other) {
    var dia = 20;
    var dt = dist(this.x, this.y, other.x, other.y);
    if (dt < dia) {
      this.size += other.size;
      bubbles.splice(other.index, 1);
    }
  }
}
1 Like

Oh, and if it doesn’t generate the error, just increase the i < 5 in the initialization loop in setup().

Hello, and welcome to the forum!

Ah, this is a classic. :slight_smile: Removing elements while looping over them can cause headaches. Do you know how to use the JavaScript debugger in your browser? This is an excellent opportunity to learn otherwise. You can tell the debugger to stop executing the code when the exception happens. From there, you can explore the state of the program and ask questions like: is the value of i what I expect it to be?

Get Started with Debugging JavaScript in Chrome DevTools

But even without a debugger, we could reason about the exception together. The error message tells us that the code tried to call collide on undefined. Like this: undefined.collide(bubbles[j]). But that’s not what the code at line 19 looks like:

bubbles[i].collide(bubbles[j]);

In which state of the program could bubbles[i] turn out to be undefined? Well, when i is larger than bubbles.length, bubbles[i] will return undefined for sure. And that is what is happening.

Now, can you see how this can occur in some rare cases?

1 Like

Sven,

Thank you for your thought and insight into my problem. You’ve given me plenty to consider. So let me try and state back my understanding:

You are saying that it is possible for the index of bubbles to be larger than the array’s length. For example, I might have already made the array shorter than (10 - 1) when it sees bubbles[10]?

I thought that array.splice removes the element and then renumbers the array 0-x? Is it that I check bubbles.length before I splice?

I will follow-through on learning how to use the debugger.

Thanks in advance for your help.

I’ll be honest, using a debugger with the p5.editor is pretty tricky and from what I can see doesn’t yield much more than the console log…

However, is this the sort of thing you’re thinking of:

      for (let j = bubbles.length - 1; j >= 0; j--) {
        if (i != j) {
          if (typeof bubbles[i] != 'undefined') {
            bubbles[i].collide(bubbles[j]);
          }
        }
      }

Would check that bubbles[i] is not defined work?

Yes, that check for undefined will make that exception go away.