1

I started learning java just over a year ago so i'm still fairly new.

I'm trying to make an object travel from one point to another at a constant net velocity no matter where the second point is in the frame. Currently it's working fairly well as long as I run the method every few frames.

The only problem is that it it will only move horizontally unless the second point is approximately between 45 and 135 degrees or between 225 and 315 degrees (1/2π and 3/2π or 5/2π and 7/2π).

It may be because of the 'if' statements meant to stop it from dividing by 0 but it doesn't seem like it. Also if there is any way to simplify those equations or remove 'if' statements I wouldn't mind some advice there too.

Note: vel is the net velocity the objects travel at and Prime.mx and Prime.my is the location of the target point.

public void target()
{ 
 if (Prime.mx > x)
 {
   if (Math.abs(x-Prime.mx) != 0)
     x = Math.round(Math.round((x + (vel*Math.cos(Math.atan(Math.abs(y-Prime.my)/Math.abs(x-Prime.mx)))))));
 }
 if (Prime.mx < x)
 {
   if (Math.abs(x-Prime.mx) != 0)
     x = Math.round(Math.round((x - (vel*Math.cos(Math.atan(Math.abs(y-Prime.my)/Math.abs(x-Prime.mx)))))));
 }
 if (Prime.my > y)
 {
   if (Math.abs(x-Prime.mx) != 0)
     y = Math.round(Math.round((y + (vel*Math.sin(Math.atan(Math.abs(y-Prime.my)/Math.abs(x-Prime.mx)))))));
 }
 if (Prime.my < y)
 {
   if (Math.abs(x-Prime.mx) != 0)
     y = Math.round(Math.round((y - (vel*Math.sin(Math.atan(Math.abs(y-Prime.my)/Math.abs(x-Prime.mx)))))));
 }
}

I use Math.round twice because the first brings it to a float from a double and the second makes it an int. I need the x and y as ints so the paint method can draw the objects.

I found a few simillar problems on the site but the closest one was in python and and the anwer didn't seem applicable to my problem.

  • 4
    You can eliminate most of the quadrant-checking logic (`if` statements and `Math.abs()` calls) by using `Math.atan2(delta_y, delta_x)` instead of `Math.atan()`. Also, be sure to calculate all the intermediate results in floating point, and only convert to integers at the very end of the process. – Jim Lewis Feb 04 '15 at 01:05
  • Given two points, you could use something like [this](http://stackoverflow.com/questions/22930952/java-graphics-draw-a-line-using-fillrect/22931106#22931106) to calculate the position along the line between over a given period of time (0 to 1). If you have a point, angel and distance (radius), you can use something like [this](http://stackoverflow.com/questions/25923480/simple-circle-rotation-simulate-motion/25923780#25923780) to calculate the second point and then apply the first example – MadProgrammer Feb 04 '15 at 01:06

2 Answers2

1

More than solution these are some advices.

First, implement all you coordinate variables as floats to prevent rounding precision loss errors and round only right before painting.

Second, define float dx = Prime.mx - x; float dy = Prime.my - y; distance to target from current point (to use later). I would use Math.atan2(dy,dx) to compute angle between current point and target. Then use that angle to increment coordinates like this:

x += Math.cos(angle)*vel;
y += Math.sin(angle)*vel;

Third, check if your object is at target using (dx*dx + dy*dy <= radius*radius) for suitable radius (can be 1).

Also note that if the y axis goes down, then the angle will be CW (clock-wise) instead of CCW (counter-clock-wise).

kajacx
  • 12,361
  • 5
  • 43
  • 70
1

I believe you are overcomplicating this. If your starting point is (sx, sy) and your destination is (dx, dy) then you can easily calculate any point (x, y) that is p distance along the line (0.0 <= p <= 1.0). You can use this to move at velocity v. So I suggest finding your end point and then using simple arithmetic to move on the x and y axis.

float dx = dist * Math.cos(angle);
float dy = dist * Math.sin(angle);
for (float p = 0.0; p <= 1.0; p = Math.min(1.0, p + dist / v) {
    x = sx + p * (dx - sx);
    y = sy + p * (dy - sy);
}

The Math.min expression in the for loop ensures that you end up exactly at the destination point.

If you already have the destination point then it's just as easy. Instead of finding dx and dy from dist and angle you find dist from dx and dy using pythagoras.

sprinter
  • 27,148
  • 6
  • 47
  • 78