简介
JGE 引擎提供了一个基于 frame 的动画模块。动画各个 frame 的参数和播放顺
序存在一个 XML 文件中。播放动画时动画模块根据时间顺序显示各个 frame。
记录动画的 XML 文件如下所示:
<?xml version="1.0" standalone="no" ?>
<script name="abc" type="ANIMATION_TYPE_ONCE_AND_STAY" framerate="20">
/* "type" can be ANIMATION_TYPE_LOOPING,
* ANIMATION_TYPE_ONCE_AND_STAY,
* ANIMATION_TYPE_ONCE_AND_BACK,
* ANIMATION_TYPE_ONCE_AND_GONE,r
* ANIMATION_TYPE_PINGPONG
*
* "framerate" is the rate of playback in frames per seconds.
*/
<frame id="1">
<obj name="head">
<settings quad="head" x="10" y="10" hsize="1.0" vsize="1.0"
rotation="0.0" r="255" g="255" b="255" a="255" />
</obj>
<obj name="body">
<settings quad="body" />
</obj>
</frame>
/*
* Each frame contains one or more frame objects.
* Each object is a quad with various settings.
* "quad" is the name of the quad.
* "x" and "y" is the position.
* "hsize" is the horizontal scaling.
* "vsize" is the vertical scaling.
* "rotation" is the angle that the quad will be rotated in radians.
* You can also specify the color and alpha of the quad with the "r", "g", "b" and "a" parameters.
*/
<frame id="2" time="0.20">
<obj name="head">
<settings quad="head" x="10" y="10" hsize="1.0" vsize="1.0"
rotation="0.0" r="255" g="255" b="255" a="255" />
</obj>
<obj name="body">
<settings quad="body" a="128" />
</obj>
</frame>
</script>
动画模块
JGE 动画的动画模块由三个类组成:
- JAnimatior
- JAnimatorFrame
- JAnimatorObject
动画模块的类图如下所示:

播放动画总体流程
播放动画分如下几步:
- 装入资源文件;
- 创在动画对象,并指定记录 frame 信息的 xml 文件;
- 设置动画对象位置;
- start 动画;
- 进入循环,每次循环调用动画对象的 Update 方法和 Render 方法,分别处
理动画逻辑和渲染。
播放一个 frame 的序列图如下所示:

示例代码如下所示:
/* Load resource. */
mResourceMgr = new JResourceManager();
mResourceMgr->LoadResource("animation.res");
/* Create animator. */
mMyAnimator = new JAnimator(mResourceMgr);
mMyAnimator->Load("left.anm");
/* Specify animator position.*/
mMyAnimator->SetHotSpot(79,126);
mMyAnimator->SetPosition(240,220);
/* Start animation */
mMyAnimator->Start();
while(!done) {
mMyAnimator->Update(dt);
mMyAnimator->Render();
}
JAnimator 类
JAnimator 的核心成员是 mFrames,它是 JAnimatorFrame 类型的指针数组,
记录了该动画包含的所有 frame。
JAnimator 的核心方法是
- Load:装入 xml 文件;
- Start:启动动画 ;
- Update:根据时间的推进及时更新当前 frame ;
- Render: 绘制当前 frame。
class JAnimator
{
public:
/*
* Constructor.
*
* @param resourceMgr - ResourceManager to look for images (JQuads)
*
*/
JAnimator(JResourceManager* resourceMgr);
/*
* Destructor.
*
*/
~JAnimator();
/*
* Load animation sequence from a script file.
*
* @param scriptFile - Animation script.
*
* @return True if no problem during loading. False otherwise.
*
*/
bool Load(const char* scriptFile);
/*
* Start animation.
*
*/
void Start();
/*
* Update animation.
*
* @param dt - Time elapsed since last update (in second).
*
*/
void Update(float dt);
/*
* Render animation.
*
*/
void Render();
/*
* Check if animation is playing or not.
*
* @return True if playing animation.
*
*/
bool IsAnimating();
private:
JResourceManager* mResource;
vector<JAnimatorFrame *> mFrames;
bool mAnimating;
bool mActive;
int mCurrentFrame;
int mAnimationType;
int mFrameDelta;
float mX;
float mY;
float mHotSpotX;
float mHotSpotY;
};
核心方法 Update 和 Render 的实现如下所示:
void JAnimator::Update(float dt)
{
if (!mAnimating) return;
if (mFrames[mCurrentFrame]->Update(dt))
{
mCurrentFrame+=mFrameDelta;
int frameCount = mFrames.size();
if (mCurrentFrame >= frameCount)
{
/* All frames have been played. */
if (mAnimationType == JSprite::ANIMATION_TYPE_LOOPING)
mCurrentFrame = 0;
else if (mAnimationType == JSprite::ANIMATION_TYPE_ONCE_AND_GONE)
{
mAnimating = false;
mActive = false;
}
else if (mAnimationType == JSprite::ANIMATION_TYPE_ONCE_AND_STAY)
{
mCurrentFrame = frameCount-1;
mAnimating = false;
}
else if (mAnimationType == JSprite::ANIMATION_TYPE_ONCE_AND_BACK)
{
mCurrentFrame = 0;
mAnimating = false;
}
else // ping pong
{
mFrameDelta *= -1;
mCurrentFrame += mFrameDelta;
}
}
else if (mCurrentFrame < 0)
{
if (mAnimationType == JSprite::ANIMATION_TYPE_PINGPONG)
{
mFrameDelta *= -1;
mCurrentFrame += mFrameDelta;
}
}
/* Play next frame.*/
if (mAnimating)
mFrames[mCurrentFrame]->Start();
}
}
void JAnimator::Render()
{
if (!mActive)
return;
mFrames[mCurrentFrame]->Render(mX-mHotSpotX, mY-mHotSpotY);
}
JAnimatorFrame 类
JAnimatorFrame 的核心成员是 mObjects,该成员是 JAnimatorObject 类型的
指针数组,保存了构成该 frame 的所有对象。
JAnimatorFrame 的核心方法是
- Start:启动该 frame;
- Update:根据时间的推进及时更新 frame 中的对象;
- Render: 绘制当前 frame。
/*
* A single frame of an animation.
*
*/
class JAnimatorFrame
{
public:
/*
* Constructor.
*
* @param parent - Parent of the frame.
*
*/
JAnimatorFrame(JAnimator* parent);
/*
* Destructor.
*
*/
~JAnimatorFrame();
/*
* Add a new object into the frame.
*
* @param obj - New animation object.
*
*/
void AddObject(JAnimatorObject *obj);
/*
* Frame update.
*
* @param dt - Time elapsed since last update (in second).
*
* @return True if the frame is done.
*
*/
bool Update(float dt);
/*
* Render frame.
*
* @param x - X position for rendering.
* @param y - Y position for rendering.
*
*/
void Render(float x, float y);
/*
* Start playing the frame.
*
*/
void Start();
private:
float mTimer;
float mFrameTime;
JAnimator* mAnimator;
vector<JAnimatorObject *> mObjects;
};
核心方法 Update 和 Render 的实现如下所示:
bool JAnimatorFrame::Update(float dt)
{
mTimer += dt;
if (mTimer >= mFrameTime)
return true;
else
{
int size = mObjects.size();
for (int i=0;i<size;i++)
mObjects[i]->Update(dt);
return false;
}
}
void JAnimatorFrame::Render(float x, float y)
{
int size = mObjects.size();
for (int i=0;i<size;i++)
mObjects[i]->Render(x, y);
}
JAnimatorObject 类
/*
* Animation object (image quad) in a frame.
*
*/
class JAnimatorObject
{
public:
/*
* Constructor.
*
*/
JAnimatorObject();
/*
* Destructor.
*
*/
~JAnimatorObject();
/*
* Update object.
*
* @param dt - Time elapsed since last update (in second).
*
*/
void Update(float dt);
/*
* Render object.
*
* @param x - X position for rendering.
* @param y - Y position for rendering.
*
*/
void Render(float x, float y);
private:
JRenderer* mRenderer;
JQuad* mQuad;
float mX;
float mY;
float mRotation;
float mHScale;
float mVScale;
PIXEL_TYPE mColor;
bool mFlipped;
};
Update 和 Render 方法的实现:
void JAnimatorObject::Update(float dt)
{
}
void JAnimatorObject::Render(float x, float y)
{
mQuad->SetHFlip(mFlipped);
mQuad->SetColor(mColor);
mRenderer->RenderQuad(mQuad, x+mX, y+mY, mRotation, mHScale, mVScale);
}
JGE Tutorial: Animator
这是 JGE 提供的一个动画例子,该例子创建了两个动画,一个是小人脸朝左跳
舞、另一个是脸朝右跳舞,两个动画交替播放。
GameApp.h 如下所示:
class GameApp: public JApp
{
private:
JResourceManager* mResourceMgr;
JAnimator* mLeft;
JAnimator* mRight;
JAnimator* mCurr;
public:
GameApp();
virtual ~GameApp();
virtual void Create();
virtual void Destroy();
virtual void Update();
virtual void Render();
virtual void Pause();
virtual void Resume();
};
GameApp.cpp 如下所示:
void GameApp::Create()
{
// JAnimator needs to get its resource from a JResourceManager
mResourceMgr = new JResourceManager();
mResourceMgr->LoadResource("animation.res");
// create the first animator
mLeft = new JAnimator(mResourceMgr);
mLeft->Load("left.anm");
// create the second animator
mRight = new JAnimator(mResourceMgr);
mRight->Load("right.anm");
mLeft->SetHotSpot(79,126);
mLeft->SetPosition(240,220);
mRight->SetHotSpot(79,126);
mRight->SetPosition(240,220);
// start the animation
mCurr = mLeft;
mCurr->Start();
}
void GameApp::Update()
{
JGE* engine = JGE::GetInstance();
......
float dt = engine->GetDelta();
mCurr->Update(dt);
// change to the other animation when the current one is done
if (!mCurr->IsAnimating())
{
if (mCurr == mLeft)
mCurr = mRight;
else
mCurr = mLeft;
mCurr->Start();
}
}
void GameApp::Render()
{
JRenderer* renderer = JRenderer::GetInstance();
// turn off bilinear filtering to have sharp image
renderer->EnableTextureFilter(false);
// render background
renderer->RenderQuad(mResourceMgr->GetQuad("bg"), 480>>1, 272>>1);
// render animation
mCurr->Render();
}
|