However we should save each frame in saparate file in this way, thus the loading speed is slowed down.
I've read this post to show how to make irrlicht support sprite sheet by using texture matrix.
In order to avoid update texture manually in the game loop, I write this sprite node animater, just for newbies like me.
here's code:
The hearder
Code: Select all
// This flie is modified from CSceneNodeAnimatorTexture
#ifndef __C_SCENE_NODE_ANIMATOR_SPRITE_H_INCLUDED__
#define __C_SCENE_NODE_ANIMATOR_SPRITE_H_INCLUDED__
#include "irrArray.h"
#include "vector2d.h"
#include <irrlicht.h>
namespace irr
{
namespace scene
{
//I have trouble compile it into the irrlicht core(vs2008 sayed dinput.h is missing), so I have to make it into a dll function.
__declspec(dllexport) ISceneNodeAnimator* createSpriteAnimator(video::ITexture*texture,
const core::array<core::vector2df>&translations,
core::vector2df& scale,
s32 timePerFrame, bool loop,
//os::timer isn't export in the lib, so you have to pass a timer here(see example below)
ITimer*timer);
//Here's the class
class CSceneNodeAnimatorSprite : public ISceneNodeAnimator
{
public:
//! constructor
CSceneNodeAnimatorSprite(video::ITexture* texture,const core::array<core::vector2df>&translations,core::vector2df& scale,
s32 timePerFrame, bool loop, u32 now);
//! destructor
virtual ~CSceneNodeAnimatorSprite();
//! animates a scene node
virtual void animateNode(ISceneNode* node, u32 timeMs);
//! Writes attributes of the scene node animator.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;
//! Reads attributes of the scene node animator.
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);
//! Returns type of the scene node animator
virtual ESCENE_NODE_ANIMATOR_TYPE getType() const { return ESNAT_UNKNOWN; }
//! Creates a clone of this animator.
/** Please note that you will have to drop
(IReferenceCounted::drop()) the returned pointer after calling
this. */
virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0);
private:
void clearSprites();
video::ITexture* Texture;
//each frame's position is stored in translations' array
core::array<core::vector2df>Translations;
core::vector2df Scale;
u32 TimePerFrame;
u32 StartTime;
u32 FinishTime;
bool HasFinished;
bool Loop;
};
} // end namespace scene
} // end namespace irr
#endif
Code: Select all
#include "CSceneNodeAnimatorSprite.h"
#include "ITexture.h"
namespace irr
{
namespace scene
{
ISceneNodeAnimator* createSpriteAnimator(video::ITexture* texture,
const core::array<core::vector2df>&translations,
core::vector2df& scale,
s32 timePerFrame, bool loop,ITimer*timer)
{
ISceneNodeAnimator* anim = new CSceneNodeAnimatorSprite(texture,translations,scale,
timePerFrame, loop, timer->getTime());
return anim;
}
//! constructor
CSceneNodeAnimatorSprite::CSceneNodeAnimatorSprite(video::ITexture* texture,
const core::array<core::vector2df>&translations, core::vector2df& scale,
s32 timePerFrame, bool loop, u32 now):
TimePerFrame(timePerFrame), StartTime(now), Loop(loop),Scale(scale)
{
//modified from texure animator, hope this part is right.. Anyway it works well till now
if (texture)
texture->grab();
Translations=translations;
Texture=texture;
FinishTime = now + (timePerFrame * translations.size());
}
//! destructor
CSceneNodeAnimatorSprite::~CSceneNodeAnimatorSprite()
{
clearSprites();
}
void CSceneNodeAnimatorSprite::clearSprites()
{
/*for (u32 i=0; i<Translations.size(); ++i)
{
if (Translations[i])
delete Translations[i];
}*/
Translations.clear();
if(Texture)
{
Texture->drop();
}
}
//! animates a scene node
void CSceneNodeAnimatorSprite::animateNode(ISceneNode* node, u32 timeMs)
{
if(!node)
return;
if (Translations.size())
{
const u32 t = (timeMs-StartTime);
u32 idx = 0;
if (!Loop && timeMs >= FinishTime)
{
idx = Translations.size() - 1;
HasFinished = true;
}
else
{
idx = (t/TimePerFrame) % Translations.size();
}
if (idx < Translations.size())
{
core::vector2df tran=Translations[idx];
core::matrix4 mat;
mat.buildTextureTransform(0,core::vector2df(0.0f),tran,Scale);
node->setMaterialTexture(0, Texture);
node->getMaterial(0).setTextureMatrix(0,mat);
}
}
}
//! Writes attributes of the scene node animator.
void CSceneNodeAnimatorSprite::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
out->addInt("TimePerFrame", TimePerFrame);
out->addBool("Loop", Loop);
// add texture in addition when serializing for editors
out->addTexture("Texture",Texture);
// add one translation in addition when serializing for editors
// to make it easier to add translations quickly
u32 count = Translations.size();
if ( options && (options->Flags & io::EARWF_FOR_EDITOR))
count += 1;
for (u32 i=0; i<count; ++i)
{
core::stringc tname = "Translation";
tname += (int)(i+1);
out->addVector2d(tname.c_str(), i<Translations.size() ? Translations[i] : core::vector2df(0.0f));
}
}
//! Reads attributes of the scene node animator.
void CSceneNodeAnimatorSprite::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
TimePerFrame = in->getAttributeAsInt("TimePerFrame");
Loop = in->getAttributeAsBool("Loop");
Texture=in->getAttributeAsTexture("Texture");
Texture->grab();
clearSprites();
for(u32 i=1; true; ++i)
{
core::stringc tname = "Translation";
tname += (int)i;
if (in->existsAttribute(tname.c_str()))
{
core::vector2df trans = in->getAttributeAsVector2d(tname.c_str());
//if (trans)
//{
Translations.push_back(trans);
//}
}
else
break;
}
}
ISceneNodeAnimator* CSceneNodeAnimatorSprite::createClone(ISceneNode* node, ISceneManager* newManager)
{
CSceneNodeAnimatorSprite * newAnimator =
new CSceneNodeAnimatorSprite(Texture, Translations, Scale, TimePerFrame, Loop, StartTime);
return newAnimator;
}
} // end namespace scene
} // end namespace irr
Code: Select all
// scale cannot bigger than 1
//scale.x = 1 / how many frames in a row
//scale.y= 1/ how many frames in a column
//For this example, I have a sprite sheet with 7 frames in a row, totally 3 columna
vector2df scale(1.f/7.f,1.f/3.0f);
vector2df trans;
array<vector2df>ts;
//caculate positions
for(f32 m=0.f;m<3.f;m+=1.f)
{
for(f32 n=0;n<7;n+=1.f)
{
trans=vector2df(n,m)*scale;
ts.push_back(trans);
}
}
//get your sprite sheet
ITexture* ft=device->getVideoDriver()->getTexture("sfx/cannon/fire/flame01.bmp");
//my image's background color is black, so I have to remove it
device->getVideoDriver()->makeColorKeyTexture(ft,video::SColor(0,0,0,0));
//create animator
ISceneNodeAnimator* ani=scene::createSpriteAnimator(ft,ts,scale,40,true,device->getTimer());
IBillboardSceneNode* testB=smgr->addBillboardSceneNode();
//add animator
testB->addAnimator(ani);
//drop it
ani->drop();
testB->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
testB->setMaterialFlag(video::EMF_LIGHTING,false);