Character speed control

Topics related to the API, programming discussions & questions, coding tips, bugs, etc. should go here.
Post Reply
User avatar
nicksen782
Posts: 714
Joined: Wed Feb 01, 2012 8:23 pm
Location: Detroit, United States
Contact:

Character speed control

Post by nicksen782 »

So, I have this game where I move a character to the left or right. Before the start of each set of movements I assign a number of x frames. In the game loop if the actor has an x frame remaining the program will remove one and then adjust the x position based on which way the actor is facing.

I wanted to control speed though so I came up with this:

Code: Select all

// ENEMY SPEED CONTROL
if( actors[i].xFramesRemaining > 0 && actors[i].vcounter8b_general > speed){
	// Move left?
	if     (actors[i].xDir==0){ actors[i].x--; }
	// Move right?
	else if(actors[i].xDir==1){ actors[i].x++; }

	actors[i].xFramesRemaining --;
	actors[i].vcounter8b_general=0;
}
Every vsync (post) the counter8b_general is incremented. If I set speed to 0 then the movement is what I would call 100% of top speed. But, if I set speed to 1 then it is 50%. Changing it to 2 is 25% and so on. I want to get speeds between those values. Perhaps in increments of 10%.

But, vsync is 60 times a second. I am using that to create counters that I can use like timers. I need the counter to count faster which I believe would give me more counts per second and therefore better granular control over speed.

Any ideas on this?
User avatar
D3thAdd3r
Posts: 3293
Joined: Wed Apr 29, 2009 10:00 am
Location: Minneapolis, United States

Re: Character speed control

Post by D3thAdd3r »

Fixed point math is the solution to this. Add a subpixel value each frame, and use the higher part of it as the x/y to draw the sprite as. Some frames it will jump a coordinate, some it wont, but it is kept track of over time.
User avatar
nicksen782
Posts: 714
Joined: Wed Feb 01, 2012 8:23 pm
Location: Detroit, United States
Contact:

Re: Character speed control

Post by nicksen782 »

Perhaps this was discussed here earlier, but how do I do this?

I'm seeing something about fixed point movements. Such as x is 1 and you add 0.25 to it but you cast it as an integer before actual use. It is still one until is it 2 or greater. In effect, 1 pixel of movement is the result of 4 changes of 0.25. I could reduce the size by 4 in this manner.

I'm reading about moving the direction and the speed instead of x and y.

I'll have to try this out... Has anyone accomplished this in an Uzebox game? Bugz maybe?
User avatar
Jubatian
Posts: 1569
Joined: Thu Oct 01, 2015 9:44 pm
Location: Hungary
Contact:

Re: Character speed control

Post by Jubatian »

If you want timers, you can do DDA (Digital Differential Analyzer, Bresenham line and likes).

For example let's give 100 ticks to one frame. You set your speed as a percentage, like 120 or 80. You add this to the timer variable in every frame, and if the timer got larger or equal to 100, you subtract 100, and move a pixel (multiple times if necessary).

Hope it is not too hard to imagine, try to code it and see the result.

FoaD by the way uses no fixed point math as there was no RAM for those larger variables. All movements which appear slower than 1px / frame are timed, particularly gravity uses one common timer (thus saving several bytes worth of RAM from coordinates).
User avatar
D3thAdd3r
Posts: 3293
Joined: Wed Apr 29, 2009 10:00 am
Location: Minneapolis, United States

Re: Character speed control

Post by D3thAdd3r »

The basic premise with the fixed point method is to use more bits to represent a position, so that you can keep track of things smaller than a pixel movement. So lets say you have pong which could store all values in a single byte as it is a single screen game. If you want the ball speed to be more precise than the granular pixel, a single byte will not work as it cannot store the values "between the pixels":

Code: Select all

int16_t ball_x, ball_y;
int16_t ball_vx, ball_vy;

	//....
	ball_vx = 128L;//set some velocity for x direction, roughly 1 pixel every other frame
	ball_vy = 308L;//set a larger speed for the y direction, some frame it will move 1 pixel, others 2, as it aliases the subpixel position to whole pixels
	//...
	while(1){
		WaitVsync(1);
		//...		
		ball_x += ball_xv;
		ball_y += ball_yv;
		//...
		uint8_t sprite_x = (uint8_t)((ball_x+127)>>8);//round to the nearest pixel value by adding ~1/2 pixel, and convert to 8 bit space
		uint8_t sprite_y = (uint8_t)((ball_y+127)>>8);
		sprites[0].x = sprite_x;
		sprites[0].y = sprite_y;
		//..
	}
	//....
That is a fairly crude example, and Bugz I am pretty sure uses subpixel precision so it could be a better more in depth example for usage in an actual game.

You can definitely use timers as well, though that creates limitations in some cases depending on the use case.
User avatar
Artcfox
Posts: 1382
Joined: Thu Jun 04, 2015 5:35 pm
Contact:

Re: Character speed control

Post by Artcfox »

Bugz uses fixed point, and I have a define called FP_SHIFT which defines how many bits to the right of the binary point to use. It boils down to when I store a pixel X, pixel Y, velocity X, velocity Y, I'm basically treating the TILE_WIDTH and TILE_HEIGHT as if they are 32 pixels by 32 pixels, rather than 8x8. and all the calculations and integrations happen as if the screen was 4 times as wide in pixels as it is, and then i round to the nearest screen pixel when i do the actual setting of the sprite's x and y. (Search for "round" in Bugz source code and you can see how I do the rounding.) I was using macros p2vt (pixel to vertical tile), p2ht (pixel to horizontal tile), vt2p (vertical tile to pixel), and ht2p (horizontal tile to pixel) for most of my conversions in the physics code, so I just made sure the shifts by FP_SHIFT happened in those macros, and the change to fixed point was largely transparent except for a couple edge cases where I needed to do something slightly different, like rounding.

Let me know if you have any questions.
Post Reply