Collision rect - ellipse : Multiple questions - More info in Body

  1. How can I make that when the laser hits the rectangle that randomly spawns, the laser will just stop? Like it will not go any further but will stop?

  2. How can I make collision so my player (ellipse) will be not able to go through the rectangle from question 1? Thank you!

The Code for both questions >

float px, py;
float len;
int value = 0;
float rx, ry;
float wx = 30, wy = 70;

void setup(){
  size(800, 600);
  cursor(CROSS);
  len = max(width + 12121, height + 12121);
  px = 255;
  py = 199;
  stroke(0);
  strokeWeight(2.7);
  rx = random(800);
  ry = random(600);
}

void draw(){
  background(255);
  drawLine(px, py, mouseX, mouseY);
  fill(0);
  stroke(2.77);
  fill(255);
  ellipse(px, py, 20, 20);
  rect(rx, ry, wx, wy);
  
  if(px > width - 10) {
    px = width - 10;
  }
  if(px < 10) {
    px = 10;
  }
  if(py > height - 10) {
    py = height - 10;
  }
  if(py < 10) {
    py = 10;
  }
}

void drawLine(float fx, float fy, float tX, float tY){
  float ang = atan2(tY - fy, tX - fx);
  float x = fx + cos(ang) * len;
  float y = fy + sin(ang) * len;
  stroke(255,0,0);
  strokeWeight(3);
  line(fx, fy, x, y);
}

void keyPressed() {
  if(keyPressed == true && key == 'd' || key == 'D') {
    px = px + 4;
  }
    if(keyPressed == true && key == 'a' || key == 'A') {
    px = px - 4;
  }
    if(keyPressed == true && key == 's' || key == 'S') {
    py = py + 4;
  }
    if(keyPressed == true && key == 'w' || key == 'W') {
    py = py - 4;
  }
}

1 Like

Answer to part 2

square collisions detection relies on knowing, the x,y co-ordinate of the first corner and the width and height of the rectangle.

your if statement should look like this;

return p1.x > square.x && p1.x < square.x + width && p1.y > square.y && p1.y < square.y + width;

using returns means you don’t need to encapsulate the condition in an if statement.

This will evaluate to true if that point is in the square. Note this will work for an ellipse but you need to amend it to include the radius of the ellipse. So what was p1.x will become (p1.x + ellipse.radius) and so on

1 Like

Processing or p5js? ?

For part one I think it would depend how you are coding the laser. it should have two points p1 and p2.

you can either use a line line intersection check, or I suppose a point line intersection check would work as well. The line point is deffo easier.

boolean check_lineP(PVector a, PVector b,PVector c){
    
    boolean k = false;
    float d1 = dist(a.x,a.y,b.x,b.y);
    float d2 = dist(a.x,a.y,c.x,c.y);
    float d3 = dist(b.x,b.y,c.x,c.y);
    float d4 = d2 + d3;
    
    float d5 = dist(a.x,a.y,c.x,c.y);
    float d6 = dist(b.x,b.y,c.x,c.y);
    
    //if(d5>=inc/2&&d6>=inc/2){
    if(d4 <= d1 + 0.05){
      k = true;
    }
    return k;
  };
  
};

heres a graphic to help explain it, this however will not return a collision point, and will simply tell you when the distance of point 2 is less than the width/height of the rectangle, you would therefore need to do this check for all sides of the rectangle, which means you would also need to test to see if the point is within said sides bounding region, otherwise all the sides will respond to a distance check.

the line line uses this code;

PVector check_intersect(Boundary a, Boundary b){

    float a1 = a.y2 - a.y1;
    float b1 = a.x1 - a.x2;
    float c1 = a1 * a.x1 + b1 * a.y1;
    float a2 = b.y2 - b.y1;
    float b2 = b.x1 - b.x2;
    float c2 = a2 * b.x1 + b2 * b.y1;
    float denom = a1 * b2 - a2 * b1;
    
    if((a.x1==b.x1&&a.x2==b.x2)&&(a.y1==b.y1&&a.y2==b.y2)){
      
      return null;
    }
     else{
        
    Float X = (b2 *c1 - b1 * c2) / denom;
    Float Y = (a1 *c2 - a2 * c1) / denom;
    
    PVector p = new PVector(X,Y);   
      boolean Linea = ((p.x<a.x1&&p.x>a.x2)||(p.x>a.x1&&p.x<a.x2))&&((p.y<a.y1&&p.y>a.y2)||(p.y>a.y1&&p.y<a.y2));
      boolean Lineb = ((p.x<b.x1&&p.x>b.x2)||(p.x>b.x1&&p.x<b.x2))&&((p.y<b.y1&&p.y>b.y2)||(p.y>y1&&p.y<b.y2));
      if(Linea&&Lineb){
        
        point(p.x,p.y);
        return p;
      }
      else{
      return null;
      }}
  };

