smooth DX9 sprite animation?

Started by
26 comments, last by Rattlehead 20 years, 4 months ago
Hi all! This is my first post here, so be gentle with me! Anyway, I''ve been tinkering with DX9 in C++ and have managed to create a sprite of a ball and I can make it bounce around the screen. But the problem I''m having is that it doesn''t animate smoothly. I know this has to be something simple I''m missing. It makes sense that it''s not smooth since the screen coords between frames are fairly far apart when it''s moving fast. But how do I make this smoother without simply slowing it down? Maybe there isn''t a way around this? I think there should be though. I mean, consider a game like Gradius, for example. Those sprites move across the screen quickly, and they don''t jump from point A to point B, they just move there fast. Which, after typing this, I see another problem I''m going to have. When I move the sprite, I''m just changing a D3DXVECTOR2 object''s x and y properties and then using these when I draw the sprite. So, if the sprite were a bullet, for example, and it were to move from one side of a target to the other due to it''s high speed, it wouldn''t actually collide with it. It would just disappear from one side and appear on the other. OK, so then I have two problems. Both could be solved by using a different method to move and draw the sprite, perhaps, but I don''t know another method. At present, I just update the vector''s x and y coords each frame and then draw the sprite using that vector with ID3DXSprite->Draw(). So, A: How do you animate a sprite''s movement smoothly? And B: How do you animate it so that it''s path actually passes through space rather than jumping from point to point based on it''s velocity and direction? Thanks in advance for any help guys! :D Rattlehead
Advertisement
actually, they do jump from point a to point b, you just need to choose a jump distance relative to your speed, though it sounds like you were doing this...
When General Patton died after World War 2 he went to the gates of Heaven to talk to St. Peter. The first thing he asked is if there were any Marines in heaven. St. Peter told him no, Marines are too rowdy for heaven. He then asked why Patton wanted to know. Patton told him he was sick of the Marines overshadowing the Army because they did more with less and were all hard-core sons of bitches. St. Peter reassured him there were no Marines so Patton went into Heaven. As he was checking out his new home he rounded a corner and saw someone in Marine Dress Blues. He ran back to St. Peter and yelled "You lied to me! There are Marines in heaven!" St. Peter said "Who him? That's just God. He wishes he were a Marine."
Hi! Thanks for the response.

Yeah, I realize that in reality, it can only draw it at a given point and then draw it at another point in the next frame...

It''s kind of difficult to describe just what it is that I want to accomplish... It''s like the animation is too obvious. Maybe I just need to slow it down some... I dunno. I keep getting the feeling that I''m missing something stupid. :-D

Rattlehead
Post some code if you can, and maybe there is something you''re missing. How many FPS are you getting? I''d say if you''re getting good FPS, it''s just not possible without adding extra features. You may want to add an anti-aliasing gaussian blur to it. As the sphere moves, another sphere or set of spheres lag behind, with increasingly darker colors, based on the speed. Simple, but makes a big difference in the quality. Perhaps your sphere (ball) is too crisp in the first place. Maybe it needs some rough edges (anti-aliasing the texture). Just some thoughts.

Chris
Chris ByersMicrosoft DirectX MVP - 2005
The reason your ball would appear jerky is because your framerate is too low. Are imposing a limit?
Hi guys! I guess the next step will be to stick a frame counter in there to see just what my framerate is... Then maybe I''ll know more.

Supernat02 - That gausian blur idea sounds pretty cool. I might try that out whether it fixes it or not... What''s the basic run-down on how you''d do that? Just calculate the positions between point A and point B and draw the "ghost images" there?

jack_1313 - I think I read somewhere that the default for DX is to limit the framerate to whatever the vertical refresh rate is. But there was a way to remove that cap. I don''t recall what it was right off and I don''t have the code up right now... I''ll have to get back to you on that...


Thanks for the suggestions guys. When I get a chance I''ll stick a fps counter in and see what I''ve got...

Rattlehead

Ok, I added a crude fps counter and I'm getting 76-78 fps. Now, when I started goofing off with this, I used the VS.NET DX wizard to create the framework of this program. It creates a loop where the program actually runs:

// Message loop to run the appfor(;;){    if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )    {        if( FALSE == GetMessage( &msg, NULL, 0, 0 ) )            break;        if( 0 == TranslateAccelerator( m_hWnd, hAccel, &msg ) )        {            TranslateMessage( &msg );            DispatchMessage( &msg );        }    }    else    {        // Update the time variables        m_fTime        = DXUtil_Timer( TIMER_GETAPPTIME );        m_fElapsedTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );        // This app uses idle time processing for the game loop        if( FAILED( FrameMove() ) )            SendMessage( m_hWnd, WM_DESTROY, 0, 0 );        if( FAILED( Render() ) )             SendMessage( m_hWnd, WM_DESTROY, 0, 0 );            Sleep( 20 );    }} 


