Moving An Image Around With Sdl


Sadistictoaster

Still Fresh
Joined
Sep 12, 2006
Messages
22
The following code will move an image around the screen , but , for some reason , the movement is quite jerky : often I'll push the stick all the way down , but the image wil not move : so I have to move it away , and back again before it'll register.

I've checked the GPX2 with some other games , and no problems there : so the stick itself is not at fault.

Any ideas? It's really winding me up.



drawSprite(playerbot, screen, 0, 0, playerx, 220, playerbot->w, playerbot->h);
if ((SDL_PollEvent(&event)) !=1)
{
switch (event.type)
{
case SDL_JOYBUTTONDOWN:
switch(event.jbutton.button)
{
case 2: //right
playerx=playerx-2;
case 6: //left
playerx=playerx+2;
break;
}
}
}
 
Poll events and cases are nasty. Use this instead:

Code:
SDL_JoystickUpdate();
up = SDL_JoystickGetButton(joystick, GP2X_BUTTON_UP);
if(up) // move up;

- Alex
 
What Alex here says is more or less true, but that's not the real problem here. An SDL_JOYBUTTONDOWN event only fires once when you're pushing the button down. Holding a button down won't generate any more of these events. That means you have to move the button back and then push it down again to move your player. Using Alex's method will keep your player moving while holding down the directional stick, but that gives way to even more problems:

The speed at which the player moves is currently dependent on the speed at which your main loop runs. This is definitely not a constant; sometimes the input polling takes longer than usual, sometimes the CPU might hiccup, whatever. This results in jerky and unpredictable movement. Also, on different systems the loop will run either much faster or much slower, making it impossible to predict how fast your game will run.

What you'll want is to use a time factor to determine how far the player moves at each loop iteration. SDL offers the SDL_GetTicks() function to determine the number of milliseconds passed since the start of the program. By retrieving the timestamp at each loop iteration and remembering the timestamp of the previous iteration, you can calculate the number of milliseconds passed since the last update. You can then use this to calculate the number of units that the player has to move by multiplying the player's speed by this time difference.

(One thing to watch our for though, is that these time differences are usually fractions of seconds. Fractions are normally represented by float variables, but due to the GP2X's lack of an FPU, you'll want to avoid these as much as possible. In this next example, the time difference is represented in milliseconds, which adds a factor of 1000 to every calculation done with it.)

Combined with Alex's tip, your code would look something like this:
Code:
// Declare our time variables
Uint32 lastUpdate, time, timeDelta;

// Speed at which the player moves, in pixels per second
int playerSpeed = 20;

// Initialize lastUpdate to the current timestamp
lastUpdate = SDL_GetTicks();

// Main loop
while ( some condition )
{
	// Get the current timestamp
	time = SDL_GetTicks();
	
	// Calculate the number of milliseconds since the last update
	timeDelta = time - lastUpdate;
	
	// Update lastUpdate to the current timestamp
	lastUpdate = time;
	
	// Update and check joystick state
	SDL_JoystickUpdate();
	if ( SDL_JoystickGetButton( joy, 2 ) )
	{
		// Move the player left. 
		// Note that timeDelta is in milliseconds instead of seconds to avoid the 
		// need for floats. This results in playerx to be multiplied by a factor 
		// of 1000, so we need to divide by 1000 when using playerx.	
		playerx = playerx - playerSpeed * timeDelta;
	}	
	if ( SDL_JoystickGetButton( joy, 6 ) )
	{
		// Move the player right
		playerx = playerx + playerSpeed * timeDelta;
	}

	// Do our drawing stuff. Note that playerx gets divided by 1000.
	drawSprite(playerbot, screen, 0, 0, playerx / 1000, 220, playerbot->w, playerbot->h);
}
This code is untested and incomplete. Some variables are undeclared and 'some condition' obviously isn't a proper loop condition.
 
That's overly complicated for moving a sprite on the screen. If you want time coordination, a frame limiter will suffice. Of course there may be some cpu hiccups at times, but honestly those things happen to modern PC games today, so why should we be so paranoid about it? All over-eager error checking takes the fun out of game programming :(

- Alex
 
I have been meaning to update my sdl test program with the below code for input, this is what I use now.

add the following in your function (or global)

Code:
bool keysHeld[323] = {false};

then when you want to read the input add the following. this example reads PC (keyboard and mouse) and GP2X input as i do most of my testing on pc first.

Code:
if (SDL_PollEvent(&event))
{
	 if (event.type == SDL_KEYDOWN)
	 {
		 keysHeld[event.key.keysym.sym] = true;
	 }
	 if (event.type == SDL_KEYUP)
	 {
		 keysHeld[event.key.keysym.sym] = false;
	 }
	 if(event.type == SDL_JOYBUTTONDOWN)
	 {
		 keysHeld[event.jbutton.button] = true;
	 }
	 if(event.type == SDL_JOYBUTTONUP)
	 {
		 keysHeld[event.jbutton.button] = false;
	 }
	 if(event.type == SDL_MOUSEBUTTONDOWN)
	 {
		 keysHeld[event.button.button] = true;
	 }
	 if(event.type == SDL_MOUSEBUTTONUP)
	 {
		 keysHeld[event.button.button] = false;
	 }
}

// add your pc/gp2x keys here
if ( keysHeld[SDLK_UP] || keysHeld[GP2X_BUTTON_UP])
{
	 // do stuff here
}

if you want to clear the input write a function that clears keysHeld. Hope that helps
 
Back
Top