Jump to content
  • Advertisement
Sign in to follow this  
tom_mai78101

How to move a dot when given 2 coordinate points?

This topic is 2524 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a dot in a blank screen. I have calculated the dot's coordinates (relative location from source component) and the mouse coordinates (after the user clicks on the screen). The constant speed of the dot is fixed at 1 pixels per tick, 60 ticks per second.

Now, there are two points in the screen. You can imagine a invisible line connecting the two points, and the dot traverses on this imaginary line from its source coordinates to the target coordinates.

What math should I use to move the dot along the line in a more linear way?

I have here a crude path movement for the dot, now basked in your glorifying eyes:


public void tick(MouseInputHandler input)
{
target = input.mousePosition;
if (target == null)
return;
int direction = 0;
if (position.x > target.x)
direction = -1;
else
direction = 1;
if (position.x == target.x)
direction = 0;

position.x += direction;

if (position.y > target.y)
direction = -1;
else
direction = 1;
if (position.y == target.y)
direction = 0;
position.y += direction;
}


If possible, where can I improve? And where can I learn more about path movement algorithms? Thanks in advance.

Share this post


Link to post
Share on other sites
Advertisement
You can use trigonometry to calculate the exact direction you need to move at.
Consider this code:

double angle = atan2(target.y-position.y, target.x-position.x);
double xVel = speed*cos(angle);
dboule yVel = speed*sin(angle);


And then you simply add the velocity values from the last code to the position of your point.

position.x += xVel;
position.y += yVel;


Hope this is what you meant and that it answers your question =)

Share this post


Link to post
Share on other sites
Actually, if you use vector math, you can avoid using trigonometry entirely. You can do this:

double xVel=target.x-position.x;
double yVel=target.y-position.y;
double mag=sqrt(xVel*xVel+yVel*yVel);
xVel=xVel*speed/mag;
yVel=yVel*speed/mag;

and then add the xVel and yVel to your position like in KazenoZ's example.

Share this post


Link to post
Share on other sites
To KazenoZ:

The dot keeps jumping around. When the dot moves, it jerks its way in straight lines, instead of going diagonally. I don't know why, but when I do logging, it shows that the values for xVel and yVel jumps without staying put in one direction.

--------------------


To RulerOfNothing:

This is what I've got:

Capture-12.png

In the console, it reveals that xVel and yVel keeps jumping around, positive to negative and back. When it's running, the dot you see in the black screen jumps around quite a lot, and the distance increases when the speed increases. It's pretty blurry.

Share this post


Link to post
Share on other sites
If you use RulerOfNothing's code, you cannot continually re-calculate the velocity every tick. Calculate the velocity once, and then use the velocity until the dot reach the target. Or, only recalculate when the target dot moves.

In Fact RulerOfNothing's code is a bit misleading. It should be:


