aspose file tools*
The moose likes Game Development and the fly likes How do I make a point travel in straight line? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Spring in Action this week in the Spring forum!
JavaRanch » Java Forums » Java » Game Development
Bookmark "How do I make a point travel in straight line?" Watch "How do I make a point travel in straight line?" New topic
Author

How do I make a point travel in straight line?

Unnar Björnsson
Ranch Hand

Joined: Apr 30, 2005
Posts: 164
I�ll start by displaying the variables:

xPool = 0;
yPool = 0;
missileX = (selected.getX()+((selected.getIcon().getIconWidth())/2));
missileY = (selected.getY()+((selected.getIcon().getIconHeight())/2));
abX = e.getX()-(selected.getX()+((selected.getIcon().getIconWidth())/2));
abY = e.getY()-(selected.getY()+((selected.getIcon().getIconHeight())/2));
abXY = Math.sqrt(Math.pow(abX, 2) + Math.pow(abY, 2));


e is a mouseEvent i.e where I clicked the mouse on the board.
selected is the currently selected unit(a class I made for unit that can move, turn etc.)
xPool and yPool are stacks of x and y values. Lets say if x=0.4 the first x would be +0 pixel the next x (x=0.8) would also be +0 pixel the third (x=1.2) would be +1 pixel. The stack is floored to the next integer so the error is never more than 1 pixel.
abX, abY and abXY are the distances i.e abX is the x-distance from source to target, abY y-distance and abXY the 2-dimensional distance(a�+b�=c�).

I have tried few solutions, the most obvious one is the mathematical form, but the point misses it�s target because in math there are 1/2 X�s and 1/3 Y�s but there is no 1/2 or 1/3 pixel.
So I tried another solution. I stacked the x�s and y�s so the error were at worst 1 pixel. Then I made an array of all the points:

misTrail = new Point[((int)abXY/5)+1];
for(int i=0; i<misTrail.length; i++)
{
xPool += abX/(abXY/5);
yPool += abY/(abXY/5);
misTrail[i] = new Point((int)(selected.getX()+xPool),
(int)(selected.getY()+yPool));

}


Every timeunit the painted point is repainted to misTrail[i] and i incremented. This almost works, the point still slightly misses it�s target. Why is that? Is there a better way to accomplish this?
I hope I didn�t make it too difficult to understand. In short I want a point or ball to shoot from a source to the point I clicked and I want the number of it�s appearances to reflect the distance it travels i.e it doesn�t go faster when close to 90� angle.
Layne Lund
Ranch Hand

Joined: Dec 06, 2001
Posts: 3061
I think the problem might be from the calculations in your loop such as

You caim that your round off error is within 1 pixel, but I think you have failed to realize that it is off by at most 1 pixel EACH TIME through the loop. So if the loop iterates twenty times, you might be off by as much as 20 pixels in the end. I suggest that you calculate the xPool each time from the initial position, rather than incrementing from the "current position". Perhaps something like this will fix the problem:

I have only showed the calculation for xPool. You can do the same thing for yPool.

I hope this answers your question. I also have some additional comments on your code. If I understand your code correctly, you are calculating two values (i.e. abX/(abXY/5) and abY/(abXY/5)) over and over again in the for loop, but the result is always going to be the same each time. You can optimize this slightly by calculating this once before the loop starts:

I don't know how much of a difference this will make, but it becomes more obvious that you are using some physics (and even trigonometry here). If you study up on these two subjects, you will probably find some ways to use the mathematics involved to make your code much simpler. It will also make it easier for other programmers to read, at least if they are familiar with the same concepts.

