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
//