In the old times, when people were still writing their own basic video routines for drawing lines and circles, it was not unheard of to use the Bresenham line algorithm for that.
Bresenham solves this problem: you want to draw a line on the screen which moves
dx pixels in the horizontal direction while at the same time spanning
dy pixels in the vertical direction. There is an inherent "floaty" character to lines; even if you have integer pixels, you end up with rational inclinations.
The algorithm has to be fast though, which means that it can use integer arithmetic only; and it also gets away without any multiplication or division, only addition and subtraction.
You can adapt that for your case:
- Your "x direction" (in terms of the Bresenham algorithm) is your clock.
- Your "y direction" is the value you want to increment (i.e., the position of your character -- careful, this is not actually the "y" of your sprite or whatever on the screen, more an abstract value)
"x/y" here are not the location on the screen, but the value of one of your dimensions in time. Obviously, if your sprite is running in an arbitrary direction across the screen, you will have multiple Bresenhams running separately, 2 for 2D, 3 for 3D.
Let's say you want to move your character in a simple movement from 0 to 25 along one of your axes. As it is moving with speed 2.5, it will arive there at frame 10.
This is the same as "drawing a line" from (0,0) to (10,25). Grab Bresenham's line algoritm and let it run. If you do it right (and when you study it, it will very quickly become clear how you do it right), then it will generate 11 "points" for you (0,0), (1,2), (2,5), (3,7), (4,10) ... (10,25).
Hints on adaptation
If you google that algorithm and find some code (Wikipedia has a pretty large treaty on it), there are some things you need to watch out for:
- It obviously works for all kinds of
dy. You are interested in one specific case though (i.e., you will never have
- The usual implementation will have several different cases for the quadrants on the screen, depending on whether
dy are positive, negative, and also whether
abs(dx)>abs(dy) or not. You of course also pick what you need here. You have to make especially sure that the direction which is increased by
1 every tick is always your "clock" direction.
If you apply these simplifications, the result will be very simple indeed, and get completely rid of any reals.