GP2X Time Based Movement


kzar

Still Fresh
Joined
Nov 8, 2005
Messages
26
Hi I am having a bash at making myself a game on the gp2x but I have a question.

SDL_GetTicks() returns a Uint32 which is a unsigned whole number stored in 4 bytes I think.
My entity's position and velocity and acceleration are stored as int's.
I made the delta this: Uint32 delta = time_passed * 0.5; (The 0.5 is pulled out of a hat but it meens that if things are moving to fast I can make it smaller I hope)

Anyway my problems are that because the 0.5 is a double and the rest are integers I get a warning. Also if I set it to 0.3 I get no movement, 0.4 I get very slow movement and then 0.5 I get far too fast movement.

Anyway my question is am I doing this in a stupid way / how do you do it? As well because I heard that you shouldn't really use float's because the gp2x doesn't use them as well as integers but is it the same with doubles?

Here are some snipplets of how I am doing it.

This is my gameloop so you can see how I am figuring out the time_passed
Code:
	while (running == true)
	{
		Uint32 last_time = current_time;
		current_time = SDL_GetTicks();
		Uint32 time_passed = current_time - last_time;
		
		get_input(&player);
		player.draw(screen);
		SDL_Flip(screen);
		player.update(time_passed);
	}

This is the update function for my entity that figures out how much it should move
Code:
void entity::update(float time_passed)
{
	Uint32 delta = time_passed * 0.5;
	
	int acc_x = force_x / mass;
	int acc_y = force_y / mass;
	
	vel_x += acc_x * delta;
	vel_y += acc_y * delta;
	
	pos_x += vel_x * delta;
	pos_y += vel_y * delta;
}

Thanks

edit: I think this should be in the "I need help (dev stuff only)" section actually but I don't think I can move it now, sorry.
 
For 0.5 you could avoid the warning with

Code:
Uint32 delta = time_passed / 2;

But I think the real problem is that time_passed is probably small and when you cast the double back to an int, the result comes out as zero for 0.3
 
Am I doing it in a ok way though? I need to tweak the number though I suppose.
 
Why not do: -

Code:
	Uint32 delta = (Uint32)(time_passed * 0.5);// Note: should explicitely cast to avoid warnings

	// Or
	// Uint32 delta = (Uint32)(time_passed >> 1); // bit-shift for speed


But having said that I think you should be using floats for acceleration and velocity (or fixed-point arithmetic), as these may require sub-pixel accuracy (I'm making the assumption pos_x / pos_y are pixel co-ordinates).

Searched forum and found these posts which may be of interest: -

http://www.gp32x.de/board/index.php?showt...amp;hl=velocity
http://www.gp32x.de/board/index.php?showt...amp;hl=velocity


[edit: attempted to make more sense]
[edit: added links]
 
Last edited by a moderator:
You can determine the number of Ticks-per-second, and then given the number of elapsed ticks react accordingly. ie: So that things move at a determined speed, not 'too fast' or 'too little'.

ie: you could just 'spin' until so many ticks have passed, then do your calculations and render, then spin some more. ie: If theres 1000 ticks per second, then maybe you want to go 1000/20 in a spin, so that you get your code to run 20-times-per-second..

/me just woke up though :)

jeff
 
kzar posted on Jul 9 2006 at 04:45 AM said:
This is the update function for my entity that figures out how much it should move
Code:
void entity::update(float time_passed)
{
	Uint32 delta = time_passed * 0.5;
	
	int acc_x = force_x / mass;
	int acc_y = force_y / mass;
	
	vel_x += acc_x * delta;
	vel_y += acc_y * delta;
	
	pos_x += vel_x * delta;
	pos_y += vel_y * delta;
}
Divide last, but covert it to a fixed point multiply by reciprocal for speed:
Code:
void entity::update(Uint32 delta_t)
{
  Uint32 rmass = (1<<16) / mass;
  Uint32 tscale = (Uint32)((1<<16) * 0.5); /* silly for 0.5, but now 0.3 will work */ 

  Int32 acc_x = force_x * rmass >> 16;
  Int32 acc_y = force_y * rmass >> 16;

  delta_t *= tscale;
  vel_x += acc_x * delta_t >> 16;
  vel_y += acc_y * delta_t >> 16;

  pos_x += vel_x * delta_t >> 16;
  pos_y += vel_y * delta_t >> 16;
}
You may need to decrease the 16 depending on the size of the numbers you're dealing with. And you can probably get more accurate pos values... IIRC:
Code:
void entity::update(Uint32 delta_t)
{
  Uint32 rmass = (1<<16) / mass;
  Uint32 tscale = (Uint32)((1<<16) * 0.5);

  Int32 acc_x = force_x * rmass >> 16;
  Int32 acc_y = force_y * rmass >> 16;

  Int32 delta_vx = acc_x * delta_t >> 16;
  Int32 delta_vy = acc_y * delta_t >> 16;

  delta_t *= tscale;
  pos_x += (vel_x + (delta_vx >> 1)) * delta_t >> 16;
  pos_x += (vel_y + (delta_vy >> 1)) * delta_t >> 16;

  vel_x += delta_vx;
  vel_y += delta_vy;
}
Keeping all your numbers in fixed point isn't a bad idea either, and sleeping for some time between iterations. Better to sleep than spin, might save power.
 