Specificially, there are a couple of equations that are helpful from physics that you can use here (and you are in fact using them, although they are disguised:

x = x0 + vx*t
y = y0 + vy*t
vx = v * sin(theta)
vy = v * cos(theta)

where

t is the amount of time (usually measured from some determined start time)
(x, y) is the position of the particle at time t
v is the velocity of the particle
vx is the x-component of the velocity
vy is the y-component of the velocity
x0 is the initial position of the particle
y0 is the initial position of the particle
theta is the angle that describes the direction that the particle is moving

Interestingly, you are already using all of these. I don't know if that is on purpose or not. If not, I strongly encourage you to look into this further. I think it will help you understand a lot of the mathematics you use in writing games.

Regards,

Layne

[ July 14, 2005: Message edited by: Layne Lund ]
[ July 14, 2005: Message edited by: Layne Lund ]

Java API Documentation
The Java Tutorial
Unnar Björnsson
Ranch Hand

Joined: Apr 30, 2005
Posts: 164
Yeah! I solved it I did it like this:

missileX = (selected.getX()+((selected.getIcon().getIconWidth())/2));
missileY = (selected.getY()+((selected.getIcon().getIconHeight())/2));
xPool = missileX;
yPool = missileY;
abX = e.getX()-(selected.getX()+((selected.getIcon().getIconWidth())/2));
abY = e.getY()-(selected.getY()+((selected.getIcon().getIconHeight())/2));
abXY = Math.sqrt(Math.pow(abX, 2) + Math.pow(abY, 2));
if((Math.abs(abY)/Math.abs(abX)) >= 1)
{
y = 8*(abY/Math.abs(abY));
x = y/(abY/abX);
}
else
{
x = 8*(abX/Math.abs(abX));
y = (abY/abX)*x;
}


If abX/abY was larger or equal to 1 Y would be forced to move 1 pixel at a time(though in this case 8 pixel to speed the travel time), if it was less then 1, X would be forced to move 1 pixel at a time, therefore the point moves exactly one pixel distance every time unit.

Thanks for your help anyway.
[ July 15, 2005: Message edited by: Unnar Bj�rnsson ]
John Dove
Greenhorn

Joined: Jul 16, 2005
Posts: 11
You could always use a parametric algorithm to "walk" through all the discrete pixel coordinates that exist in your line segment. The following sample code does this:

-------------------------
package simulation.math;

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// top-level public class
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/**
* an instance of this class lets a user "walk" through all the integer (x,y)
* points that comprise a line segment.
*
* @author John Dove scjp,scjd 2005
*/
public class ParametricLineStep
{
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// fields
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

/**
* the target line whose coordinates must be "walked" through, and
* returned to the user.
*/
private Line m_line;

/**
* the last point that was parsed from the line.
*/
private Point m_lastPointReturned;

/**
* flag indicating if the entire line has been parsed.
*/
private boolean m_lineParsed;

/**
* the percentage to increment the "step percent increment" by, which dictates
* where on the line the parse is currently at.
*/
private double m_stepPercentIncrement;

/**
* dictates where on the line the parse is currently at.
*/
private double m_stepPercent;

/**
* the x-value of the starting point for parametrically parsing the line.
*/
private int m_startPointX;

/**
* the y-value of the starting point for parametrically parsing the line.
*/
private int m_startPointY;

/**
* the remaining x-axis length that the start point will need to grow by,
* in order to completely parse the line.
*/
private int m_remainingLengthX;

/**
* the remaining y-axis length that the start point will need to grow by,
* in order to completely parse the line.
*/
private int m_remainingLengthY;

//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// methods
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
/**
* creates an empty instance that is not parsing a line yet.
*/
public ParametricLineStep()
{
m_line = null;
m_lastPointReturned = new Point();
}

/**
* resets the line parse to the beginning of the line.
*/
public void rewind()
{
m_stepPercent = 0.0;
m_lineParsed = false;
}

/**
* sets the line to parse to the supplied line.
*
* @param line the supplied line to parse.
*/
public void setLine(Line line)
{
// save the line
m_line = line;
rewind();

// determine the line length
double lineLength = 0;

// if the line is parallel to the x-axis
if (m_line.m_p1.m_y == m_line.m_p2.m_y)
{
lineLength = Math.abs(m_line.m_p1.m_x - m_line.m_p2.m_x) + 1;
}
// else if the line is parallel to the y-axis
else if (m_line.m_p1.m_x == m_line.m_p2.m_x)
{
lineLength = Math.abs(m_line.m_p1.m_y - m_line.m_p2.m_y) + 1;
}
// else, if the line is NOT parallel to either axis, we the use pythagorean
// theorem to compute the line length
else
{
// first get the distance in points (i.e. discrete pixels) between the
// x and y ordinates. +1 is used to ensure that we get an accurate point
// count inclusive of the endpoints themselves. For example, 5-2 = 3,
// but between 2 and 5 *inclusive* there are actually 4 points.
int xDifference = Math.abs(m_line.m_p1.m_x-m_line.m_p2.m_x) + 1;
int yDifference = Math.abs(m_line.m_p1.m_y-m_line.m_p2.m_y) + 1;
lineLength = Math.sqrt(xDifference*xDifference + yDifference*yDifference);
}

// determine the step percent increment, which is equal to the "percentage"
// of the line that *half* a pixel is equal to
m_stepPercentIncrement = 0.5/lineLength;

// determine the starting point for parametrically parsing the line
m_startPointX = line.m_p1.m_x;
m_startPointY = line.m_p1.m_y;

// determine the remaining lengths in BOTH the x and y directions
// that the start point will need to grow by, in order to completely
// parse the line. +1 is NOT needed, as we have a startX/YPoint
m_remainingLengthX = line.m_p2.m_x - line.m_p1.m_x;
m_remainingLengthY = line.m_p2.m_y - line.m_p1.m_y;
}

/**
* returns the next point on the line, else null if no more points remain.
* This method will always return the SAME object reference, however, the
* values will be changed to be that of the next point (x,y).
*
* @return the next point on the line, else null if no more points remain.
*/
public Point getNextPoint()
{
// assume no more points exist, so set return value to null
Point returnValue = null;

// if the line has NOT been completely parsed yet
if (!m_lineParsed)
{
// while the next point has not been determined and the step percent is
// less than 1.0; i.e. this check does NOT cover the 1.0 step percent,
// instead, the 1.0 step percent is covered outside the while loop (below)
// as a special case
while(m_stepPercent <= 1.0)
{
// get the next point
int nextPointX = m_startPointX + (int)Math.round(m_stepPercent * m_remainingLengthX);
int nextPointY = m_startPointY + (int)Math.round(m_stepPercent * m_remainingLengthY);

// if this is the FIRST point to be parsed, return it
if (m_stepPercent == 0.0)
{
m_lastPointReturned.m_x = nextPointX;
m_lastPointReturned.m_y = nextPointY;
returnValue = m_lastPointReturned;
break;
}
// else, if this is the 2ND+ point to be parsed, such that it is NOT
// equal to the last point parsed, return it
else if (!m_lastPointReturned.equals(nextPointX,nextPointY))
{
m_lastPointReturned.m_x = nextPointX;
m_lastPointReturned.m_y = nextPointY;
returnValue = m_lastPointReturned;
break;
}

// increment the step percent and try again. If continually repeated,
// this will eventually cause the while loop to exit without ever
// finding a return point
m_stepPercent = m_stepPercent + m_stepPercentIncrement;
}

//----------------------------------------------------------------------
// SPECIAL CASE: step percent >= 1.0
//----------------------------------------------------------------------
// if the while loop (above) exited WITHOUT finding a return Point, it
// means the step percent must be >= 1.0. In this special case, we will
// attempt to return the other endpoint of the line, if and only if it
// has NOT already been returned in a prior call to this method
//----------------------------------------------------------------------
if (returnValue == null)
{
// in any case, the line will be considered fully parsed after this
// code block executes
m_lineParsed = true;

// get the next point
int nextPointX = m_line.m_p2.m_x;
int nextPointY = m_line.m_p2.m_y;

// if this final point differs from the last that was returned from this
// method, use it as the return value
if (!m_lastPointReturned.equals(nextPointX,nextPointY))
{
m_lastPointReturned.m_x = nextPointX;
m_lastPointReturned.m_y = nextPointY;
returnValue = m_lastPointReturned;
}
}
// else, the while loop exited because the next point was FOUND, which also
// means that the step percent is still LESS THAN 1.0. In this case we
// simply increment the step percent for the NEXT call to this method
else
{
m_stepPercent = m_stepPercent + m_stepPercentIncrement;
}
}

// returns the next point on the line, else null if no more points exist
return returnValue;
}
}


Regards,<br />John Dove<br />john_dove@mapinfo.com<br /><a href="http://home.nycap.rr.com/jdove" target="_blank" rel="nofollow">http://home.nycap.rr.com/jdove</a>
Layne Lund
Ranch Hand

Joined: Dec 06, 2001
Posts: 3061
John,

Would you please go back and edit your above post by adding UBB CODE tags? UBB works a lot like HTML and the CODE tags will preserve your formatting so that we can read your code more easily.

Thanks

Layne
John Dove
Greenhorn

Joined: Jul 16, 2005
Posts: 11
>>> UBB works a lot like HTML and the CODE
>>> tags will preserve your formatting so that we
>>> can read your code more easily.

I did not know that UBB existed. :-) So it's just a variant of markup language that is used in forums then? Is it an industry standard, xor is it proprietary unto each forum that "offers" its usage?


>>> Would you please go back and edit your above
>>> post by adding UBB CODE tags?

Sure - will do. Gotta go to work right now, however, I will try and do this editing at work.


Regards,
John Dove
johndove_123@hotmail.com
john_dove@mapinfo.com
http://home.nycap.rr.com/jdove






Thanks

Layne
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
 
subject: How do I make a point travel in straight line?