This site requires JavaScript, please enable it in your browser!
Greenfoot back
darkmist255
darkmist255 wrote ...

2012/11/6

Line of sight help

darkmist255 darkmist255

2012/11/6

#
I'm trying to make a boolean method that will return true if actor 1 can see actor 2 (no obstacles between them). My approach was to get x1 and y1 of actor 1, and x2 and y2 of actor 2. Once I have those, calculate the linear equation, then just do a for() loop from x1 through x2, checking for obstacles each time. One major problem though, for some reason I seem incapable of calculating a linear equation via code. Here are two attempts I made: Firstly with Slope-Intercept form: y = mx + b
1
2
3
4
5
6
7
8
9
double yDiff = y2 - y1;
double xDiff = x2 - x1; if(xDiff == 0) xDiff = xDiff + 0.000001; //assures it will not be 0
double m = yDiff/xDiff;
double b = y2 - (m * x2);
for(int x = Math.min((int)x2, (int)x1); x < Math.max((int)x2, (int)x1); x++)
{
    int y = (int)((m * x) + b);
//then the check for obstacles at (x, y)
}
Then again with Two-Point form: y - y1 = ((y2 - y1)/(x2 - x1)) * (x - x1)
1
2
3
4
5
for(int x = Math.min((int)x2, (int)x1); x < Math.max((int)x2, (int)x1); x++)
{
    int y = (int) ((((y2 - y1)/(x2 - x1)) * (x - x1)) + y1);
//then the check for obstacles at (x, y)
|
All seems fine to me, but if I use System.out.println() to check the values, I end up with nowhere near what I expect. I've even tried just entering test coordinates on a graphing calculator and I end up with a graph far off from the original coordinates. Any idea what's going on? Any help is appreciated.
danpost danpost

2012/11/6

#
In line 7, try casting 'x' to a 'double' and see if you do not get different results.
darkmist255 darkmist255

2012/11/6

#
1
2
3
int y = (int)((m * (double)x) + b);
int yy = (int)((m * x) + b);
if(y != yy) System.out.println(y + " " + y2);
It never printed any values after a good 20 seconds, so I'm assuming that's not the problem. Also, this problem happens even if I go through these with pen and paper, even though I don't see anything wrong with them.
danpost danpost

2012/11/6

#
I would probably do something a little silly (but it would work). Create a new class called LineOfSight:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// in actor1 class
int x = (getX() + actor2.getX()) / 2;
int y = (getY() + actor2.getY()) / 2;
int yDiff = actor2.getY() - getY();
int xDiff = actor2.getX() - getX();
int slope = (int) (Math.round(Math.atan2(yDiff, xDiff) * 180.0 / Math.PI));
int length = (int) Math.hypot(yDiff, xDiff);
LineOfSight los = new LineOfSight(length, slope);
getWorld().addObject(los, x, y);
if (los.isSightClear())
{
    // what to do when no intersectors
}
// for the LineOfSight class
import greenfoot.*;
 
public class LineOfSight extends Actor
{
    public LineOfSight(int length, int slope)
    {
        setImage(new GreenfootImage('narrow dimension', length));
        setRotation(slope);
    }
 
    public boolean isSightClear()
    {
        int objCt = getIntersectingObjects(null).size();
        getWorld().removeObject(this);
        return objCt == 2;
    }
}
The LOS (LineOfSight) object removes itself when you get the 'sight clear state'. The two objects it WILL intersect are actor1 and actor2. If there are more, it will return 'false'. The length is, of course given; however, the 'narrow dimension' can be adjusted to the size of whatever is to pass between the two objects.
darkmist255 darkmist255

2012/11/6

#
If I can't figure out the problem with my current method that definitely sounds like a decent alternative!
danpost danpost

2012/11/6

#
A problem you might come across with your method is: what happens when one object is nearly directly above another? By iterating x, you might get a few points in between, but the majority of them will be skipped over. You probably would have to do something like: if the slope is between -1 and 1, interate the x; else, iterate the y.
danpost danpost

2012/11/6

#
I did sort of the same kind of thing in my Pendulum Demo scenario. I created a 'Drop' object, which was placed at the ceiling plate of the pendulum. In its constructor, it got the length and angle of the pendulum, relocated itself down to the ball of the pendulum; then, its y-coordinate was adjusted to the marker bar. There, it would create a mark on the world background and remove itself. One drop is created each act cycle that the pendulum is not being manually adjusted on. I did not look to double check if that was exactly the way I did it; but, it was something like that.
darkmist255 darkmist255

2012/11/6

#
Finally! Okay I got it working by modifying the formula slightly (still don't know why it didn't work before).
1
2
double m = yDiff/xDiff;
int y = (int) ((m * (x - x1)) + y1);
Next step I think I'll iterate y as well, that's a good point.
danpost danpost

2012/11/6

#
As far as my Pendulum Demo scenario, I checked. I did do a few things differently than explained above. First, the moving down the line to the ball and dropping to the marker bar was done in the act() method. Second, I did not have it mark the background image; but, instead, had 'Page' objects (like sheets of paper) which scrolled up the screen being sent the location to mark before the Drop object removed itself. For any point (x, y) and slope m, another point can be arrived at, by setting a new x (x2) and solving for y (y2), using y2 = y + m * (x2 - x) The y-intercepts cancel out from one point to another. The proof follows y = m * x + b // the point-slope formula y1 = m * x1 + b // one point on the line y2 = m * x2 + b // a second point on the line // subtracting the first from the second y2 - y1 = ( m * x2 + b ) - ( m * x1 + b) y2 - y1 = m * x2 + b - m * x1 - b // removing parantheses y2 - y1 = m * x2 - m * x1 + b - b // communicative property ('b's cancel) y2 - y1 = m * (x2 - x1) // simplifying and combining y2 = m * (x2 - x1) + y1 // adding 'y1' to both sides This is precisely what you ended up with (only, you subtracted the second line above from the first)
Lordkallad Lordkallad

2016/1/26

#
Hi By testing Danpost's code I got an error, saying that isSightClear method was non-static and could not be refered from a static context. How can i fix that ?
danpost danpost

2016/1/26

#
Lordkallad wrote...
By testing Danpost's code I got an error, saying that isSightClear method was non-static and could not be refered from a static context. How can i fix that ?
Please note that the snippet of code above calls the 'isSightClear' method on an object created from the LineOfSight class and not calling the method on the class itself.
Lordkallad Lordkallad

2016/2/11

#
Ok, I fixed my problem. It works fine until i get at a medium range. When the two actors move to each other, at one point the VisLine does a turn, rotating of 180 degrees. Do you have a solution ?
danpost danpost

2016/2/11

#
Normally, once the code for creating a line of sight and being able to determine whether any object obstructs it is completed, the image of the line of sight object would be made transparent. So there is nothing within the code given to act upon the line being upside down or not. This you will have to do yourself. Also, it would be better for both actors be passed to the line of sight object and have the line of sight object do the calculations. By doing so, it would be easy to have your actor determine which actor, it or the one creating a line of sight to, to pass as which argument to the line of sight constructor (maybe always passing the actor to the left first every time).
You need to login to post a reply.