The loop contains that Sleep() in there to keep it in control. If I comment that out, I get 335 fps. Which is a bit much, methinks.

When I was talking about allowing the FPS to go above the vertical refesh rate, that has to do with the D3DPRESENT_PARAMETERS you use when you create the D3D device. If you set this:

// d3dpp is the D3DPRESENT_PARAMETERS struct...d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; 


then it will uncap the framerate and allow a framerate above the vertical refresh rate. If I comment that line out, it uses the default and I end up with 60 fps (I have a 60Hz refresh rate).

In discussing this, I may have hit on an idea though. As it stands, I just store the horizontal and vertical movement of the sprite. Each frame I add or subtract the movement numbers from the screen coords. I also add the gravity value to the vertical movement. This way, if the sprite is moving up, then it moves up less each frame until it begins to drop. If it's dropping, it accelerates until it hits the terminal velocity I have set for it.

Here's the function that calculates the sprite's position on screen:
// This is the function called to calculate the screen coords// of the sprite. The sprite is referred to as the "shot". // This function is called once each frame. So, the faster// frames are drawn, the faster the sprite moves. THIS IS BAD...// shotVector is the D3DXVECTOR2 used to store the screen coords// of the shot.// vMovement is the vertical movement component. Positive if// the shot is moving down, negative if it's moving up.// hMovement is the horizontal movement component. Positive if// the shot is moving right, negative if it's moving left.// terminalV is the termial velocity. Basically vMovement can't// go above this.// gravity is the amount added to vMovement each frame.// hFriction is the amount subtracted from hMovement every frame// in which the shot is on the "ground".// clientWidth and clientHeight are the width and height of the// drawing area and the sprite is 10 pixels square.void CMyApplication::CalcShotPos(){    // To keep it going, we reset it all if it gets near 0...    // If it's got downward inertia...    if(vMovement < 1)    {	// And if it can't bounce back up...	if((vMovement*-1) < gravity)	{	    // And if it's not rolling any more...            if((hMovement < 1) && (hMovement > -1))	    {		shotVector.x = rand()%(int)clientWidth;		shotVector.y = rand()%(int)clientHeight;		hMovement = rand()%50;	        vMovement = 0;		return;	    }	}    }    // Apply gravity...    vMovement += gravity;    if(vMovement > terminalV)    {	vMovement = terminalV;    }    // Determine if shot will hit boundaries this time...    if(hMovement >= 0)    {	// Will it go off the right side?	        if((shotVector.x + hMovement) > clientWidth)        {            shotVector.x = (clientWidth-10);	    hMovement = (hMovement*-1);        }            else // If it WON'T go off the right side...        {	    shotVector.x += hMovement;        }    }    else    {   // Will it go off the left side?        if((shotVector.x + hMovement) < 0)        {            shotVector.x = 0;            hMovement = (hMovement*-1);        }        else // If it WON'T go off the left side...        {	    shotVector.x += hMovement;        }    }    // Will it hit the bottom?    if((shotVector.y + vMovement) > (clientHeight-10))    {	shotVector.y = (clientHeight-10);	// Will it be able to bounce back up?	if(vMovement < gravity)	{	    vMovement = 0;	}	else	{	    vMovement = (vMovement*-1);	}	// Apply friction	if(hMovement != 0)	{	    if(hMovement > 0)	    {	        hMovement -= hFriction;	    }	    else	    {		hMovement += hFriction;            }	}    }    else    {		shotVector.y += vMovement;    }}


Did I mention that it was crude?

Maybe there's a way to actually draw the sprite in all of the "in between" positions and have it's speed dictated by it's velocity (as it should be). I'm not sure exactly what I'm saying here. It's just a vague idea right now. Basically, I'm getting the idea that my method of animating the sprite is too crude to produce good results. But what is the better way?

Brandon

[edited by - Rattlehead on December 3, 2003 11:41:46 AM]
you need to take into account the delta time that passes with each update tick of your main logic loop. Pass this delta time into all the functions which are involved in movement, so it can calcuate the current postiton based upon the current time.

There are many timmers available, but for now try TimeGetTime(), this returns the number of miliseconds which has passed since your machine started up.

Since your modeling projecticle dynamics you might want to use the physics formula describing its behavior, which integrates gravity as well.

-ddn
Hi! Thanks for the tips... Unfortunately, I lack the experience to implement them...

If you could just elaborate a bit on how to use the delta time and maybe point me toward a simple physics algorithm?

This isn''t a serious project, by the way. Rather, I''m trying to further my understanding of DirectX in a C++ environment. At this point, I''m just starting out...

Again, thanks for helping out!

Brandon
I''m no expert but I think this article covers what they mean by delta time:
http://www.mvps.org/directx/articles/implementing_steady_motion.htm

HTH,
Michael

This topic is closed to new replies.

Advertisement