# moving a square in a specified direction

• 03-13-2011, 04:44 AM
totj
moving a square in a specified direction
Alright, pretty simple concept but has been a challenge to code...

i have a square with (sx,sy), and the mouse can click(mx,my) anywhere on the screen. then, by subtracting the mouse's position by the squares position, it moves. Here's where the problem occurs - the further away you click from the square the bigger the velocity will be, and the faster it moves. I want one smooth speed.

i tried implementing Euclid's algorithm to find the gcd of the velocity and dividing it, but not all fractions divide, and if the gcd is negative it divides both by a negative number and flips the direction.

is my way completely wrong, is there an easier way, a different way, or a way to fix this?

Code:

```import java.applet.Applet; import java.awt.Graphics; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; public class Main extends Applet implements Runnable,MouseListener{         private static final long serialVersionUID = 1L;         int sx = 20; //square x         int sy = 20;         int mx;    //mouse x         int my;         boolean flag = false; //has mouse been clicked?         long vx;  //velocity of x         long vy;                 public void init(){                 setSize(400,300);                 addMouseListener(this);         }         public void start(){                 Thread th = new Thread(this);                 th.start ();         }         public void run(){                 Thread.currentThread().setPriority(Thread.MIN_PRIORITY);                                while(true){                                                        repaint();                                                 if((sx < 400 && sy < 300) && (flag == true)){ //is it on the screen?                                 moveSquare();                         }                                                 try{                                 Thread.sleep(20);                         }catch (InterruptedException ex){}                         Thread.currentThread().setPriority(Thread.MAX_PRIORITY);                 }         }         public void paint(Graphics g){                 g.fillRect(sx, sy, 10, 10);         }         public void mouseClicked(MouseEvent e){                 flag = true;                 mx = e.getX();                 my = e.getY();                                 vx = mx - sx;                 vy = my - sy;                                 int divisor = (int) gcd(vx,vy);                 vx = vx / divisor;                 vy = vy / divisor;         }         public void moveSquare(){                 double speed = 0.1; //just slows it down a bit                 sx += vx * speed;                 sy += vy * speed;         }         public static long gcd(long a, long b) {                   if (b==0)                     return a;                   else                     return gcd(b, a % b);         }                 public void mouseEntered(MouseEvent arg0){}         public void mouseExited(MouseEvent arg0){}         public void mousePressed(MouseEvent arg0){}         public void mouseReleased(MouseEvent arg0){} }```
• 03-13-2011, 05:05 AM
pbrockway2
Subtracting the positions sounds right to me.

You should then normalise the vector that results ie divide both its x- and y-components by (x^2+y^2)^0.5 (ie the length of the vector). You can achieve a speed independent of the initial size of the vector by adding an increasing multiple of this normalised vector every 20ms. This approach presupposes that the square's location is known in terms of doubles and only rounded to ints when the square is painted.

As an alternative, the normalised vector could, itself, be rounded to whole number of pixels in the x- and y- directions. Then this value could be added to the square's position every 20ms. This would yield a speed that was "almost" independent of the initial mouse-square distance.
• 03-13-2011, 04:15 PM
ozzyman
the reason the speed varies is because you are subtracting a Position rather than a Speed
i.e. the greater the position => the greater the subtraction => the greater the speed

you need to define an integer "Speed" and set it to say '1' (1 pixel); then run a loop e.g.

while the mousePos - squarePos doesn't equal 0:
subtract the SPEED (e.g. -1 px per loop)
delay the time (e.g. 1 second)

so that it subtraxts 1 pixel per second for example to get the speed you want
• 03-14-2011, 03:16 AM
totj
Quote:

Originally Posted by ozzyman
while the mousePos - squarePos doesn't equal 0:
subtract the SPEED (e.g. -1 px per loop)
delay the time (e.g. 1 second)

so that it subtraxts 1 pixel per second for example to get the speed you want

but the x and y are different amounts, this would move to the closest x or y, and then continue in a line until it reaches the other.

Quote:

Originally Posted by pbrockway2
Subtracting the positions sounds right to me.

