DelphiX - Frame rate independent movement!! Help!

Started by
5 comments, last by Mike Moore 20 years, 11 months ago
Hi, I really need some advice on how to correctly implement frame rate independent movement in a game I am writing. It’s got me really puzzled and I really could do with some help. I am using Delphi and the DelphiX components It’s a typical 4 way scrolling game. The player stays in the centre of the screen and I’m using DelphiX’s Tbackground sprite as a tiled background. The tiles are 32x32 pixels wide (the same as the player), although I may change this. I am using DelphiX’s Dxtimer for the main playing routine and I’ve set this timer’s interval to 0, to achieve the maximum FPS. I want the player to move smoothly from over one tile onto the next, provided the way isn’t blocked of course and I’ve been doing all this fine. No diagonal moves either, only up, down, left and right. However, the way I had been doing this is to move the player (or rather the Tbackground sprite’s position underneath) by 3.2 pixels in each time cycle. So in effect you get 10 nice smooth steps as the player moves across the grid. Before I allow the player to move I check the square he wants to go on to is walkable in the normal fashion. Now this works wonderful on my computer with a Voodoo card. I get 117/120 FPS (according to the Dxtimer) and the player moves at exactly the right speed. Also my calculations of where my player is is simple, because everything nicely divides up. I just keep track when he’s between squares and count along until I reach 10 (3.2 each move remember), then I know he’s moved fully onto a new grid/tile position. Or I can simply divide the overall x,y by 32 to produce the square he is on precisely (because it divides up precisely) But, if I run my game on a friends computer he only gets 58/65 frames per second. Everything is nice and smooth, but because I’m still only adjusting the player by 3.2 pixels on each timer cycle the game plays almost half as slow (60 odd frames compared to my 120). So. I’ve been reading on the internet, including on gamedev.net about “frame rate independent movement”. I came to the conclusion (perhaps incorrectly!?) that I need to move not by 3.2 pixels on each cycle but by varying it depending on the FPS (cycle). Sounds good I thought. I did this by first deciding how many pixels I’d like to travel in one second. For example, say I want to move 96 pixels per second. I get the current FPS and do the maths… PixelsPerSec/FPS = no.of pixels I should move on this cycle. (one frame). On my machine I’d get 96/117=0.8205128 My friends for example 96/58=1.6551724 Now. This all sounds great to me. But the problem has come when trying to now work out exactly where my player character is. When I was adjusting his movements by 3.2 I knew that after 10 movements in any direction I’d get a *direct* XY value as to which tile he was on and so could work out which tiles were blocking him etc. But now, as my tbackground sprite moves around beneath my player, I am not sure how to determine where my player is and importantly when he should stop exactly over the next tile. Because the numbers are now not divisible precisely by 32, and change because of the frame rate each time. This is the maths bit, which I was never really any good at at school so, you’ll have to forgive me here!! :-) If I just divide my player’s xy position by 32 I can sort of tell where he is. But my main problem is I need the player to stay exactly over a tile. No overlap at all, except when he is moving between tiles of course, either up/down, left or right (not diagonal). I can’t seem to now work out how to stop my player when he slides across from one tile to another and then make him stop exactly over the other tile. I''m now increasing the position by some obscure figure, not 3.2 so I never *hit* the next tile cleanly. Does ANY of this make sense to you? J I know there is a simple answer to this, but my brain is beginning to hurt now. It’s just a simple maths calculation isn’t it? Is this the correct way to solve the frame rate independent movement anyway? It looks right. Anyway, some advice if you understand any of this, would be helpful! Regards, Mike
Advertisement
I can''t help you with your DelphiX problem, but I''d like to congratulate you to your Oscar for "Best Documentary".
"Bowling for Columbine" is an awesome movie. Great job!
This is only a suggestion, and one which I have implemented.

I added a TTimer and set it''s interval to 200, a slow tick serves to even out the machine ''jerks'' and doesn''t interfere with high speed processing. The point is the TTimer ticks according to real time, not machine speed.

In the DXTimer routine, I increment a tick counter.

I hold a global variable which indicates the number of ticks I want to occur between events (camera waypoints, sprite movements, whatever). This can be set up by experiment on a few (preferably slower) machines.

In the TTimer routine, I compare the tick counter against the global variable and, if it is faster than I want, I increase the interval of the DXTimer, if slower, decrease it. I also zeroise the tick counter for the next time. This means eventually the DXTimer will tick at the speed I want in real time.

It is also possible, by this method, to have a ''speed control'' slider, the value of which goes into the global variable during development and testing, and can be hidden for the distribution.

I''m sure there are other methods (using the lag time, maybe), but this one certainly works for me.

Hope this helps a little.



Stevie

Don''t follow me, I''m lost.
StevieDon't follow me, I'm lost.
You don''t actually need another Timer (TTimer), you can simply use GetTickCount to achieve the same thing.
Let''s say you want to move your player 1 pixel every 10 milliseconds, do this:

GLOBAL:
LastTickCount: LongInt;

ONCREATE:
LastCount := GetTickCount;

YOUR TIMER-EVENT:
ThisTickCount := GetTickCount;
if ThisTickCount >= LastTickCount + 10 then
begin
LastTickCount := GetTickCount;
Move_Your_Sprite_One_Pixel;
end;


This is pretty much what you''re after.
Might be missing the point but why not use a Pixels per second approach?

Say you want the object to move 100 pixels per second then in the update area you just do the following


x:=x+(100 * (lagcount / 1000);

obviously x is a real, keep it as real until you do the actual drawing and then use trunc(x).

This way you know the objects move at the same speed regardless of system. Also it is now easy to implement velocity by changing the 100 to a variable and increasing or decreasing it.



[edited by - czar on May 5, 2003 3:42:28 PM]
Czar,

I am trying to do that and this does appear to work. Regardless of the frame rate the background appears to scroll at the same speed.

However, now my problem is trying to make sure the player stops exactly on the next tile.

If I move right, say half the screen, and then move him back left, he never stops in exactly the same pixel position because we are not adding/subtracting values that divide into the tile''s 32 pixel size.

Do you see what I mean?

Mike
quote:Original post by Harry Hunt
You don''t actually need another Timer (TTimer), you can simply use GetTickCount to achieve the same thing.
Let''s say you want to move your player 1 pixel every 10 milliseconds, do this:

GLOBAL:
LastTickCount: LongInt;

ONCREATE:
LastCount := GetTickCount;

YOUR TIMER-EVENT:
ThisTickCount := GetTickCount;
if ThisTickCount >= LastTickCount + 10 then
begin
LastTickCount := GetTickCount;
Move_Your_Sprite_One_Pixel;
end;


This is pretty much what you''re after.


I like this idea, and had experimented with it. But it never seems to produce smooth movement. Should I be using a different (faster) timer to make this decision quicker? DelphiX only seems to allow one timer.


Mike


This topic is closed to new replies.

Advertisement