Keeping track of previous position for collision detection

Hello all. So far all the gracious answers on this forum have kept me from posting, but this one is stumping me too hard.

I have a class “Root”, which is an ellipse that gets drawn following a random and varying direction.
I’ve been trying to integrate collision detection by filling the ellipses previously drawn positions into an ArrayList and then, within the class itself, checking the current location.x and location.y position of the ellipse against the previous location.x and location.y positions stored in the ArrayList (see “PVector storeDrawn()” and “void collsionDetect()” ).

At the moment there are two major problems:

  1. The for loop is checking the current position against the position from the frame / iteration immediately before hand - so the if statement of “dist < 40?” is always going to be true.

  2. The ellipse also crosses over previously drawn positions without the if statement triggering (picture attached). So even though the for array is collecting the previous positions, and is having the current position checked against them, it’s still not detecting a collision between the two - and I dont know why.

I suspect I’m going about the ArrayList / for loop combination incorrectly. But can’t figure this one out any further without help!

Root[] root = new Root[1];

void setup() {
  size (800, 800, P2D);
  for (int i = 0; i < root.length; i++) {
    root[i] = new Root(0, 200);
  }
}

void draw() {
  for (int i = 0; i < root.length; i++) {
    root[i].update();
    root[i].display();
    root[i].noEdges();
    root[i].collisionDetect();
  }
}
class Root {

  ArrayList<PVector> drawn = new ArrayList<PVector>();

  PVector bottomTarget;
  PVector location;
  PVector velocity;
  PVector acceleration;
  PVector direction;


  float t;
  float radius = 5;
  float tx;
  float ty;

  int topSpeed = 1;
  int counter = 0;

  Boolean collided = false;

  Root(float dirX, float dirY) {
    location = new PVector(width / 2, 0);
    velocity = new PVector(0, 0);
    direction = new PVector(dirX, dirY);
  }

  void update () {

    PVector bottomTarget = new PVector(width / 2, height);
    PVector acceleration = PVector.sub(bottomTarget, location);
    PVector randTurn = new PVector(noise(tx), noise(ty));

    acceleration.add(direction);
    acceleration.setMag(1);
    acceleration.normalize();
    acceleration.mult(1);

    velocity.add(acceleration);
    velocity.limit(topSpeed);

    location.add(randTurn);
    location.add(velocity);

    tx += 0.02;
    ty += 0.04;
  }

  void display() {
    fill(0);
    ellipse(location.x, location.y, radius, radius);
    storeDrawn();
  }

  // store the current xy pos as a pvector and move onto next cell in arraylist
  PVector storeDrawn() {
    PVector v = new PVector(0, 0);
    drawn.add( new PVector(location.x, location.y));
    for (int i = 0; i < drawn.size(); i++) {
      v = drawn.get(i);
    }

    return v;
  }

  // check if current xy pos will collide with any previous xy pos
  void collisionDetect() {
    if ( millis() / 1000 > 5) {
      for (int i = 0; i < drawn.size(); i++) {
        if (dist(location.x, location.y, drawn.get(i).x, drawn.get(i).y) < 40) {
          direction.add(20, 0);
          alterPath();
          collided = true;
        }
      }
    }
  }

  // random path variation
  void alterPath() {
    velocity.add( -1, 0);
  }

  // teleport to other edge on canvas edge collision
  void noEdges() {
    if (location.x > width) {
      location.x = 0;
    } else if (location.x < 0) {
      location.x = width;
      //radius += 5;
    }

    if (location.y > height) {
      location.y = 0;
    } else if (location.y < 0) {
      location.y = height;
    }
  }

  void growInsidePot() {
    if ((location.x > width) || (location.x < 0)) {
      velocity.x = velocity.x * -1;
      //println("in function x:", velocity.x);
    }
    if ((location.y > height) || (location.y < 0)) {
      velocity.y = velocity.y * -1;
      //println("in function x:", velocity.y);
    }
  }
}


You may be detecting the collision correctly, and just not doing enough about it.

First of all, the PVector direction doesn’t seem to be used anywhere in a meaningful way. You create it, and update it when a collision occurs, but it’s never used anywhere else.

Next, when a collision happens, you simply call alterPath(), which only modifies the velocity slightly. Perhaps you could make it do something more? Bounce, like in noEdges? Change color?

Also, you have a collided boolean, and it’s got a value that does change when a collision happens, but, again, it’s never used for anything else.

1 Like

Thanks for the speedy reply.
I followed your advice and made the result of the collision more obvious by changing the stroke color and also implemented direction reversal like in noEdges.

I also edited the for loop in a way that I thought may stop it from checking the current state - against its past state - in the exact same frame when being saved to the array… Hope that makes sense.

  // check if current xy pos will collide with any previous xy pos
  void collisionDetect() {
    if ( millis() / 1000 > 2) {
      for (int i = 100; i < drawn.size(); i++) {
        if (dist(location.x, location.y, drawn.get(i-90).x, drawn.get(i-90).y) < 40) {

          alterPath();
          collided = true;
        }
      }
    }
  }

  // random path variation
  void alterPath() {
    velocity.x = velocity.x * -1;
    stroke(random(255), random(255), random(255));
  }

So you were right in that the collision was working, but it seems to work only some of the time. In the picture below you can see the wiggly vertical lines are drawn because the ellipse is bouncing away from its closest wall. However, later when it crosses over from the left, it crosses over the other lines without reversing the direction. Any further ideas?

Is it possible that at a certain point the ArrayList itself runs into trouble?
ie is this a problem thats related to time running too long - and then yielding a different result from the algorithm?

I didn’t have time to read your code completely.

But it reminded me of this example: Non-orthogonal Collision with Multiple Ground Segments / Examples / Processing.org (three tabs)

Please note that the ground (in your case that would be the older line you want to check your new line against) consists of small line segments. Because of that the ball (orb, equivalent to your new line) can bounce in different angles.

I think in your code it’s possible in rare cases that your new line moves through the older line (a glitch when the points are too far apart). It would help if you store it as line segments like in the example above. Then you can also make a better bouncing.

Chrisir