[color=#000088]double[color=#000000] xDist[color=#666600]=[color=#000000]target[color=#666600].[color=#000000]x[color=#666600]-[color=#000000]position[color=#666600].[color=#000000]x[color=#666600];
[color=#000088]double[color=#000000] yDist[color=#666600]=[color=#000000]target[color=#666600].[color=#000000]y[color=#666600]-[color=#000000]position[color=#666600].[color=#000000]y[color=#666600];
[color=#000088]double[color=#000000] mag[color=#666600]=[color=#000000]sqrt[color=#666600]([color=#000000]xDist[color=#666600]*[color=#000000]xDist[color=#666600]+[color=#000000]yDist[color=#666600]*[color=#000000]yDist[color=#666600]);
[color=#000000]double xVel[color=#666600]=[color=#000000]xDist[color=#666600]*[color=#000000]speed[color=#666600]/[color=#000000]mag[color=#666600];
[color=#000000]double yVel[color=#666600]=[color=#000000]yDist[color=#666600]*[color=#000000]speed[color=#666600]/[color=#000000]mag[color=#666600];



Although, I personally prefer the trig method.

Share this post


Link to post
Share on other sites
It's jumping around due to the loss of procession. You need to put something in so that it gets to exactly the pixel you want it to or gets close to it. If you use Doubles all the way through you'll get it to move in prefect diagonals but due to the speed never getting it perfectly correct it over shoots on the last frame of the calculation. This results in it having to turn around and go the other direction which it over shoots again and again. Your original code had this correct because it was using raw integers but could result in it going faster then 1 pixel per frame since going 1 up and 1 accost would be a speed of sqrt(2) 1.4 pixels when it moved diagonal but 1 pixel when it moved in only one direction. Even with Integers if you use the donated formulas it will jump around due to over shooting.


Something like this should work

if (PointX < PointDestX && (PointX + xVel) > PointDestX) {
PointX = PointDestX;
} else if (PointX != PointDestX) {
PointX += xVel;
}
if (PointY < PointDestY && (PointY + yVel) > PointDestY) {
PointY = PointDestY;
} else if (PointY != PointDestY) {
PointY += yVel;
}


Personally I don't like the way you're passing in the MouseInputHandeler every time. I'm not sure how the rest of your code looks ether but I have my susspisions based on you passing in the Mouse Handeler.

Something like this may help you.

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.JFrame;
public class Test extends JFrame implements WindowListener, MouseListener {
public static void main(String args[]) {
Test t = new Test();
}
Canvas canvas;
double speed = 1;
double PointX = 100;
double PointY = 100;
double PointDestX = 200;
double PointDestY = 200;
volatile boolean isRunning = true;
Thread animationThread;
public Test() {
super("Test");
animationThread = new Thread(new animation());
setSize(320, 240);
canvas = new myCanvas();
add(canvas);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addWindowListener(this);
canvas.addMouseListener(this);
setVisible(true);
}
@Override
public void windowOpened(WindowEvent e) {
animationThread.start();
}
@Override
public void windowClosing(WindowEvent e) {
isRunning = false;
}
@Override
public void mouseClicked(MouseEvent e) {
PointDestX = e.getX();
PointDestY = e.getY();
}
class animation implements Runnable {
@Override
public void run() {
while (isRunning) {
canvas.repaint();
try {
/*
int direction = 0;
if (PointX > PointDestX) {
direction = -1;
} else {
direction = 1;
}
if (PointX == PointDestX) {
direction = 0;
}

PointX += direction;

if (PointY > PointDestY) {
direction = -1;
} else {
direction = 1;
}
if (PointY == PointDestY) {
direction = 0;
}
PointY += direction;
*/

double xVel = PointDestX - PointX;
double yVel = PointDestY - PointY;
double mag = Math.sqrt(xVel * xVel + yVel * yVel);
xVel = xVel * speed / mag;
yVel = yVel * speed / mag;
//double xDist = PointDestX - PointX;
//double yDist = PointDestY - PointY;
//double mag = Math.sqrt(xDist * xDist + yDist * yDist);
//double xVel = (int) (xDist * 2 / mag);
//double yVel = (int) (yDist * 2 / mag);
if (PointX < PointDestX && (PointX + xVel) > PointDestX) {
PointX = PointDestX;
} else if (PointX != PointDestX) {
PointX += xVel;
}
if (PointY < PointDestY && (PointY + yVel) > PointDestY) {
PointY = PointDestY;
} else if (PointY != PointDestY) {
PointY += yVel;
}
Thread.sleep(10);
} catch (InterruptedException ex) {
}
}
}
}
class myCanvas extends Canvas {
Image offscreen = null;
Graphics offgc;
@Override
public void paint(Graphics g) {
if (offscreen == null) {
offscreen = createImage(getWidth(), getHeight());
offgc = offscreen.getGraphics();
} else if (offscreen.getHeight(canvas) != getHeight() | offscreen.getWidth(canvas) != getWidth()) {
offscreen = createImage(getWidth(), getHeight());
offgc = offscreen.getGraphics();
}
offgc.setColor(Color.black);
offgc.fillRect(0, 0, this.getWidth(), this.getHeight());
offgc.setColor(Color.white);
offgc.fillRect((int) PointX, (int) PointY, 1, 1);
g.drawImage(offscreen, 0, 0, this);
}
@Override
public void update(Graphics g) {
paint(g);
}
}
/*unused handlers go here*/
}


I even have problems with this code since I should be doubling up on the points when they are being changed vs when they are being drawn so that it can work on two processors properly but that would take more time then I'm willing to do. However this allows the logic to be run without having the mouse object passed to it every single time. I'm also using Thread.sleep to control the frames and there are better ways of doing that when you're using something like the lwjgl instead of a canvas. Then again I like having more control over my threads since tossing them into a thread pool or scheduler causes too much blocking which will slow it down on code this small.

Share this post


Link to post
Share on other sites
[color=#000088]EDIT: I am too sick of the behavior of the code tags to repeat what I just typed. Sorry.

Share this post


Link to post
Share on other sites
I'm passing my MouseInputHandler because I need the mouse click positions.

New information:

I found out that my dot moves vertically and horizontally, but never diagonally when using any of the methods mentioned. I shall try to refine this. All in all, my dot moves in an unnatural way, I'm not satisfied with it, but if I need to make it move more smoothly, it would require implementing the A* algorithm or something, which I'm not ready to tackle it yet.

One last thing, how do you check and stop updating the X and Y if the dot starts to jump back and forth? The only (bad) way is to add a lot of if...else conditions.

===================================================

@alvaro, is this your code?


double xDist = target.x - position.x;
double yDist = target.y - position.y;
double mag = sqrt(xDist * xDist + yDist * yDist);
if(mag >= speed)
{
double xVel = xDist * speed / mag;
double yVel = yDist * speed / mag;
position.x += xVel;
position.y += yVel;
}
else
{
position.x = target.x;
position.y = target.y;
}
//-----------------------------------------------------------------------------------
Vector2D dist = target - position;
double mag = length(dist);
if(mag >= speed)
position += dist * (speed / mag);
else
position = target;

Share this post


Link to post
Share on other sites

@alvaro, is this your code?

Yes, it is! How did you get it? When I posted it I saw some garbled mess and I couldn't see how to recover it...

Share this post


Link to post
Share on other sites

I found out that my dot moves vertically and horizontally, but never diagonally when using any of the methods mentioned. I shall try to refine this.

That is a bug. Perhaps you are using `int' in some place where you should be using `double'?

All in all, my dot moves in an unnatural way, I'm not satisfied with it, but if I need to make it move more smoothly, it would require implementing the A* algorithm or something, which I'm not ready to tackle it yet.[/quote]
No, A* has nothing to do with smooth movement. Figure out exactly what your code is doing wrong and fix it.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!