Last edited by a moderator:
rabidcow posted on Jul 10 2006 at 07:44 PM said:
kzar posted on Jul 9 2006 at 04:45 AM said:
This is the update function for my entity that figures out how much it should move
Code:
void entity::update(float time_passed)
{
	Uint32 delta = time_passed * 0.5;
	
	int acc_x = force_x / mass;
	int acc_y = force_y / mass;
	
	vel_x += acc_x * delta;
	vel_y += acc_y * delta;
	
	pos_x += vel_x * delta;
	pos_y += vel_y * delta;
}
Divide last, but covert it to a fixed point multiply by reciprocal for speed:
Code:
void entity::update(Uint32 delta_t)
{
  Uint32 rmass = (1<<16) / mass;
  Uint32 tscale = (Uint32)((1<<16) * 0.5); /* silly for 0.5, but now 0.3 will work */ 

  Int32 acc_x = force_x * rmass >> 16;
  Int32 acc_y = force_y * rmass >> 16;

  delta_t *= tscale;
  vel_x += acc_x * delta_t >> 16;
  vel_y += acc_y * delta_t >> 16;

  pos_x += vel_x * delta_t >> 16;
  pos_y += vel_y * delta_t >> 16;
}
You may need to decrease the 16 depending on the size of the numbers you're dealing with. And you can probably get more accurate pos values... IIRC:
Code:
void entity::update(Uint32 delta_t)
{
  Uint32 rmass = (1<<16) / mass;
  Uint32 tscale = (Uint32)((1<<16) * 0.5);

  Int32 acc_x = force_x * rmass >> 16;
  Int32 acc_y = force_y * rmass >> 16;

  Int32 delta_vx = acc_x * delta_t >> 16;
  Int32 delta_vy = acc_y * delta_t >> 16;

  delta_t *= tscale;
  pos_x += (vel_x + (delta_vx >> 1)) * delta_t >> 16;
  pos_x += (vel_y + (delta_vy >> 1)) * delta_t >> 16;

  vel_x += delta_vx;
  vel_y += delta_vy;
}
Keeping all your numbers in fixed point isn't a bad idea either, and sleeping for some time between iterations. Better to sleep than spin, might save power.

Cool reply thanks. I was wondering what delta_t was for though as you didn't declare it or set it up to start with?

Also I was wondering, I know my code is kind of naff but I made acceleration and volocity floats and it seemed to work except movement in negative directions seemed to be a lot faster than positive ones?! I was wondering if you maybe knew why?

Thanks again
 
Last edited by a moderator:
kzar posted on Jul 10 2006 at 03:50 PM said:
Cool reply thanks. I was wondering what delta_t was for though as you didn't declare it or set it up to start with?
I changed the name of the parameter. ;)
kzar posted on Jul 10 2006 at 03:50 PM said:
Also I was wondering, I know my code is kind of naff but I made acceleration and volocity floats and it seemed to work except movement in negative directions seemed to be a lot faster than positive ones?! I was wondering if you maybe knew why?
I'd guess rounding error, but I dunno. -1/2 = ...11111111.1, +1/2 = ...00000000.1 Chop off the .1 and only one of them has any effect. With a really tight loop, you might be getting mostly 1 from SDL_GetTicks with an occasional 2 (or higher, maybe on a task switch), so most but not all of your increments get rounded to zero in the positive direction.

If that's it, add a sleep in the loop and use floating or fixed point for the temporary values in update to make the error smaller.
 
Last edited by a moderator:
I move objects based on a frame interval; e.g. move this object _px up or down on the Y axis, _px left or right on the X, et cetera .. every certain number of frames. So movement slower than 1 px per second, which at 60 FPS+ can be very fast, would occur just every 3 frames or so. This avoids using decimal multiplication or division which are quite slow on the ARM9.
 
Back
Top