Sign in to follow this  
grechzoo

Trouble figuring a way to incorporate basic momentum in SDL game

Recommended Posts

[color="#202020"][font="Verdana, Arial, Helvetica, sans-serif"]Okay I need big advice on how to incorporate some simple momentum into my player movement. I want him to speed up and slow down naturally and have a good jumping and falling arc etc.

I drew movement curves on graph paper, (I have a background in animation, so I know how to make it fluid and smooth.) So lateral + X and – X movement, as well as curves for jumping and falling (- Y and + Y)

I mapped out these curves to values (e.g. pixels per frame) and percentages through a 24 frame accceleration cycle (on the X) and 12 frame deceleration. (want to player to stop fast, but still stop naturally)

Here are the graphs that i mapped out:

lateral negative and positive X movement
[url="http://postimage.org/image/1xyxmohpg/"]http://postimage.org/image/1xyxmohpg/[/url]
Y jumping and falling
[url="http://postimage.org/image/1xz48tvok/"]http://postimage.org/image/1xz48tvok/[/url]

And here is my excel file. (numbers taken from plotting movement curves)
[url="http://postimage.org/image/1gltq11r8"]http://postimage.org/image/1gltq11r8[/url]

Basically I have no idea how to incorporate this properly into my program, taking into account my input handling, and how switching from left to right quickly could really cause slower response for example.

Is there an easier method that I can get my head around? Have I gone about this the totally wrong way?

I have tried reading physics books for programmers, even beginner ones but not once have I seen easy to read and understand code really walked through for me because trust me I need someone to hold my hand to understand it. Even this integration article that discusses euler and rk4 which is meant to be beginner friendly gave me no clues.

Any advice on where to go or what to do to try and find a way to overcome this problem would be sooooooooooo gratefully appreciated [img]http://forums.libsdl.org/images/smiles/icon_biggrin.gif[/img]

Thanks[/font][/color]
[color="#202020"][font="Verdana, Arial, Helvetica, sans-serif"]
[/font][/color]
[color="#202020"][font="Verdana, Arial, Helvetica, sans-serif"]ps:(I know I started a topic specifically asking for advice on this topic a short while ago before i started making this game, and through all the reading and research I still haven't found a clear clear way to grasp how to do this, I have tried doing all these graphs and problem solving a way to incorporate it in my own way but that hasn't worked :()[/font][/color]

Share this post


Link to post
Share on other sites
One issue that I see is that you are doing all of your calculations per FRAME. This means that depending on your draw rate your animations/physics will behave differently. You should be updating velocities and accelerations per some unit of time. This will ensure that any movements will happen at the same rate regardless of how fast the game draws. Now a simple way to introduce smooth player movement is to separate out the players total velocity with his current acceleration. So when the user presses D he is just adding a constant acceleration to the current velocity of the player (up to a maximum velocity). This will give the effect that the player object is "building up" momentum. To stop him you just check if his velocity is larger than zero and if the key isn't pressed and then subtract a deceleration form his velocity.

Now the jump arc can be done in the same way, however now when the user presses W you add a very high instant acceleration to the players velocity to give him the upward push and subtract a smaller gravitational deceleration.

It is VERY important that this is done with respect to TIME and not FRAME. Acceleration is a squared term which means that if you use frames a slight variation in draw rate can give you very different physics results.

So it would look like this kinda:

[code]
onKeyPressedEvent{

if(keyIsDown(D))
{
player.Velocity.x += playerAcceleration;
}

if(keyIsDown(W))
{
player.Velocity.y += playerJumpAcceleration;
}

}

onUpdate(int elapsedTime) <------TIME relient
{
if(player.Velocity.x > 0 && !keyIsDown(w))
{
player.Velocity -= playerDeceleration;
}

if(player.Velocity.y > 0)
{
player.Velocity.y -= gravityDeceleration;
}


player.position.x += player.velocity.x;
player.position.Y += player.velocity.y;
}
[/code]


I'm no physics buff and it's late so you might want to double check or look for another source. But that's a method you could use to model momentum. You would obviously need to tweak the values to suit your needs but this is a pretty intuitive way to approach this problem.

Share this post


Link to post
Share on other sites
truly i thank you for your take on this, it looks great, and very similar to what i had in mind, just couldn't get to the endpoint.

and thanks i will cap to time not frame for sure.

again really thank you for explaining it out so clearly, it has definitely reinvigorate my approach to this and i should hopefully get something playable hashed out today.

you are awesome :)

Share this post