and will return a point of intersection. Again you would need to test this for all sides.

2 Likes

this is processing, not p5.js

if you want to understand the math to the line line check, heres the best resource I’ve found.

1 Like

Thank you, but doesn’t work.

you’re gonna have to be a bit more specific. Which method did you decide to go with.

please understand that this is a public forum where we help each other.

  • you asked questions
  • you got answers

in future someone might google / or search this forum directly
a similar question
so he end up here at this topic

  • -1- so deleting questions and answers is not what we do here

  • -2- if you found a answer / solution ( even if elsewhere … )
    we expect that you share this here ( for any future readers )


let me share something about my history in this “world”
many years ago starting coding Arduino ( same PDE )
i learned about finding help from googling / code sharing / forums / …
and learned the hard way, got very angry because nothing worked !
until i got it:

do not copy code from questions!
from answers only

LOL


2 Likes

nothing works, what people told me.

very sorry that we failed you,

next time we both work more exact?

-you- with single questions per topic, well prepared with a MVCE code
what can be run/tested by us.

-we- by asking back when we not understand your question.


but not forget, even you would have got a wrong answer
it means someone try to help you
and spend some of our free time to answer.

so still i insist on my last point -2-
that you share your solution to the community

worst cases happen that someone asks questions to rare topics / libraries usage cases
and NOT get any answer, so post back a own solution ,
with the remark " looks like i am talking to myself "
yes, can happen, still the right way.


Hello, I am searching for answers but thanks for your time.

Ok. How do I Delete this post? cause I accidentally deleted the game.

Please note the line line intersection code makes use of a boundary class, which is just made up of two pvectors, for p1 and p2 of any line. So if you want to use it you either have to create said class or just pass 4 pvector points and amend the code.

The thing is this code works one 100% however expecting code 100% ready to work, is like saying please complete my assignment for me, which I sometimes do, but I have to be at my desk and I have to have the time, also in general this is not good practice as it doesnt encourage personal understanding of a topic or personal research. I understand that sometimes finding the resources online can be frustrating which is why when I am not available to code everything from scratch, and in this case creating a line detection for a shape class is something which is a little more than trivial I always leave all the resources required. Hence the videos and the links, which again as I said if you watch and or read will lead you to the solution you are looking for.

4 Likes

here’s working code based on the first type of collision I suggested. uses a Rect class, to handle all the edges if you wanted to opt for point line collsions or line line collision, and a Lazer class, which is basically a line where you can play around with the individual points and add some logic.

https://www.openprocessing.org/sketch/783621

that’s much more complicate than I thought

I tried line line intersection with a class boundary.

It’s not too bad

but when mouse is opposite the Box, the laser stops too. Annoying.

Why?

Search for ??? in the code please.

Thank you very much!!!

Chrisir

// see
// https://discourse.processing.org/t/collision-rect-ellipse-multiple-questions-more-info-in-body/15155/2 

// player 
float px, py; // player 
float pWidth=20; // player
float pWidthHalf = pWidth/2;// player

// rect / obstacle 
float rx, ry;
float wx = 30, wy = 70;
Boundary[] rectBoundaries = new Boundary [4]; 

// ----------------------------------------------------------------------------------------------
// processing core functions 

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

  cursor(CROSS);
  px = 255;
  py = 199;
  stroke(0);
  strokeWeight(2.7);

  // random pos of the rect BUT with a distance to the border, so the rect does not leave the screen
  rx = random(width-wx);
  ry = random(height-wy);

  // seeing the rect as lines 
  rectBoundaries[0] = new Boundary( rx, ry, rx+wx, ry ) ;         // -->  right   
  rectBoundaries[1] = new Boundary( rx+wx, ry, rx+wx, ry+wy ) ;   // |  down  
  rectBoundaries[2] = new Boundary( rx+wx, ry+wy, rx, ry+wy   ) ; // <-- left  
  rectBoundaries[3] = new Boundary( rx, ry+wy, rx, ry ) ;         // | and up again
}

