Search code examples
javascriptcollision-detectionp5.js

How to stop collide2D from detecting p5.js


I am using the collide2D library in p5.js to detect if my player hits an obstacle. If it does, i wantthe player to have 1 less lives. The problem i've run in to is that when i hit an obstacle it keeps removing lives for the whole time i hover over it so i end up with -100 lives when i hover over the whole obstacle.

Code in class Rock(my obstacle):

    isColliding(obj) {
      let hit = collideRectCircle(obj.x - 55, obj.y - 60, 105, 109, this.x, this.y, 130);
      return hit;
    }

code in draw:

  for (let i = 0; i < rocks.length; i++) {
    if (rocks[i].isColliding(unicorn)) {
      lives -= 1
      // if (lives <= 0) {
      //   gameOver();
      // }
    }

Solution

  • This sounds like a case where instead of detecting that a condition is true, you want to detect when the condition changes from false to true. The trick is you need to track the state of the condition per-obstacle (assuming two rocks colliding with unicorn simultaneously should decrement lives by 2). There are a couple of ways you could do that:

    // Option 1. Store the rock-unicorn collision state on each rock
    function draw() {
      // ...
    
      for (let i = 0; i < rocks.length; i++) {
        if (rocks[i].isColliding(unicorn)) {
          if (!rocks[i].wasColliding) {
            lives -= 1;
          }
          // Additional collisions with this rock will not decrement another life
          rocks[i].wasColliding = true;
        } else {
          // Once the collision ends, the rock becomes dangerous again
          rocks[i].wasColliding = false;
        }
      }
    }
    

    or

    // Option 2. keep track of the collision states in a Set on unicorn
    // This assumes that unicorn.collidingRocks = new Set() has been run when unicorn is created
    // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
    function draw() {
      // ...
    
      for (let i = 0; i < rocks.length; i++) {
        if (rocks[i].isColliding(unicorn)) {
          if (unicorn.collidingRocks.has(rocks[i])) {
            lives -= 1;
          }
          // Additional collisions with this rock will not decrement another life
          unicorn.collidingRocks.add(rocks[i]);
        } else {
          // Once the collision ends, the rock becomes dangerous again
          unicorn.collidingRocks.delete(rocks[i]);
        }
      }
    }
    

    Option two would be a little less efficient, because it has to do set lookups/adds/deletes instead of just 𝚶(1) array index lookups when checking for or changing the collision state. However it would be better OOP design since it's really the unicorn that cares whether it is already colliding with the rocks, rather than the rocks caring. This would have practical implications too in the case where there were more than one unicorn for example.