Jump to content
  • Advertisement
Sign in to follow this  
PumpkinPieman

Sprite Animation Timing

This topic is 4892 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

I made a quick sprite class that allows me to read in a simple format and animate it based on a time interval, however for some reason when matched with the intervals from the original gif file they seem off. A lot. The one in the program seems somewhere around one and a half times as fast as the gif and I can't really explain it. If you need an example here is a compiled version, and here is the original gif. The interval that is used for all frames is 50ms. Any ideas what may be causing this? Thanks
struct _sprfheader;

struct _sprfaction;
struct _sprfframe;

struct _spraction;
struct _sprframe;

struct _sprfheader{
	DWORD	id; // SPRL
	char	texture[256];
	DWORD	nactions;
	DWORD	nframes;
};

struct _sprfaction{
	char	actionname[50];
	DWORD	nframes;
	D3DXVECTOR2 center;
};

struct _sprfframe{
	D3DXVECTOR2	position;
	D3DXVECTOR2 textureoffset;
	D3DXVECTOR2	texturesize;
	D3DXVECTOR2	center;
	float	rotation;
	DWORD	duration;
	char	depth;
};


struct _spraction : _sprfaction{
	_sprframe * frames;
};

struct _sprframe : _sprfframe{
	_sprframe* next;
};

class cSpriteAnimation{
private:
	cGraphics*	m_pGraphics;
	D3DXMATRIX	m_mat;
	

	cTexture	m_texture;

	_sprframe*	m_currentframe;
	float		m_currenttime;

	stdext::hash_map<std::string, _spraction*>	m_actions;
//	std::map<const char*, _spraction*>	m_actions;

public:
	cSpriteAnimation();
	~cSpriteAnimation();
	

	void SetMatrix(D3DXMATRIX* mat);