void draw() {
  background(255);

  // draw a Laser ------------------------------------
  drawLine(px, py, mouseX, mouseY);

  // show player ----------------------------------------------
  stroke(0); // black 
  fill(0, 255, 0); // green 
  ellipse(px, py, pWidth, pWidth);

  // show rect / obstacle -----------------------------------
  stroke(0, 0, 255); // blue 
  fill(255);  // white 
  rect(rx, ry, wx, wy);
  //for (Boundary bBox : rectBoundaries) { 
  //  bBox.display();
  //}//for 

  // check player against screen border ---------------------------- 
  if (px > width - pWidthHalf) {
    px = width - pWidthHalf;
  }
  if (px < pWidthHalf) {
    px = pWidthHalf;
  }
  if (py > height - pWidthHalf) {
    py = height - pWidthHalf;
  }
  if (py < pWidthHalf) {
    py = pWidthHalf;
  }
}

// ----------------------------------------------------------------------------------------------
// other functions 

void drawLine(float fx, float fy, 
  float tX, float tY) {
  // Laser   
  // fx,fy is the player, tX,tY the mouse.

  // Laser length  
  float len = max(width + width, height + width); // WAS + 12121 ;
  // angle 
  float ang = atan2(tY - fy, tX - fx);
  // x and y is he new target pos of the laser when not interrupted by box. 
  float x = fx + cos(ang) * len;
  float y = fy + sin(ang) * len;

  // check if laser is interrupted by box. 
  Boundary laser = new Boundary(fx, fy, 
    x, y);
  for (Boundary bBox : rectBoundaries) {
    PVector newTarget = check_intersect ( bBox, laser );  
    if ( newTarget != null ) {
      // Yes.
      println("Here 1 ");
      x=newTarget.x;
      y=newTarget.y;
    }//if
  }//for 

  // red laser 
  stroke(255, 0, 0);
  strokeWeight(3);
  line(fx, fy, 
    x, y);
}//func 

// -----------------------------------------------------------------------------------------------
// Inputs

void keyPressed() {
  // 4 is the speed of the player.
  // We ignore the key if player would hit the box. 

  if (keyPressed == true && key == 'd' || key == 'D') {
    if (!collision1(new PVector(px+pWidthHalf+4, py), new PVector( rx, ry ), wx, wy))   
      px = px + 4;
  }
  if (keyPressed == true && key == 'a' || key == 'A') {
    if (!collision1(new PVector(px-pWidthHalf-4, py), new PVector( rx, ry ), wx, wy))   
      px = px - 4;
  }
  if (keyPressed == true && key == 's' || key == 'S') {
    if (!collision1(new PVector(px, py+pWidthHalf+4), new PVector( rx, ry ), wx, wy))   
      py = py + 4;
  }
  if (keyPressed == true && key == 'w' || key == 'W') {
    if (!collision1(new PVector(px, py-pWidthHalf-4), new PVector( rx, ry ), wx, wy))
      py = py - 4;
  }
}

// -------------------------------------------------------------------------------------------------
// the math bit 

boolean collision1 (PVector p1, PVector square, float widthSquare, float  heightSquare) {
  // This is used when moving the player against the box. 
  // This will evaluate to true if that point p1 is in the square "square".
  return p1.x > square.x && 
    p1.x < square.x + widthSquare && 
    p1.y > square.y && 
    p1.y < square.y + heightSquare;
}

PVector check_intersect(Boundary a, Boundary b) {
  // This checks laser against rect. 

  float a1 = a.y2 - a.y1; 
  float b1 = a.x1 - a.x2; 
  float c1 = a1 * a.x1 + b1 * a.y1; 
  float a2 = b.y2 - b.y1; 
  float b2 = b.x1 - b.x2; 
  float c2 = a2 * b.x1 + b2 * b.y1; 
  float denom = a1 * b2 - a2 * b1; 

  // leave when both lines a and b are the same 
  if ((a.x1==b.x1&&a.x2==b.x2) &&
    (a.y1==b.y1&&a.y2==b.y2)) {
    return null;
  } 

  Float X = (b2 * c1 - b1 * c2) / denom; 
  Float Y = (a1 * c2 - a2 * c1) / denom; 

  PVector p = new PVector(X, Y); 
  boolean Linea = a.compare(p); 
  boolean Lineb = b.compare(p);

  // if ! (p is inside both) [function checks for endless lines; we have to avoid this] 
  if  ( ! (Linea && Lineb)) { // ???? 
    // checks if laser point is on the box 
    if (pointOfCollisionIsOnRect(p)) {  // ????? 
      // point(p.x, p.y);
      stroke(11);
      ellipse (p.x, p.y, 7, 7);
      return p;
    }
  }// if 

  // No match found  
  return null;
  //
}//func 

