Posted: Fri Aug 25, 2006 8:26 pm Post subject: [Tutorial] Moving an Object Towards a Target
Moving an Object Towards a Target
Introduction
The object of this tutorial is to move an object (an (x,y) point) towards a target (another (x,y) point). This can include a ball moving towards another ball, a worm moving towards the cursor. If you have two points, you can make one move to the other (and with some creative thinking, make them both move towards each other, make one accelerate, etc!)
Let's get on with it
Okay, let's start with a simple example. We want to make a ball move around the screen. Okay, simple enough. The ball will have an x and y coordinate (we won't worry about radius). And for every animation loop, we'll move the ball a certain amount, we'll call this value 'speed'. So we move the ball like this.
code:
x += speed
y += speed
But of course the ball won't always be moving 45 degrees, it could be moving horizontally or vertically. We replace 'speed' with two value, xSpeed and ySpeed.
code:
x += xSpeed
y += ySpeed
Here's an example program:
code:
int x = 10
int y = 20
int xSpeed = 10
int ySpeed = 5
loop
x += xSpeed
y += ySpeed
end
That's all good. The ball will move across the screen at a shallow slope, increasing in x and lot more than y. That's all good.
Speed of an object
Okay, that's nice, but what if we want to know how fast our ball is moving? I don't mean how fast it's moving in the x or y direction, I mean, overall. When you're traveling in a direction between north and north-east at 50 km/h, you're still going 50km/h if you change to going north. So our ball, in the example above, isn't moving at 5 pixels per loop, or 10 pixels per loop.
What speed is it going? First, let's rename xSpeed and ySpeed. We'll call them dx and dy, or delta x and delta y. Because they're the x and y differences between the ball's current coordinate and the ball's next coordinate.
Okay, let's look at the dx and dy as vectors. If you remember grade 10 science, you remember that vectors have magnitude and direction. Well, dx has a magnitude of 10 and a direction in the +ve x direction, while dy has a magnitude of 5 and a direction in the +ve y direction.
Now, this is from grade 11 physics, so it might be new to you. Try to follow, and trust me. If you have any questions, I'm usually on the irc channel.
Let's make a vector diagram. B(10,20) is the ball's current coordinate. We'll draw dx going to the right, because we're adding that onto x. And we'll then draw dy going up, because we're adding that onto y. We can figure out where these get us, and that's our new point. Now, the vector labelled 'v' is the speed or velocity of the ball, and is drawn from B to the new position:
From this diagram, we can see that v = dx + dy (a little bit of physics, that's call vector addition. When you add vectors a and b, you draw a and then draw b starting from the head of a). So we can arrange the vectors into a vector addition diagram:
How this helps us you ask? Well, we want to know the length of 'v' here, because that's the ball's velocity. (Remember velocity is the change in distance of the change in time). How does this diagram help us? Look at it, it's a right triangle! And I know you passed grade 9 math, so we can easily use Pythagorean's theorem, a^2 + b^2 = c^2, where a and b are sides of a right triangle and c is the hypotenuse.
So in this case
code:
v^2 = dx^2 + dy^2
or
v = sqrt(dx^2 + dy^2)
So, let's update are example to calculate and show the ball's speed. In the example we'll use speed instead of 'v' for sake of readability:
code:
int x = 10
int y = 10
int dx = 10
int dy = 5
int speed
loop
x += dx
y += dy
speed = sqrt(dx^2 + dy^2)
print("Speed = " + speed)
end
Our output should be:
code:
11.18034
So we'll round that off, and say our ball is moving at 11.2 pixels per loop.
Now, off course, this is only the first step. We don't even know the problem.
The Problem
What's the problem I'm trying to address? Well, just this. Say you want you're object to move towards a point. You would find the difference in x and y between you're object and the target.
code:
int diffx = targetx - x
int diffy = targety - y
You'll move you're ball towards in the x direction and in the y direction. A simple selection structure:
code:
if diffx < dx
x = targetx
else if diffx > 0
x += dx
else if diffx < 0
x -= dx
end
if diffy < dy
y = targety
else if diffy > 0
y += dy
else if diffy < 0
y -= dy
end
What we're doing here:
First, if the distance between this x/y and the target's x/y is less than the ball's movement speed in that direction, we'll simply move right to the target x/y (since we don't want to go over it). Otherwise, we'll move pos/neg x/y direction in order to get to that point. The object will move according to its own x and y speeds.
What's the problem with this? Well, look at what can happen:
If the ball reaches the target's x position before the y position, or vice versa (which, if the target is not pre-calculated, will almost always happen), we get some weird motion. Now say you're trying to get a ball to move towards something. If you walk towards something, do you do some crazy weird path? No, you go straight towards it.
So how do we do this? Watch and be amazed! This is how we move an object. We move it by changing its x and its y. And that will give us a speed. So, if we want to move an object towards something, we can't predetermine it's x and y changes. We do need something, and we can set a speed. It's pretty simple to want your ball to move at about 30 pixels per loop, right? Well, it's a little more complicated to do it, but it makes sense. So we have 3 values for movement: dx, dy, and speed.
We can find any of the other values if we have the two others.
dx and dy will form a triangle with speed because we want the ball to move at a constant speed, or rather, the speed we set it to.
But we only have one value, speed. So we'll turn to the idea of proportional triangles. If we have two similar triangles, their sides are proportional. Take the following diagram:
The smaller triangle has sides a, c, and e. The large triangle has sides (a+b), (c+d), f
So, in this example, a/(a+b) = c/(c+d) = e/f
This is also true the other way around, (a+b)/a = (c+d)/c = f/e.
BE WARNED though, a/(a+b) != (c+d)/c. All the sides of one triangle have to be on the top of the fractions, while the sides of the triangles are on the bottom.
How do we apply this? Well, let's make a diagram with our movement triangle and the target. We want the ball to move towards the target, so we'll set it's speed in that direction.
I've introduced some new values here: diffx and diffy are the x/y differences between the ball and the target. And 'dist' is the distance between the ball and the target, which can be easily found using Pythagoreans theorem with diffx and diffy.
So now we have a direct way to find dx and dy. And we're translating our ball by dx and dy, so thus we have a direct way to move our ball directly towards a target. And you can bet that sqrt(dx^2 + dy^2) will be exactly speed. Or, as close as possible. I recommend leaving dx and dy as a double/real type, and round when you change the x and y values. Also, leave 'dist' as a double/real, and you don't have to round it ever.
Here's an example program where the ball will follow the mouse cursor at 30px/loop, written in no particular language but easy to convert to any.
code:
//Start our ball at (10,10)
int x = 10
int y = 10
//The x and y offsets to move the ball
double dx
double dy
//Our ball will move 30 pixels per loop
int speed = 30
//Values for the target's x and y
int targetx
int targety
//The loop
loop
//Set the target to the mouse's position
targetx = mouseX
targety = mouseY
//Find the x and y differences between the ball and the target
int diffx = targetx - x
int diffy = targety - y
//Calculate the distance between the ball and the target
double dist = sqrt(diffx^2 + diffy^2)
//Calculate the x and y offsets to move the ball
dx = (speed / dist) * diffx
dy = (speed / dist) * diffy
//If the ball moves past the target, keep it at the target
if abs(diffx) < abs(dx)
x = targetx
end
if abs(diffy) < abs(dy)
y = targety
end
//Move the ball
x += round(dx)
y += round(dy)
//Draw the ball
drawball(x, y)
end
There you go! Try it, any questions or suggestions PLEASE post, or talk to me on the irc channel. Thanks for listening
Sponsor Sponsor
Aziz
Posted: Sat Aug 26, 2006 12:56 am Post subject: (No subject)
Here's an example program in Turing
Turing:
View.Set("graphics:800;600,position:center;center,title:Chase the mouse,offscreenonly")
%Start our ball at (10,10) var x :int:=10 var y :int:=10
%The x and y offsets to move the ball var dx, dy :real
%Our ball will move 5 pixels per loop var speed :int:=5
%Values for the target's x and y var targetx, targety :int
%Just a button value, no use to us var button :int
%The loop loop %Set the target to the mouse's position Mouse.Where(targetx, targety, button)
%Find the x and y differences between the ball and the target var diffx := targetx - x
var diffy := targety - y
%Calculate the distance between the ball and the target var dist :=sqrt(diffx ** 2 + diffy ** 2)
%If the ball is ontop of the mouse, set it there, otherwise calculate movement. %This prevents divide by zero errors. if dist <= 0then
x := targetx
y := targety
else %Calculate the x and y offsets to move the ball
dx :=(speed / dist)* diffx
dy :=(speed / dist)* diffy
endif
%If the ball moves past the target, keep it at the target ifabs(diffx) < abs(dx)then
x := targetx
endif
Next challenge - moving an object with a limited turn radius. Currently your object just goes in a straight line on cruise control. See if you can implement object's orientation and curved turns. Such as a car or a snake facing one way, and having a non-straight-line target.
Posted: Sat Aug 26, 2006 8:59 am Post subject: (No subject)
for that would you not just use some sort of difference constant (or something of the sort), to control how much the dx and dy values change? for example, if you (using the program above [pseudo or not]) have the ball following the mouse, and swing it upwards, the dy value would change almost opposite, but you could just change it so that it changes no greater than say 4 pixels? am i right or am i wrong?
Aziz
Posted: Sat Aug 26, 2006 10:13 am Post subject: (No subject)
I'm not exactly sure what you're talking about, but let me see:
You mean, have it so that the dx and dy can change, but no more than 4? So what if the ball is at (10,10) and the target is at (20, 200). If both dx and dy are four, the ball would move at an angle to get nearest to the target, but it wouldn't be travelling towards the target. Look at the third picture (It's under "The Problem") that's what I mean.
Now I'm not sure that's what you're talking about. If you could, write a sample program (or alter mine) and paste it?
Tony
Posted: Sat Aug 26, 2006 2:10 pm Post subject: (No subject)
SuperFreak82 wrote:
you could just change it so that it changes no greater than say 4 pixels? am i right or am i wrong?
wrong
if your dy was 2, and then the new target is in exact opposite direction, so that dy becomes -2 => your |acceleration| is 4, but you have just turned 90 degrees on the spot.
Posted: Sat Aug 11, 2007 2:20 pm Post subject: RE:[Tutorial] Moving an Object Towards a Target
I want to point out that some of these characters are unreadable/gibberish on my browser (firefox) running on Vista.
If you wish to use mathematical notations please use the compsci's [tex] tag
Edit: apparently its your apostrophe that's messed up, Aziz.
Aziz
Posted: Mon Aug 13, 2007 10:29 am Post subject: RE:[Tutorial] Moving an Object Towards a Target
It's like that with all the old posts from v2. It does it with XP as well.
Sponsor Sponsor
Nick
Posted: Mon Aug 13, 2007 11:17 am Post subject: Re: RE:[Tutorial] Moving an Object Towards a Target
Aziz @ Mon Aug 13, 2007 10:29 am wrote:
It's like that with all the old posts from v2. It does it with XP as well.
i'd like to point out that it does it with ME as well... nice tuturial btw this will help me in games... im thinking of a rts which will come extremly handy koudos (however you spell it)
Aziz
Posted: Mon Aug 13, 2007 12:02 pm Post subject: RE:[Tutorial] Moving an Object Towards a Target
I think it's spelt "kudos" but beats me. I think it's what happened when Dan moved the forums from v2 to v3, so it's OS independent.
This is where my math courses came in. Take Geometry and Discreet Math if you can, it's great.
Nick
Posted: Mon Aug 13, 2007 2:07 pm Post subject: RE:[Tutorial] Moving an Object Towards a Target
im great at math so i definatly will ^_^
Clayton
Posted: Wed Aug 15, 2007 7:39 pm Post subject: RE:[Tutorial] Moving an Object Towards a Target
Geometry and Discrete Mathematics no longer exists in the Ontario High School Curriculum.
Aziz
Posted: Wed Aug 15, 2007 10:06 pm Post subject: RE:[Tutorial] Moving an Object Towards a Target
That's right, my teacher from Grade 12 told me that a few weeks ago . . . What are they replacing it with?
Clayton
Posted: Thu Aug 16, 2007 7:15 pm Post subject: RE:[Tutorial] Moving an Object Towards a Target
They are actually taking out the old Geometry and Discrete and Calculus courses, and replacing them with an Advanced Functions (4U) course, and a new calc course, Calculus and Vectors (also 4U). From what I understand, Advanced Functions is a soft introduction to ideas from Geometry and Discrete, as well as Calculus, and is therefore a prereq for Calculus and Vectors.
Nick
Posted: Fri Aug 17, 2007 4:00 pm Post subject: RE:[Tutorial] Moving an Object Towards a Target