	bool Create(cGraphics* pGraphics, LPCSTR filename);
	void Draw(DWORD timeoffset, float distance = 0.0f);
	bool SetAction(const char* action);
	void Free(void);

};

	cSpriteAnimation::cSpriteAnimation()
	{
		Free();
	};

	cSpriteAnimation::~cSpriteAnimation()
	{
		Free();
	};

	void cSpriteAnimation::SetMatrix(D3DXMATRIX* mat)
	{
		if(mat != NULL)
			m_mat = (*mat);
	};

	bool cSpriteAnimation::Create(cGraphics* pGraphics, LPCSTR filename)
	{
		Free();

		FILE* fp;
		_sprfheader		sprfileheader;
		_sprfaction*	sprfileaction;
		_sprfframe*		sprfileframes;

		_spraction*		sprtempaction;
		_sprframe*		sprtempframes;

		bool ret = true;

		if((m_pGraphics = pGraphics) == NULL)
			return false;

		if((fp = fopen(filename, "rb")) == NULL)
			return false;

		if((fread(&sprfileheader, sizeof(sprfileheader), 1, fp) != 1) || (sprfileheader.id != 'SPRL')){
			ret = false;
		}

		if(m_texture.Load(m_pGraphics, sprfileheader.texture) == false){
			ret = false;
		}

		sprfileaction = new _sprfaction[sprfileheader.nactions];
		sprfileframes = new _sprfframe[sprfileheader.nframes];

		if(fread(sprfileaction, sizeof(_sprfaction)*sprfileheader.nactions, 1, fp) != 1 ||
			fread(sprfileframes, sizeof(_sprfframe)*sprfileheader.nframes, 1, fp) != 1){
			ret = false;
		}

		fclose(fp);

		if(ret == true){
			DWORD framecountdone = 0;
			for(DWORD iact = 0; iact < sprfileheader.nactions; iact++){
				sprtempaction = new _spraction;
				memcpy(sprtempaction, &sprfileaction[iact], sizeof(_sprfaction));
				sprtempframes = new _sprframe[sprtempaction->nframes];
				sprtempaction->frames = sprtempframes;

				sprtempframes[sprtempaction->nframes-1].next = &sprtempframes[0];
				for(DWORD ifrm = 0; ifrm < sprtempaction->nframes; ifrm++){
					memcpy(&sprtempframes[ifrm], &sprfileframes[framecountdone + ifrm], sizeof(_sprfframe));

					if(ifrm < sprtempaction->nframes - 1)
                        sprtempframes[ifrm].next = &sprtempframes[ifrm + 1];
				}
				framecountdone += sprtempaction->nframes - 1;
				m_actions[sprtempaction->actionname] = sprtempaction;
			}
		}

		delete [] sprfileaction;
		delete [] sprfileframes;

		return ret;
	};

	void cSpriteAnimation::Draw(DWORD timeoffset, float distance)
	{
		if(m_currentframe == NULL)
			return;

		m_currenttime += timeoffset;

		while(m_currenttime > m_currentframe->duration){
			m_currenttime -= m_currentframe->duration;
			m_currentframe = m_currentframe->next;
		}
	

		D3DXMATRIX	mat;
		D3DXMATRIX	trans;
		RECT		mask;

		D3DXVECTOR3 tempcenter(m_currentframe->center.x, m_currentframe->center.y, 0.0f);
		D3DXVECTOR3 temptranslation(m_currentframe->position.x, m_currentframe->position.y, distance);	// Fix it for depth

		D3DXQUATERNION temprotation;
		D3DXQuaternionRotationYawPitchRoll(&temprotation, 0.0f, 0.0f, m_currentframe->rotation);

		D3DXMatrixTransformation(&mat, &tempcenter, NULL, NULL, &tempcenter, &temprotation, &temptranslation);

		SetRect(&mask, (int)m_currentframe->textureoffset.x, (int)m_currentframe->textureoffset.y, (int)m_currentframe->textureoffset.x + (int)m_currentframe->texturesize.x, (int)m_currentframe->textureoffset.y + (int)m_currentframe->texturesize.y); 

//		D3DXMatrixMultiplyTranspose(&mat, &mat, &m_mat);
		m_pGraphics->GetSprite()->SetTransform(&mat);
		m_pGraphics->GetSprite()->Draw(m_texture.GetTexture(), &mask, NULL, NULL, 0xFFFFFFFF);

		return;
	};

	bool cSpriteAnimation::SetAction(const char* action)
	{
		if(m_actions.count(action) == 0){
			m_currentframe = NULL;
			return false;
		}

		m_currentframe = &m_actions[action]->frames[0];
		return true;
	};

	void cSpriteAnimation::Free(void)
	{
		m_pGraphics = NULL;
		ZeroMemory(&m_mat, sizeof(D3DXMATRIX));
		
		m_currentframe = NULL;;
		m_currenttime = 0;

		m_texture.Free();
	};

Share this post


Link to post
Share on other sites
Advertisement
I don't see anywhere in your code where you are waiting for the timing to catch up to the expected interval... how is that supposed to work?

Share this post


Link to post
Share on other sites
What do you mean? In the draw function I update the time, which in turn adds it to the frameoffset time. If the frameoffset time is greater then the duration of the frame it subtracts the duration and skips to the next frame, this continues until I have a value less then the current frame duration.

Is this what you mean?

Share this post


Link to post
Share on other sites
From what I can see, your draw method seems to be all right...

Are you sure your TIMING is correct? If the delta times you pass to your draw method are incorrect, for sure there will be problems getting the gifs to synch...

Have you tried mining the code with trace outputs to see what actually happens in real time?

Hope this helps

Eric

Share this post


Link to post
Share on other sites
Alright, I was intrigued by your problem so I did some work...

I downloaded like 2 animated gif editors, and tried to run your sample gif in it. They both told me there were 50ms between frames. The thing is, when I ran the animation in both editors, it was way faster than what I saw in IE.

I guess IE slows down the gifs, but I don't see why it would do such a thing...

From what I can see, the gif running in my browser runs a 10 frames / sec, not 20...

Try using a delay of 100 ms and let me know if this solves your problem. It seemed to work perfectly in a gif editor I downloaded.

Hope this helped :)

Eric

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!