boolean pointOfCollisionIsOnRect(PVector p) {
  return 
    p.x>rx-2    &&
    p.x<rx+wx+2 && 
    p.y>ry-2    && 
    p.y<ry+wy+2 ;
}

// ===================================================================

class Boundary {

  // I am a line

  float x1, y1, 
    x2, y2; 

  // constr
  Boundary ( float x1_, float y1_, 
    float x2_, float y2_ ) {

    x1=x1_; 
    y1=y1_; 

    x2=x2_; 
    y2=y2_;
  }// constr

  void display() {
    stroke(0, 0, 255);
    line(x1, y1, 
      x2, y2);
  }//method 

  boolean compare(PVector p) {
    // This returns true when p is NOT inside the boundary  
    return
      ((p.x<x1&&p.x>x2)||
      (p.x>x1&&p.x<x2)) && 
      ((p.y<y1&&p.y>y2)||
      (p.y>y1&&p.y<y2));
  }//method 
  //
}//
//
1 Like

Amended your code slightly, your !(linea && lineb) should simply be linea && lineb

also

in your drawline function;

float x = mouseX;
float y = mouseY;

then x &&y are updated if there is an intersection.

// see
// https://discourse.processing.org/t/collision-rect-ellipse-multiple-questions-more-info-in-body/15155/2 

// player 
float px, py; // player 
float pWidth=20; // player
float pWidthHalf = pWidth/2;// player

// rect / obstacle 
float rx, ry;
float wx = 30, wy = 70;
Boundary[] rectBoundaries = new Boundary [4]; 

// ----------------------------------------------------------------------------------------------
// processing core functions 

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

  cursor(CROSS);
  px = 255;
  py = 199;
  stroke(0);
  strokeWeight(2.7);

  // random pos of the rect BUT with a distance to the border, so the rect does not leave the screen
  rx = random(width);
  ry = random(height);

  // seeing the rect as lines 
  rectBoundaries[0] = new Boundary( rx, ry, rx+wx, ry ) ;         // -->  right   
  rectBoundaries[1] = new Boundary( rx+wx, ry, rx+wx, ry+wy ) ;   // |  down  
  rectBoundaries[2] = new Boundary( rx+wx, ry+wy, rx, ry+wy   ) ; // <-- left  
  rectBoundaries[3] = new Boundary( rx, ry+wy, rx, ry ) ;         // | and up again
}

void draw() {
  background(255);

  // draw a Laser ------------------------------------
  drawLine(px, py, mouseX, mouseY);

  // show player ----------------------------------------------
  stroke(0); // black 
  fill(0, 255, 0); // green 
  ellipse(px, py, pWidth, pWidth);

  // show rect / obstacle -----------------------------------
  stroke(0, 0, 255); // blue 
  fill(255);  // white 
  rect(rx, ry, wx, wy);
  //for (Boundary bBox : rectBoundaries) { 
  //  bBox.display();
  //}//for 

  // check player against screen border ---------------------------- 
  if (px > width - pWidthHalf) {
    px = width - pWidthHalf;
  }
  if (px < pWidthHalf) {
    px = pWidthHalf;
  }
  if (py > height - pWidthHalf) {
    py = height - pWidthHalf;
  }
  if (py < pWidthHalf) {
    py = pWidthHalf;
  }
}

// ----------------------------------------------------------------------------------------------
// other functions 

