PDA

View Full Version : moving sprites



buster
13-09-2003, 12:38 AM
Can someone show me some code to move a sprite from it's
current position to new position?? A sort of Sprite.Moveto(x,y) procedure

Traveler
13-09-2003, 11:07 AM
Have you tried the DirectX component sets yet? In case you haven't I highly recommend those. DelphiX for example is not very hard and comes with some great samples. Among those examples, you'll also find the answer to your question.

buster
15-09-2003, 08:01 AM
I had a look but the samples don't do what i'm asking
what I need to is have a sprite at say (100,30) and then tell it to move to
location (200,300) but move in a stright line at agiven speed and i need to know when it gets there

Traveler
15-09-2003, 08:23 AM
I'm not sure there's a componentset that has a function you described. But why don't you write it yourself? Moving a sprite in a straight line at a given speed is a very simple procedure.


if player.x < 400 then
player.x &#58;= player.x + player.speed
else
begin
showmessage&#40;'I''m home'&#41;
timer1.enabled &#58;= false // else you get this message forever ;&#41;
end;
this should get you started...

buster
15-09-2003, 09:32 AM
I think that i'm not making my self clear on what i'm asking so i'll
try agian the sprite is at (100,30) i tell it to goto (200,100) and in some amout of steps it will get to the position (200,100) so the x value has moved 100 pixels and the y value has moved 70 pixels but the x and y
get to their positions at the same time I hope this makes sence..

Alimonster
15-09-2003, 09:59 AM
The task varies depending on whether your updates occur at a fixed time or with delta time.

First, let's consider the fixed time-per-updates (e.g. if your updates happened in response to a timer tick). You have two values to calculate:

The amount that the x value will change per tick
The amount that the y value will change per tick

This is simple enough -- you want to calculate the difference in x (and y):
destination - current position. Divide each value by the amount of updates that are wanted to get how much to move the sprites each tick. For example (untested code):

type
TSprite = record
x: Single;
y: Single;
SpeedX: Single;
SpeedY: Single;
DestX: Single;
DestY: Single;
end;

procedure SetSpriteDestination(var Sprite: TSprite; NewX, NewY: Single;
Updates: Integer);
var
NewSpeedX: Single;
NewSpeedY: Single;
begin
// we want to move to (NewX, NewY). Calculate the differences
// to get the total amount to move (positive or negative). Once
// we know how far to move, we want a division, since we don't
// want to move over there in one go!
NewSpeedX := (NewX - Sprite.X) / Updates;
NewSpeedY := (NewY - Sprite.Y) / Updates;

Sprite.SpeedX := NewSpeedX;
Sprite.SpeedY := NewSpeedY;
Sprite.DestX := NewX;
Sprite.DestY := NewY;
end;

const
VERY_SMALL_NUMBER = 0.1e-6;

procedure UpdateSprite(var Sprite: TSprite);
begin
// check whether we've reached the destination
if (abs(Sprite.DestX - Sprite.X) <= VERY_SMALL_NUMBER) and
(abs(Sprite.DestY - Sprite.Y) <= VERY_SMALL_NUMBER) then
begin
Sprite.SpeedX := 0;
Sprite.SpeedY := 0;
Sprite.X := Sprite.DestX;
Sprite.Y := Sprite.DestY;
end
else
begin
// move there!
Sprite.X := Sprite.X + Sprite.SpeedX;
Sprite.Y := Sprite.Y + Sprite.SpeedY;
end;
end;

Note that you shouldn't compare floating point numbers directly for
equality -- instead, use an epsilon value as above. Floating point numbers
can have small inaccuracies creeping in over time, so the numbers may be
(e.g.) 0.00000002 instead of just 0.0 depending on the operations you use. Play around with the small number to toggle the "close enough" factor. I forget good values (the value 0.1e-6 is probably much too small here, try making it a bigger number...).