Link to post
Share on other sites
[quote name='NickGomes' timestamp='1310883793' post='4836263']
One issue that I see is that you are doing all of your calculations per FRAME. This means that depending on your draw rate your animations/physics will behave differently. You should be updating velocities and accelerations per some unit of time. This will ensure that any movements will happen at the same rate regardless of how fast the game draws. Now a simple way to introduce smooth player movement is to separate out the players total velocity with his current acceleration. So when the user presses D he is just adding a constant acceleration to the current velocity of the player (up to a maximum velocity). This will give the effect that the player object is "building up" momentum. To stop him you just check if his velocity is larger than zero and if the key isn't pressed and then subtract a deceleration form his velocity.
[/code]


I'm no physics buff and it's late so you might want to double check or look for another source. But that's a method you could use to model momentum. You would obviously need to tweak the values to suit your needs but this is a pretty intuitive way to approach this problem.
[/quote]
Im still having some problems.

a problem i have tried many things to resolve. and that is when HOLDING the right key down. the xVelocity does not rise, it stays the same, the block moves at a constant speed instead of what should be accelerating at a constate rate.

the reason for this is that even though the event handling function is called tens if not hundred of times a second, if the right key is HELD the values aren't updated. However if i tap the right key, through each tap the speed of the player increases by the amount i set. but HOLDING i cant get this to work.

i have tried keystates, key events, or even a combination of both.

the line :
[code]case SDLK_RIGHT: xVelocity -= ACCELERATION; [/code]
if held, is simply set once, and the xVelocity stays constant. when really every time the event handling function is called i want this line executed if the right key is being held.

a snippet of the full event handling function and move function is below.
[code]


void Player::handleInput()
{

if (event.type == SDL_KEYDOWN)
{
switch ( event.key.keysym.sym)
{
case SDLK_UP: yVelocity -= playerBox.h / 3;
break;
case SDLK_DOWN: yVelocity += playerBox.h / 3;
break;
case SDLK_LEFT: xVelocity -= ACCELERATION;
break;
case SDLK_RIGHT: xVelocity += ACCELERATION;

default : ;
}
}

else if( event.type == SDL_KEYUP )
{
switch( event.key.keysym.sym )
{
case SDLK_UP: yVelocity += playerBox.h / 3;
break;
case SDLK_DOWN: yVelocity -= playerBox.h / 3;
break;
case SDLK_LEFT: xVelocity += ACCELERATION;
break;
case SDLK_RIGHT: xVelocity -= ACCELERATION;
break;

default : ;
}
}


Uint8 *playKeystates = SDL_GetKeyState(NULL);

if (playKeystates[SDLK_ESCAPE])
{
isPaused = true;
}

if (playKeystates[SDLK_d])
{
isDead = true;
}

if (playKeystates[SDLK_SPACE])
{
Mix_PlayChannel( -1, jumpSound, 0 );
}

}



void Player::move(Uint32 deltaTime)
{
//check platform collisions




//move player
playerBox.x += xVelocity * (deltaTime / 1000.f);


playerBox.y += yVelocity * (deltaTime / 1000.f);


//constrain to level
if ( ( playerBox.x < 0) || ((playerBox.x + playerBox.w) > LEVEL_WIDTH) )
{
isDead = true;
}

if ((playerBox.y < 0) || ((playerBox.y + playerBox.h) > LEVEL_HEIGHT))
{
isDead = true;
}

//check win collisions
if (((playerBox.x + playerBox.w) >= winRect.x) && (playerBox.y <= winRect.y+winRect.h))
{
isWin = true;
}


}

[/code]


I know im useless at this, i should be better at problem solving, but soemtime when i have been working on something for a while my brain just blocks up.

Share this post


Link to post
Share on other sites
Normally you will only get one SDL_KEYDOWN event even if you hold the key or not. So instead of updating the velocity when you receive an event you can update the velocity as often as you update the player position.

Share this post


Link to post
Share on other sites
[quote name='Wooh' timestamp='1311257644' post='4838454']
Normally you will only get one SDL_KEYDOWN event even if you hold the key or not. So instead of updating the velocity when you receive an event you can update the velocity as often as you update the player position.
[/quote]

thanks, yeah this was a key point to what i decided to do.

on the key events i set up key down and up boolean flags.

then in the main loop called a function to edit the x and y velocities based on those flags. this way the right key will continually be registered as true until it is released and the flag is turned to false. each time through the loop if the right key was still true, xVelocity was increase.

got a very nice smooth run in now, with easily configurable momentum using a weight variable.

it was tough to get my head around so i thank everyone who helped. really does feel great knowing i've finally figured it out.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this