void drawLine(float fx, float fy, 
  float tX, float tY) {
  // Laser   
  // fx,fy is the player, tX,tY the mouse.

  // Laser length  
  float len = max(width + width, height + width); // WAS + 12121 ;
  // angle 
  float ang = atan2(tY - fy, tX - fx);
  // x and y is he new target pos of the laser when not interrupted by box. 
  //float x = fx + cos(ang) * len;
  //float y = fy + sin(ang) * len;
  float x = mouseX;
  float y = mouseY;
  // check if laser is interrupted by box. 
  Boundary laser = new Boundary(fx, fy, 
    x, y);
  for (Boundary bBox : rectBoundaries) {
    PVector newTarget = check_intersect ( bBox, laser );  
    if ( newTarget != null ) {
      // Yes.
      println("Here 1 ");
      x=newTarget.x;
      y=newTarget.y;
    }//if
  }//for 

  // red laser 
  stroke(255, 0, 0);
  strokeWeight(3);
  line(fx, fy, 
    x, y);
}//func 

// -----------------------------------------------------------------------------------------------
// Inputs

void keyPressed() {
  // 4 is the speed of the player.
  // We ignore the key if player would hit the box. 

  if (keyPressed == true && key == 'd' || key == 'D') {
    if (!collision1(new PVector(px+pWidthHalf+4, py), new PVector( rx, ry ), wx, wy))   
      px = px + 4;
  }
  if (keyPressed == true && key == 'a' || key == 'A') {
    if (!collision1(new PVector(px-pWidthHalf-4, py), new PVector( rx, ry ), wx, wy))   
      px = px - 4;
  }
  if (keyPressed == true && key == 's' || key == 'S') {
    if (!collision1(new PVector(px, py+pWidthHalf+4), new PVector( rx, ry ), wx, wy))   
      py = py + 4;
  }
  if (keyPressed == true && key == 'w' || key == 'W') {
    if (!collision1(new PVector(px, py-pWidthHalf-4), new PVector( rx, ry ), wx, wy))
      py = py - 4;
  }
}

// -------------------------------------------------------------------------------------------------
// the math bit 

boolean collision1 (PVector p1, PVector square, float widthSquare, float  heightSquare) {
  // This is used when moving the player against the box. 
  // This will evaluate to true if that point p1 is in the square "square".
  return p1.x > square.x && 
    p1.x < square.x + widthSquare && 
    p1.y > square.y && 
    p1.y < square.y + heightSquare;
}

PVector check_intersect(Boundary a, Boundary b) {
  // This checks laser against rect. 

  float a1 = a.y2 - a.y1; 
  float b1 = a.x1 - a.x2; 
  float c1 = a1 * a.x1 + b1 * a.y1; 
  float a2 = b.y2 - b.y1; 
  float b2 = b.x1 - b.x2; 
  float c2 = a2 * b.x1 + b2 * b.y1; 
  float denom = a1 * b2 - a2 * b1; 

  // leave when both lines a and b are the same 
  if ((a.x1==b.x1&&a.x2==b.x2) &&
    (a.y1==b.y1&&a.y2==b.y2)) {
    return null;
  } 

  Float X = (b2 * c1 - b1 * c2) / denom; 
  Float Y = (a1 * c2 - a2 * c1) / denom; 

  PVector p = new PVector(X, Y); 
  boolean Linea = a.compare(p); 
  boolean Lineb = b.compare(p);

  // if ! (p is inside both) [function checks for endless lines; we have to avoid this] 
  if  (  (Linea && Lineb)) { // ???? 
    // checks if laser point is on the box 
    if (pointOfCollisionIsOnRect(p)) {  // ????? 
      // point(p.x, p.y);
      stroke(11);
      ellipse (p.x, p.y, 7, 7);
      return p;
    }
  }// if 

  // No match found  
  return null;
  //
}//func

boolean pointOfCollisionIsOnRect(PVector p) {
  return 
    p.x>rx-2    &&
    p.x<rx+wx+2 && 
    p.y>ry-2    && 
    p.y<ry+wy+2 ;
}

// ===================================================================

class Boundary {

  // I am a line

  float x1, y1, 
    x2, y2; 

  // constr
  Boundary ( float x1_, float y1_, 
    float x2_, float y2_ ) {

    x1=x1_; 
    y1=y1_; 

    x2=x2_; 
    y2=y2_;
  }// constr

  void display() {
    stroke(0, 0, 255);
    line(x1, y1, 
      x2, y2);
  }//method 

  boolean compare(PVector p) {
    // This returns true when p is NOT inside the boundary  
    return
      ((p.x<x1&&p.x>x2)||
      (p.x>x1&&p.x<x2)) || 
      ((p.y<y1&&p.y>y2)||
      (p.y>y1&&p.y<y2));
  }//method 
  //
}//
//
3 Likes