You should then normalise the vector that results ie divide both its x- and y-components by (x^2+y^2)^0.5 (ie the length of the vector). You can achieve a speed independent of the initial size of the vector by adding an increasing multiple of this normalised vector every 20ms. This approach presupposes that the square's location is known in terms of doubles and only rounded to ints when the square is painted.

As an alternative, the normalised vector could, itself, be rounded to whole number of pixels in the x- and y- directions. Then this value could be added to the square's position every 20ms. This would yield a speed that was "almost" independent of the initial mouse-square distance.

i normalized it (and rounded the vector itself to int), but i dont get what you mean by adding an increasing multiple every time it repaints (20ms).
• 03-14-2011, 03:29 AM
ozzyman
oh thats true, i forgot that you need both a horizontal speed and a vertical speed

for example.
start pos = x=50 y=75
end pos = 0,0
to reach both at the same time speed y needs to be faster than speed x by the calculation of 75/50 = 1.5*speed x

so over time this will happen
set speed x to 5 pixels, delay 200ms
speed y = 5*1.5 = 7.5 pixels
0.0 secs --- pos x=50; y=75
0.2 secs --- pos x=45; y=67.5
0.4 secs --- pos x=40; y=60
0.6 secs --- pos x=35; y=52.5
0.8 secs --- pos x=30; y=45
1 secs ----- pos x=25; y=37.5
2 secs ----- pos x=0; y=0
• 03-14-2011, 11:30 AM
pbrockway2
Quote:

i normalized it (and rounded the vector itself to int), but i dont get what you mean by adding an increasing multiple every time it repaints (20ms).

If you have rounded it to int values then you can just keep adding that vector every 20ms as you were doing originally.

Note that you may find that simply rounding it makes it a zero vector! In that case multiply both components by some convenient factor like 1000 before you round.
• 03-14-2011, 11:10 PM
totj
Quote:

Note that you may find that simply rounding it makes it a zero vector! In that case multiply both components by some convenient factor like 1000 before you round.
well, when i do that and then normalize the vector its always going to be 0 as well.
Code:

```int vectLength = (int) Math.pow((vx*vx+vy*vy), 0.5) * 1000; vx = vx / vectLength; vy = vy / vectLength;```
dividing by a gigantic number is going to yield 0.

Quote:

to reach both at the same time speed y needs to be faster than speed x by the calculation of 75/50 = 1.5*speed x
i tried that but it still only goes to the closest line.. the only new code is
Code:

```if(sx > sy){         speedx = (sx*10 / sy*10) / 100.0;         speedy = 1; } if(sy > sx){         speedy = (sy*10 / sx*10) / 100.0;         speedx = 1; }```
and later on in the method moveSquare{}
Code:

```if(mx - sx > 0)         vx = 1; if(mx - sx < 0)         vx = -1; if(my - sy > 0)         vy = 1; if(my - sy < 0)         vy = -1;```
in case it needs to go backwards in any direction. this would be what you said is the speed, instead of 5 pixels i did 1.

sorry for taking up so much of your guys' time...i feel like this is a very simple PEBCAK error to both of these solutions that i just cant see.
• 03-15-2011, 01:12 AM
pbrockway2
I meant something like

Code:

```double vectLength =  Math.pow((vx*vx+vy*vy), 0.5); vx = (1000 * vx) / vectLength; vy = (1000 * vy) / vectLength;```

Are you trying to move from one position to another at speed independent of travel distance? Because your original code didn't do that.
• 03-15-2011, 01:49 AM
totj
now its just throwing it off the screen. i think im missing the big picture to all of this.. i can try to implement what your saying but i dont know if i can do it correctly without understanding of what its doing and why its doing it that way.

im trying to get it to move in one direction, whether its from point to point, or just in that direction until it goes off the screen. id prefer the latter, but it doesnt really matter.
• 03-15-2011, 07:39 AM
pbrockway2
This is basically your code - it might be easier to see the algebra this way...

Code:

