Double hit on object collision and repeat trigger

Hello processing forum :slight_smile:

I’m making a small program that moves circles (‘buoys’) around the screen that are then triggered by expanding circles (‘waves’) in turn making more waves of their own. Waves have random speeds.

I’ve tried to make an MCVE below with a stationary test buoy and one that you move with the mouse.

I have 3 problems that I can’t figure out.

Problem 1: Each wave triggers each buoy twice when it hits, I’ve tried to resolve this by tracking which buoys the waves have hit and checking that before triggering

Problem 2: A slightly different problem, I would like each wave to only trigger a buoy once, I thought the solution for problem 1 would fix this also :frowning:

Problem 3: The collision detection algorithm I am using is patchy and because both the waves and buoys are moving sometimes it will not trigger. Is there a better way to do this? EDIT: I’m going to explore this as a solution? https://stackoverflow.com/questions/49722061/processing-how-to-detect-collisions-when-one-object-is-traveling-too-fast

Any help appreciated!

import java.util.Iterator;

ArrayList<Wave> waves = new ArrayList<Wave>();
int time;

void setup() {
  size(800, 800);
}

void draw() {
  background(0);
  //make buoys and add to arraylist
  ArrayList<buoy> buoys = new ArrayList<buoy>();
  buoys.add(new buoy(3*width/4, height/2, 100));
  buoys.add(new buoy(mouseX, mouseY, 101));
  //display buoys
  for (buoy b : buoys) {
    b.update();
  }
  //make waves
  makeWaves();
  //check if waves hit buoys
  checkHits(buoys);
}

class buoy {
  float xpos, ypos;
  int hits, level, dia, id;
  buoy ( float x, float y, int i) {
    xpos = x;
    ypos = y;
    id = i;
    dia = 30;
  }
  void update() {
    noStroke();
    fill(255, 0, 0);
    ellipse(xpos, ypos, dia, dia);
  }
}

class Wave {
  float xpos, ypos, maxdia, dia, speed, setf;
  color colour;
  int alphalevel, origin, id;
  int[] hitbuoys;

  Wave ( float x, float y, float sd, float md, float s, float sf, color c, int o) {
    xpos = x;
    ypos = y;
    maxdia = md;
    dia = sd; //set start diameter
    speed = s;
    setf = sf; //set fade on/off
    alphalevel = 255;
    colour = c;
    origin = o; //set origin of wave for big waves origin is 0 for bouywaves it's bouy.id
    hitbuoys = new int[0]; //array to track buoys this wave has already triggered
  }
  void update() {
    if ( setf > 0) {
      alphalevel = int(map( dia, 0, maxdia, 255, 0));
    }
    strokeWeight(5);
    noFill();
    stroke(color(colour, alphalevel));
    ellipse(xpos, ypos, dia, dia);
    dia += speed/2;
  }
}

void makeWaves() {
  //make waves randomly over time
  if ( millis() > time) {
    waves.add(new Wave(width, height/2, 0, 2*width, random(2, 4), 1, color(0, random(40, 240), random(220, 255)), 0));
    if ( random(0, 1) > 0.9) {
      time = millis() + int(random(1600, 2000));
    } else {
      time = millis() + int(random(4000, 8000));
    }
  }
  //display waves and delete once at max diameter
  Iterator itrW = waves.iterator();
  Wave waveElement = null;
  while (itrW.hasNext()) {
    waveElement = (Wave)itrW.next();
    waveElement.update();
    if (waveElement.dia > waveElement.maxdia) {
      itrW.remove();
    }
  }
}

void checkHits(ArrayList buoys) {
  //iterate through buoys
  Iterator itrB = buoys.iterator();
  buoy buoyElement = null;
  while (itrB.hasNext()) {
    //create arraylist to add buoywaves to
    ArrayList<Wave> buoywaves = new ArrayList<Wave>();
    buoyElement = (buoy)itrB.next();
    //iterate through waves
    for (Wave wave : waves) {      
      //check that the wave does not originate from the buoy to stop buoys triggering themselves
      if (wave.origin != buoyElement.id) {
        //check whether this wave has triggered this buoy before
        boolean hitbefore = false;
        for (int a : wave.hitbuoys) {
          if (a == buoyElement.id) {
            hitbefore = true;
          }
        }
        if (hitbefore == false) {
          //check if wave is hitting buoy is there a better way to do this?!? if the buoy is moving fast it can miss the wave trigger
          float r=wave.dia/2;
          float x=buoyElement.xpos;
          float y=buoyElement.ypos;
          float cx= wave.xpos, cy= wave.ypos;
          float dist= (x-cx)*(x-cx)+(y-cy)*(y-cy);
          if ((dist >= r*r) && (dist < (r + (wave.speed/2))*(r + (wave.speed/2)))) {
            //add this buoy id to the array of buoys triggered by this wave and generate buoy waves
            append(wave.hitbuoys, buoyElement.id);
            buoywaves.add(new Wave(buoyElement.xpos, buoyElement.ypos, buoyElement.dia, map(wave.alphalevel, 0, 255, buoyElement.dia, 800), random(1, 2), 1, 255, buoyElement.id));
          }
        }
      }
    }
    //add buoywaves to main waves arraylist
    waves.addAll(buoywaves);
  }
}

It’s no solution to one of your Problems but you can save a little code if you use the dist function.
It can directly calculate the distance between two points.

dist(x1,y1,x2,y2)=sqrt(sq(x1-x2)+sq(y1-y2));

A thing you can try is taking the velocity of the buoy and make a loop with checks every Pixel on the way.
The look will look like this

for(int i=0;i<=dist(x,y,vx,vy);i++){}

And the point to check is.

x1+vx*i/dist(x,y,vx,vy),y1+vy*i/dist(x,y,vx,vy)
1 Like

Thanks for this. Yes I will try and change the collision detection to something like that.

I have solved problem 1, double trigger of collision by removing the division by 2 when increasing my wave diameter during update, so dia += speed instead of dia += speed/2

I still can’t figure out why storing the id’s of buoys triggered by a wave and then checking that array before triggering isn’t working to stop repeat triggering of buoys by the same wave though.

Problem 2 solved, I wasn’t using append properly, so wave.hitbouys = append(wave.hitbuoys, buoyElement.id); instead of just append(wave.hitbuoys, buoyElement.id);