Hello!

And you changed one && to a || here too:



  boolean compare(PVector p) {
    // This returns true when p is NOT inside the boundary  
    return
      ((p.x<x1&&p.x>x2)||
      (p.x>x1&&p.x<x2)) ||   // !!!!!!!!!
      ((p.y<y1&&p.y>y2)||
      (p.y>y1&&p.y<y2));
  }//method 
  //
}//class

And then if ( Linea && Lineb ) { works.

Remark

There also was another error.

This error was not visible because we drew the laser before the rect, so the rect covered the too long laser beam.

When we swap this (draw box before laser), we can see that the laser in some cases (box north-west of player) was cutting through the box onto the backside of the box and then stopped (too late) (that’s hard to explain but depending on the order of the lines of the box in the array rectBoundaries it can happen that we have 2 line intersections between laser and line of the box. Now we reset x,y twice. When the 2nd time the backside is last in rectBoundaries we overwrite the better value with the point more far away from the player. This is the case when the box is north-west of the player).

I corrected that by checking the distance of the 4 (2) reflection points to the player (using shortestDistance).
Or in short: we have to make sure that we hit the nearest side of the rect with the laser (and not the backside, seen from the player).

So draw box before laser is important for testing. Even after fixing the error though, it looks better when we draw laser before box, so the box covers the laser. Below is laser before box (this in draw()).

Full code below

Chrisir


// Laser Game 

// see
// https://discourse.processing.org/t/collision-rect-ellipse-multiple-questions-more-info-in-body/15155/2 

// player 
float px, py; // player 
float pWidth=20; // player size 
float pWidthHalf = pWidth/2;// player size half 

// rect / obstacle 
float rx, ry;
float wx = 30, wy = 70;
Boundary[] rectBoundaries = new Boundary [4]; // (to stop the laser later) 

// ----------------------------------------------------------------------------------------------
// processing core functions 

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

  cursor(CROSS);
  px = width/2;  // player
  py = height/2;
  stroke(0);
  strokeWeight(2.7);

  // random pos of the rect BUT with a distance wx and wy to the border, so the rect does not leave the screen
  rx = random(width-wx);
  ry = random(height-wy);

  // seeing the rect as lines (to stop the laser later)
  rectBoundaries[0] = new Boundary( rx, ry, rx+wx, ry ) ;         // -->  right   
  rectBoundaries[1] = new Boundary( rx+wx, ry, rx+wx, ry+wy ) ;   // |  down  
  rectBoundaries[2] = new Boundary( rx+wx, ry+wy, rx, ry+wy   ) ; // <-- left  
  rectBoundaries[3] = new Boundary( rx, ry+wy, rx, ry ) ;         // | and up again
}

void draw() {
  background(255);

  // draw Laser ------------------------------------
  drawLine(px, py, 
    mouseX, mouseY);

  // show player ----------------------------------------------
  stroke(0); // black 
  fill(0, 255, 0); // green 
  ellipse(px, py, pWidth, pWidth);

  // show rect / obstacle -----------------------------------
  stroke(0, 0, 255); // blue 
  fill(255);  // white 
  rect(rx, ry, wx, wy);

  // check player against screen border ---------------------------- 
  if (px > width - pWidthHalf) {
    px = width - pWidthHalf;
  }
  if (px < pWidthHalf) {
    px = pWidthHalf;
  }
  if (py > height - pWidthHalf) {
    py = height - pWidthHalf;
  }
  if (py < pWidthHalf) {
    py = pWidthHalf;
  }
}

// ----------------------------------------------------------------------------------------------
// other functions 

