Archived

This topic is now archived and is closed to further replies.

smooth DX9 sprite animation?

This topic is 5125 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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 app

for(;;)
{
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]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
i just use a static variable, say lastTime, that i save to at the end of the function. So it''ll be like this....

curTime = timeGetTime();
deltaT = curTime - lastTime;

//do whatever needs done here

lastTime = curTime;
return 0;

this way, each time the function is called, the object is moved at the velocity. So, for example:

Vector frameMove = velocity * deltaT;
pos += frameMove;

now, your velocity is no longer dependent on the framerate.

Have Fun

Share this post


Link to post
Share on other sites
Thanks guys! You''ve both been very helpful!

MichaelW - I read that page you gave the URL for. That is something I''m definately going to explore. It was just what I needed.

personwholives - I think your suggestion is where I''ll start out from. From there I can start adding more advanced stuff...

Thanks again guys!

Brandon

Share this post


Link to post
Share on other sites
It''s one of the D3D extention things... A place to start is in the DirectX documentation. Assuming you''re using DX9, go to:
DirecX Graphics->Reference->Direct3D Extension->Interfaces->ID3DXSprite.

Here''s where I actually create the sprite:

// There are a few specific DX items used below.

// gpd3dDevice is the device (duh).

// piTexShot is a PDIRECT3DTEXTURE9 (global).

// pShotSprite is a LPD3DXSPRITE (also global).


if(D3DXCreateTextureFromFileEx(g_pd3dDevice,"shot.bmp",0,0,1,0,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED,D3DX_FILTER_NONE,D3DX_DEFAULT,0xFFFF00FF,NULL,NULL,&piTexShot)!= D3D_OK)
{
MessageBox(m_hWnd,"Failed to load texture shot.bmp!","Awww Crap!", MB_OK);
}
D3DXCreateSprite(g_pd3dDevice,&pShotSprite);


If I remember correctly, you''ll need to include 3d3x9.h for this.

Here''s the rendering bit:

g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );

g_pd3dDevice->BeginScene();

pShotSprite->Begin();
// This is the function to draw the sprite to the screen.

// There is also DrawTransform() which can apply a matrix.

// Also, note the use of shotVector here. It is a D3DXVECTOR2.

// Basically, it just stores the screen coords of the sprite.

pShotSprite->Draw(piTexShot,NULL,NULL,NULL,0,&shotVector,0xFFFFFFFF);
pShotSprite->End();

g_pd3dDevice->EndScene();

g_pd3dDevice->Present( NULL, NULL, NULL, NULL );


I hope that was clear enough. If not, let me know and I''ll try to explain better. One thing I learned a lot from was this article:
http://www.gamasutra.com/features/20010629/geczy_01.htm
But be warned that it deals with DX8. Also, I don''t remember how much of it I used. I think I got some concepts from it but had to research most of the code from the DX documentation. In other words, it''s a good article, but don''t let it confuse you with regards to DX9 since I believe some stuff has changed...

Good Luck and let me know if I can help more!

Brandon

Share this post


Link to post
Share on other sites
haha thanx, i didnt realize u were actually using sprites, i assumed u were using surfaces and just called em sprites cuz thats easier, maybe i should just switch to sprites... thanx :-D

Share this post


Link to post
Share on other sites
Heh... Actually, that was my original intention, but then I found the DX sprite support (mainly from that article) and decided, what the heck! So that''s how that design decision was made...

Brandon

Share this post


Link to post
Share on other sites
Has anyone else installed the DX9 SDK Summer 2003 update? Microsoft seem to have completely changed the ID3DXSprite and ID3DXFont interfaces, which has screwed up all my code.

For example, the new ID3DXSprite.Draw function looks like this:
HRESULT Draw(          LPDIRECT3DTEXTURE9 pTexture,
CONST RECT *pSrcRect,
CONST D3DXVECTOR3 *pCenter,
CONST D3DXVECTOR3 *pPosition,
D3DCOLOR Color
);

Share this post


Link to post
Share on other sites
Ademan555 - Hey! Shakespeare rox! I''m a big fan of Hamlet, read it countless times...

Useless Hacker - I''ve not installed that update yet... Looks like they may have simplified things a bit.. maybe. How much of a pain is it to use a D3DXVECTOR3? I''ve yet to try one of those... How much did they change in that? Any other critical items? Thanks for the heads up!

Brandon

Share this post


Link to post
Share on other sites
hahah, just got back from school, and looked at ur texture loading code...wow LOL, i like the caption on the message box :-D, but just to tell yah, i read that checking if ur HRESULT function == D3D_OK is a bad plan, because theres more than 1 successful HRESULT such as S_OK and crap like that....just a suggestion :-D

Share this post


Link to post
Share on other sites
Heh, thanks for the tip. I''m aware of the variety of results that DX can give. As for this particular instance, I know it works because I''ve seen it pop up, hehe... Also, I had to "edit" it a bit, the message in the actual code isn''t PG rated... LOL.

Brandon

Share this post


Link to post
Share on other sites
quote:
Original post by Rattlehead
Useless Hacker - I''ve not installed that update yet... Looks like they may have simplified things a bit.. maybe. How much of a pain is it to use a D3DXVECTOR3? I''ve yet to try one of those... How much did they change in that? Any other critical items? Thanks for the heads up!
Well, I haven''t quite sussed it yet , but it looks like the Draw function adds it to a list and then all the sprites are drawn together when you call End. However, I can''t figure out how to rotate and stretch a sprite which was easy before.

Share this post


Link to post
Share on other sites