Results 1 to 16 of 16
  1. #1
    totj is offline Member
    Join Date
    Mar 2011
    Posts
    13
    Rep Power
    0

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

    Thanks in advance :)

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

  2. #2
    pbrockway2 is offline Moderator
    Join Date
    Feb 2009
    Location
    New Zealand
    Posts
    4,565
    Rep Power
    12

    Default

    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. #3
    ozzyman's Avatar
    ozzyman is offline Senior Member
    Join Date
    Mar 2011
    Location
    London, UK
    Posts
    797
    Blog Entries
    2
    Rep Power
    4

    Default

    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 03:18 PM.

  4. #4
    totj is offline Member
    Join Date
    Mar 2011
    Posts
    13
    Rep Power
    0

    Default

    Quote Originally Posted by ozzyman View Post
    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 View Post
    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. #5
    ozzyman's Avatar
    ozzyman is offline Senior Member
    Join Date
    Mar 2011
    Location
    London, UK
    Posts
    797
    Blog Entries
    2
    Rep Power
    4

    Default

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

    Default

    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. #7
    totj is offline Member
    Join Date
    Mar 2011
    Posts
    13
    Rep Power
    0

    Default

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

    Default

    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. #9
    totj is offline Member
    Join Date
    Mar 2011
    Posts
    13
    Rep Power
    0

    Default

    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 01:20 AM.

  10. #10
    pbrockway2 is offline Moderator
    Join Date
    Feb 2009
    Location
    New Zealand
    Posts
    4,565
    Rep Power
    12

    Default

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

  11. #11
    totj is offline Member
    Join Date
    Mar 2011
    Posts
    13
    Rep Power
    0

    Default

    oh my holy jesus, a million thank you's. works perfectly :)

  12. #12
    ozzyman's Avatar
    ozzyman is offline Senior Member
    Join Date
    Mar 2011
    Location
    London, UK
    Posts
    797
    Blog Entries
    2
    Rep Power
    4

    Default

    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. #13
    JosAH's Avatar
    JosAH is offline Moderator
    Join Date
    Sep 2008
    Location
    Voorschoten, the Netherlands
    Posts
    13,651
    Blog Entries
    7
    Rep Power
    21

    Default

    Quote Originally Posted by ozzyman View Post
    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
    cenosillicaphobia: the fear for an empty beer glass

  14. #14
    ozzyman's Avatar
    ozzyman is offline Senior Member
    Join Date
    Mar 2011
    Location
    London, UK
    Posts
    797
    Blog Entries
    2
    Rep Power
    4

    Default

    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. #15
    JosAH's Avatar
    JosAH is offline Moderator
    Join Date
    Sep 2008
    Location
    Voorschoten, the Netherlands
    Posts
    13,651
    Blog Entries
    7
    Rep Power
    21

    Default

    Quote Originally Posted by ozzyman View Post
    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
    cenosillicaphobia: the fear for an empty beer glass

  16. #16
    pbrockway2 is offline Moderator
    Join Date
    Feb 2009
    Location
    New Zealand
    Posts
    4,565
    Rep Power
    12

Similar Threads

  1. I need a little direction for a dictionary app
    By Alexis in forum AWT / Swing
    Replies: 5
    Last Post: 02-11-2011, 07:43 PM
  2. random direction
    By i8java in forum Threads and Synchronization
    Replies: 5
    Last Post: 04-26-2010, 10:37 PM
  3. moving square
    By blindfolded in forum New To Java
    Replies: 5
    Last Post: 01-22-2010, 05:58 PM
  4. Looking for direction...
    By ewomack in forum New To Java
    Replies: 4
    Last Post: 09-13-2009, 11:00 PM
  5. [SOLVED] Need direction...
    By hotice1027 in forum New To Java
    Replies: 5
    Last Post: 11-28-2008, 09:03 AM

Posting Permissions

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