void drawLine(float fx, float fy, 
  float tX, float tY) {
  // Laser   
  // fx,fy is the player, tX,tY the mouse.

  // Laser length  
  float len = max(width + width, height + width); // WAS + 12121 ; for both 
  // angle 
  float ang = atan2(tY - fy, tX - fx);
  // x and y is the new target pos of the laser when not interrupted by box. 
  float x = fx + cos(ang) * len;
  float y = fy + sin(ang) * len;
  // (or simply float x=mouseX; float y=mouseY;)

  // check if laser is interrupted by box. Adjust x,y if necessary.  
  Boundary laser = new Boundary(fx, fy, // make a new Boundary object representing the laser 
    x, y);
  float shortestDistance=10000; // gives us the smallest distance eventually (pre-init shortestDistance with 10000)
  // check 4 sides of box 
  for (Boundary bBox : rectBoundaries) {
    // get null OR the point where laser and the side of the box intersect
    PVector newTarget = check_intersect ( bBox, laser );
    if ( newTarget != null ) {
      // We have an intersection. 
      // We also have to make sure that we hit the nearest side of the rect with the laser (and not the backside, seen from the player).
      float newDist=newTarget.dist ( new PVector(fx, fy) );  // measure new distance
      // compare distance to previous shortest distance "shortestDistance". Is it shorter?
      if (newDist < shortestDistance) {  
        // Yes.
        // store new shortest distance in "shortestDistance"
        shortestDistance = newDist;
        // Overwerite x and y. 
        x=newTarget.x;
        y=newTarget.y;
      }//if
    }//if
  }//for 

  // red laser 
  stroke(255, 0, 0);
  strokeWeight(3);
  line(fx, fy, 
    x, y);
}//func 

// -----------------------------------------------------------------------------------------------
// Inputs

void keyPressed() {
  // 4 is the speed of the player.
  // We ignore the key if player would hit the box. 

  if (keyPressed == true && key == 'd' || key == 'D') {
    if (!collision1(new PVector(px+pWidthHalf+4, py), new PVector( rx, ry ), wx, wy))   
      px = px + 4;
  }
  if (keyPressed == true && key == 'a' || key == 'A') {
    if (!collision1(new PVector(px-pWidthHalf-4, py), new PVector( rx, ry ), wx, wy))   
      px = px - 4;
  }
  if (keyPressed == true && key == 's' || key == 'S') {
    if (!collision1(new PVector(px, py+pWidthHalf+4), new PVector( rx, ry ), wx, wy))   
      py = py + 4;
  }
  if (keyPressed == true && key == 'w' || key == 'W') {
    if (!collision1(new PVector(px, py-pWidthHalf-4), new PVector( rx, ry ), wx, wy))
      py = py - 4;
  }
}

// -------------------------------------------------------------------------------------------------
// the math functions 

boolean collision1 (PVector p1, PVector square, 
  float widthSquare, float  heightSquare) {
  // This is used when moving the player against the box. 
  // This will evaluate to true if that point p1 is in the square "square".
  return p1.x > square.x && 
    p1.x < square.x + widthSquare && 
    p1.y > square.y && 
    p1.y < square.y + heightSquare;
}

PVector check_intersect(Boundary a, Boundary b) {
  // This checks laser against rect. 

  float a1 = a.y2 - a.y1; 
  float b1 = a.x1 - a.x2; 
  float c1 = a1 * a.x1 + b1 * a.y1; 
  float a2 = b.y2 - b.y1; 
  float b2 = b.x1 - b.x2; 
  float c2 = a2 * b.x1 + b2 * b.y1; 
  float denom = a1 * b2 - a2 * b1; 

  // leave when both lines a and b are the same 
  if ((a.x1==b.x1&&a.x2==b.x2) &&
    (a.y1==b.y1&&a.y2==b.y2)) {
    return null;
  } 

  Float X = (b2 * c1 - b1 * c2) / denom; 
  Float Y = (a1 * c2 - a2 * c1) / denom; 

  PVector p = new PVector(X, Y); 
  boolean Linea = a.compare(p); 
  boolean Lineb = b.compare(p);

  // if (p is inside both)  
  if  ( Linea && Lineb ) {  
    return p; // return PVector
  }// if 

  // No match found  
  return null; // return null
  //
}//func 

// ===================================================================

class Boundary {

  // I am a line

  float x1, y1, 
    x2, y2; 

  // constr
  Boundary ( float x1_, float y1_, 
    float x2_, float y2_ ) {
    x1=x1_; 
    y1=y1_; 

    x2=x2_; 
    y2=y2_;
  }// constr

  /*
  void display() {
   stroke(0, 0, 255);
   line(x1, y1, 
   x2, y2);
   }//method
   */

  boolean compare(PVector p) {
    // This returns true when p is inside the boundary  
    return
      ((p.x<x1&&p.x>x2)||
      (p.x>x1&&p.x<x2)) || 
      ((p.y<y1&&p.y>y2)||
      (p.y>y1&&p.y<y2));
  }//method 
  //
}//class
//
2 Likes