```import java.applet.Applet; import java.awt.Graphics; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; public class Main extends Applet implements Runnable,MouseListener{         private static final long serialVersionUID = 1L;         int sx = 20; //square x         int sy = 20;         int mx;    //mouse x         int my;         boolean flag = false; //has mouse been clicked?         [color=blue]double vx;  // velocity (the step size)         double vy;[/color]                 public void init(){                 setSize(400,300);                 addMouseListener(this);         }         public void start(){                 Thread th = new Thread(this);                 th.start ();         }         public void run(){                 Thread.currentThread().setPriority(Thread.MIN_PRIORITY);                                while(true){                                                        repaint();                                                 if((sx < 400 && sy < 300) && (flag == true)){ //is it on the screen?                                 moveSquare();                         }                                                 try{                                 Thread.sleep(20);                         }catch (InterruptedException ex){}                         Thread.currentThread().setPriority(Thread.MAX_PRIORITY);                 }         }         public void paint(Graphics g){                 g.fillRect(sx, sy, 10, 10);         }         public void mouseClicked(MouseEvent e){                 flag = true;                 mx = e.getX();                 my = e.getY();                                         // first make (vx,vy) the vector the square will travel                 vx = mx - sx;                 vy = my - sy;                                     [color=blue]// next scale the vector so that its length is one unit                     // only the direction matters                 double scale = Math.sqrt(vx * vx + vy * vy);                 vx /= scale;                 vy /= scale;                                 System.out.printf("mouseClicked(): step size = %f,%f%n", vx, vy);[/color]         }         public void moveSquare(){                 [color=blue]double speed = 5;[/color]                 sx += vx * speed;                 sy += vy * speed;         }                 public void mouseEntered(MouseEvent arg0){}         public void mouseExited(MouseEvent arg0){}         public void mousePressed(MouseEvent arg0){}         public void mouseReleased(MouseEvent arg0){} }```
I chose to make vx and vy doubles so that the speed vector could be accurately represented. (Check out the values that are printed to the console.)

One thing you may notice is that the "errors" build up in an expression like "sx+=vx*speed". You might want to consider how easy it would be to make sx and sy doubles as well.
• 03-15-2011, 08:22 PM
totj
oh my holy jesus, a million thank you's. works perfectly :)
• 03-15-2011, 09:17 PM
ozzyman
pbrock, i understand this calculation gets the length of the hypotenuse of the triange, which is the path the square must travel along...
Code:

`double scale = Math.sqrt(vx * vx + vy * vy);`
but what does the next part do to it to derive a uniform speed?
Code:

```vx /= scale; vy /= scale; double speed = 5; sx += vx * speed; sy += vy * speed;```
• 03-15-2011, 09:31 PM
JosAH
Quote:

Originally Posted by ozzyman
pbrock, i understand this calculation gets the length of the hypotenuse of the triange, which is the path the square must travel along...
Code:

`double scale = Math.sqrt(vx * vx + vy * vy);`
but what does the next part do to it to derive a uniform speed?
Code:

```vx /= scale; vy /= scale; double speed = 5; sx += vx * speed; sy += vy * speed;```

The first two lines turn the vector (vx, vy) into a unit vector. The last two lines add that unit vector to a point (sx, sy) multiplied by a factor 'speed'. So the point (sx, sy) follows the (straight line) trajectory along the vector (vx, vy).

kind regards,

Jos
• 03-15-2011, 09:33 PM
ozzyman
Thanks a lot Jos! Now i understand it completely. It was the unit vector i couldn't figure out, but I think we learnt about unit vectors at one point back at college Maths
• 03-15-2011, 09:42 PM
JosAH
Quote:

Originally Posted by ozzyman
Thanks a lot Jos! Now i understand it completely. It was the unit vector i couldn't figure out, but I think we learnt about unit vectors at one point back at college Maths

A unit vector is just a vector with length 1, so for any vector v not equal to (0, 0), v/|v| is a unit vector.

kind regards,

Jos
• 03-16-2011, 12:26 AM
pbrockway2
Quote:

a million thank you's. works perfectly
You're welcome.