Line of sight
back
Source
/* @pjs preload="player.png"; */
PImage player;
int NUMBER_OF_WALLS = 4;
int NUMBER_OF_PEOPLE = 6;
PVector[] people;
Rectangle[] walls;
// Setup the example
void setup(){
size(640, 480);
imageMode(CENTER);
player = loadImage("player.png");
walls = new Rectangle[NUMBER_OF_WALLS];
for(int i = 0; i < walls.length; i++){
int x = i * width / walls.length + 50;
int y = floor(random(50, height-200));
walls[i] = new Rectangle(x, y, 100, 100);
}
people = new PVector[NUMBER_OF_PEOPLE];
for(int i = 0; i < people.length; i++){
int x = floor(random(32, width-32));
int y = floor(random(32, height-32));
for(Rectangle wall : walls){
while(wall.overlap(x, y, player.width, player.height)){
y += 64;
}
}
people[i] = new PVector(x, y);
}
}
// The draw() method is called every frame
void draw(){
background(#4488cc);
PVector mV = new PVector(mouseX, mouseY);
for(Rectangle wall : walls){
wall.display();
}
for(PVector person : people){
PVector intersect = getWallIntersection(person, mV);
if(intersect != null){
tint(#ff0000);
}else{
noTint();
stroke(255);
line(person.x, person.y, mV.x, mV.y);
}
image(player, person.x, person.y);
}
ellipse(mV.x, mV.y, 32, 32);
}
PVector getWallIntersection(PVector start, PVector end){
float distanceToWall = MAX_FLOAT;
PVector closestIntersection = null;
for(Rectangle wall : walls){
PVector nw, ne, se, sw, intersect;
nw = new PVector(wall.x, wall.y);
ne = new PVector(wall.x + wall.width, wall.y);
sw = new PVector(wall.x, wall.y + wall.height);
se = new PVector(wall.x + wall.width, wall.y + wall.height);
/* top line */
intersect = intersectPLines(start, end, nw, ne);
if(intersect != null){
float distance = dist(start.x, start.y, intersect.x, intersect.y);
if(distance < distanceToWall){
distanceToWall = distance;
closestIntersection = intersect;
}
}
/* left line */
intersect = intersectPLines(start, end, nw, sw);
if(intersect != null){
float distance = dist(start.x, start.y, intersect.x, intersect.y);
if(distance < distanceToWall){
distanceToWall = distance;
closestIntersection = intersect;
}
}
/* right line */
intersect = intersectPLines(start, end, se, ne);
if(intersect != null){
float distance = dist(start.x, start.y, intersect.x, intersect.y);
if(distance < distanceToWall){
distanceToWall = distance;
closestIntersection = intersect;
}
}
/* bottom line */
intersect = intersectPLines(start, end, se, sw);
if(intersect != null){
float distance = dist(start.x, start.y, intersect.x, intersect.y);
if(distance < distanceToWall){
distanceToWall = distance;
closestIntersection = intersect;
}
}
}
return closestIntersection;
}
PVector intersectPLines(PVector v1start, PVector v1end, PVector v2start, PVector v2end){
return intersectLines(v1start.x, v1start.y, v1end.x, v1end.y, v2start.x, v2start.y, v2end.x, v2end.y);
}
/* From: http://processingjs.org/learning/custom/intersect/ */
PVector intersectLines(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4){
float a1, a2, b1, b2, c1, c2;
float r1, r2 , r3, r4;
float denom, offset, num;
PVector ret = null;
// Compute a1, b1, c1, where line joining points 1 and 2
// is "a1 x + b1 y + c1 = 0".
a1 = y2 - y1;
b1 = x1 - x2;
c1 = (x2 * y1) - (x1 * y2);
// Compute r3 and r4.
r3 = ((a1 * x3) + (b1 * y3) + c1);
r4 = ((a1 * x4) + (b1 * y4) + c1);
// Check signs of r3 and r4. If both point 3 and point 4 lie on
// same side of line 1, the line segments do not intersect.
if ((r3 != 0) && (r4 != 0) && same_sign(r3, r4)){
return null;
}
// Compute a2, b2, c2
a2 = y4 - y3;
b2 = x3 - x4;
c2 = (x4 * y3) - (x3 * y4);
// Compute r1 and r2
r1 = (a2 * x1) + (b2 * y1) + c2;
r2 = (a2 * x2) + (b2 * y2) + c2;
// Check signs of r1 and r2. If both point 1 and point 2 lie
// on same side of second line segment, the line segments do
// not intersect.
if ((r1 != 0) && (r2 != 0) && (same_sign(r1, r2))){
return null;
}
//Line segments intersect: compute intersection point.
denom = (a1 * b2) - (a2 * b1);
if (denom == 0) {
return null;
}
if (denom < 0){
offset = -denom / 2;
}
else {
offset = denom / 2 ;
}
// The denom/2 is to get rounding instead of truncating. It
// is added or subtracted to the numerator, depending upon the
// sign of the numerator.
num = (b1 * c2) - (b2 * c1);
ret = new PVector(0,0);
if (num < 0){
ret.x = (num - offset) / denom;
}
else {
ret.x = (num + offset) / denom;
}
num = (a2 * c1) - (a1 * c2);
if (num < 0){
ret.y = ( num - offset) / denom;
}
else {
ret.y = (num + offset) / denom;
}
// lines_intersect
return ret;
}
boolean same_sign(float a, float b){
return (( a * b) >= 0);
}
class Rectangle{
int x;
int y;
int width;
int height;
Rectangle(int x, int y, int width, int height){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
void display(){
noStroke();
rect(x, y, width, height);
}
boolean overlap(int otherX, int otherY, int otherWidth, int otherHeight){
return !(x + width < otherX || x > otherX+otherWidth || y + height < otherY || y > otherY+otherHeight);
}
}