Things are a little more complicated if you use delta time. For this, do the following: think about how far you want to go in a given amount of time (note: time, rather than updates). Keep a track of the current amount of time that's passed that's passed. Then, it's pretty straightforward to calculate the amount to move. I'll explain how later today once I get back home (got work to do :().

Crisp_N_Dry
16-09-2003, 10:39 PM
An alternative is to calculate the angle between the Current Position and the Destination Position, then move you sprite at this angle at whatever speed towards its destination. The following code shows you how. BTW the following GetAngle code is of my own concoction since I couldn't remeber the proper way so don't laugh if it's horribly unoptimised or just plain silly.



function GetAngle&#40;SPos,FPos&#58; TPoint&#41;&#58; Real;
var
Lgt,Hgt&#58; Real;
Rad,Deg&#58; Real;
begin
Deg&#58;=0;
Lgt&#58;=FPos.X-SPos.X;
If Lgt=0 Then Lgt&#58;=0.01;
Hgt&#58;=FPos.Y-SPos.Y;
If Hgt=0 Then Hgt&#58;=0.01;
Rad&#58;=ArcTan&#40;Hgt/Lgt&#41;;
//Top Left Corner
If &#40;FPos.X<SPos.X&#41; and &#40;FPos.Y<SPos.Y&#41; Then Deg&#58;=Rad*&#40;180/Pi&#41;+180;
//Top Right Corner
If &#40;FPos.X>=SPos.X&#41; and &#40;FPos.Y<SPos.Y&#41; Then Deg&#58;=Rad*&#40;180/Pi&#41;+360;
//Bottom Left Corner
If &#40;FPos.X<SPos.X&#41; and &#40;FPos.Y>=SPos.Y&#41; Then Deg&#58;=Rad*&#40;180/Pi&#41;+180;
//Bottom Right Corner
If &#40;FPos.X>=SPos.X&#41; and &#40;FPos.Y>=SPos.Y&#41; Then Deg&#58;=Rad*&#40;180/Pi&#41;;
GetAngle&#58;=Deg;
end;
after we use our GetAngle procedure like so


Angle&#58;=GetAngle&#40;Point&#40;CurPos.X,CurPos.Y&#41;,Point&#40;Des tPos.X,DestPos.Y&#41;&#41;;

(BTW if this doesn't seem to work properly, try switching the order in which you parse the vars into the getangle function e.g dest first then curpos. I forget which way round they go I think this is correct)
we can then use this angle to move the object towards the destination with the following code. Again, this code is my own and I have no idea whether it's the best way of doing things but it's my way of doing things.


CurPos.X&#58;=Round&#40;Speed*Cos&#40;&#40;Angle&#41;*Pi/180&#41;&#41;+CurPos.X;
CurPos.Y&#58;=Round&#40;Speed*Sin&#40;&#40;Angle&#41;*Pi/180&#41;&#41;+CurPos.Y;

The pi/180 converts the result of the Cos/Sin into Degrees, the standard return for these are in Radians. Let me know what you think.
[/i]

Alimonster
18-09-2003, 09:18 AM
Crisp_N_Dry: your function looks okay, apart from the formatting (http://community.borland.com/soapbox/techvoyage/article/1,1795,10280,00.htm) ;) It would be useful for times when the destination changed a lot (maybe homing missiles or whatever), though that would need a little modification to ensure it doesn't overshoot.

I totally forgot to mention the delta time way to go from point a to point b. Ooops! One method is to keep the time passed and total time expected. You could then calculate a percent of time passed and multiply it with the given vectors (i.e., calculate one percent of the horizontal movement required, then one percent of the vertical movement). This would be standard interpolation, a + t(b - a). This would be pretty much guaranteed to find the spot

The alternative would be a bit similar to Crisp_N_Dry's method, in that each sprite has a speed, so it's not known how long it will take. This involves the usual stuff, multiplying a vector by the speed and the time passed (IIRC!), with an annoying check to ensure that the person doesn't overshoot (since they may move too far depending on how much time has passed).

The advantage of using an angle is that you can keep the old one, and gradually "turn" towards where you want to go - handy for vehicle-like turning circles, I'd suppose (without having tested that assumption).