Sprite Animation Timing

Started by
4 comments, last by PumpkinPieman 18 years, 10 months ago
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();
	};

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?

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

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?
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
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
Yeah, I've tried 100ms already and I've noticed that it works fine. I was wondering why it seems so irregualr.

Thanks. :)

This topic is closed to new replies.

Advertisement