# Thread: moving a square in a specified direction

1. Member
Join Date
Mar 2011
Posts
13
Rep Power
0

## 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?

Java 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);
}
public void start(){
th.start ();
}
public void run(){
while(true){

repaint();

if((sx < 400 && sy < 300) && (flag == true)){ //is it on the screen?
moveSquare();
}

try{
}catch (InterruptedException ex){}
}
}
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){}
}```
Last edited by totj; 03-13-2011 at 04:45 AM. Reason: forgot the code :P

2. Moderator
Join Date
Feb 2009
Location
New Zealand
Posts
4,565
Rep Power
12
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.

3. 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
Last edited by ozzyman; 03-13-2011 at 04:18 PM.

4. Member
Join Date
Mar 2011
Posts
13
Rep Power
0
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.

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).

5. 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

6. Moderator
Join Date
Feb 2009
Location
New Zealand
Posts
4,565
Rep Power
12
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.

7. Member
Join Date
Mar 2011
Posts
13
Rep Power
0
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.
Java 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.

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
Java 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{}
Java 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.

8. Moderator
Join Date
Feb 2009
Location
New Zealand
Posts
4,565
Rep Power
12
I meant something like

Java 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.

9. Member
Join Date
Mar 2011
Posts
13
Rep Power
0
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.
Last edited by totj; 03-15-2011 at 02:20 AM.

10. Moderator
Join Date
Feb 2009
Location
New Zealand
Posts
4,565
Rep Power
12
This is basically your code - it might be easier to see the algebra this way...

Java 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);
}
public void start(){
th.start ();
}
public void run(){
while(true){

repaint();

if((sx < 400 && sy < 300) && (flag == true)){ //is it on the screen?
moveSquare();
}

try{
}catch (InterruptedException ex){}
}
}
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.

11. Member
Join Date
Mar 2011
Posts
13
Rep Power
0
oh my holy jesus, a million thank you's. works perfectly :)

12. pbrock, i understand this calculation gets the length of the hypotenuse of the triange, which is the path the square must travel along...
Java Code:
`double scale = Math.sqrt(vx * vx + vy * vy);`
but what does the next part do to it to derive a uniform speed?
Java Code:
```vx /= scale;
vy /= scale;
double speed = 5;
sx += vx * speed;
sy += vy * speed;```

13. 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...
Java Code:
`double scale = Math.sqrt(vx * vx + vy * vy);`
but what does the next part do to it to derive a uniform speed?
Java 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

14. 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

15. 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

16. Moderator
Join Date
Feb 2009
Location
New Zealand
Posts
4,565
Rep Power
12
a million thank you's. works perfectly
You're welcome.

#### Posting Permissions

• You may not post new threads
• You may not post replies
• You may not post attachments
• You may not edit your posts
•