cocos2dx学习笔记之帧动画详解

如果使用合图的话,可以使用以下方式创建帧动画:
bool HelloWorld::init()
{
    if ( !Layer::init() )
    {
        return false;
    }
    
    auto rootNode = CSLoader::createNode("MainScene.csb");
    addChild(rootNode);

	//1.创建精灵
	Sprite* fire = Sprite::create("fire180114.jpg", Rect(0, 0, 256, 256));
	fire->setPosition(200, 320);
	rootNode->addChild(fire);
	//2.创建动画,设置间隔
	Animation* animation = Animation::create();
	animation->setDelayPerUnit(1.0 / 16);//动画共16帧,运行时间1秒
	animation->setRestoreOriginalFrame(true);//动画执行完后返回第一帧
	//3.加载精灵帧
	Texture2D* texture = Director::getInstance()->getTextureCache()->addImage("fire180114.jpg");
	for (int i = 0; i <= 3; i++)
	{
		for (int j = 0; j <= 3; j++)
		{
			animation->addSpriteFrameWithTexture(texture, Rect(256 * j, 256 * i, 256, 256));
		}
	}
	//4.运行动画
	fire->runAction(RepeatForever::create(Animate::create(animation)));

    return true;
}

动画效果:


本例子是使用void addSpriteFrameWithTexture(Texture2D* pobTexture, const Rect& rect)这个函数加载精灵帧的,此外常用的还有void addSpriteFrame(SpriteFrame *frame);

 void addSpriteFrameWithFile(const std::string& filename);详细用法可到CCAnimation.h中查看

接下来分析下帧动画的实现原理:动画既然通过runAction执行,那么作为一种动作,应该符合动作的实现规律。从上一篇动作类Action分析的文章中(传送门http://blog.csdn.net/ellis1970/article/details/79054341)可以得知,动作类最终在各自的update函数中完成算法的实现,那么我们直接进入Animate的update中:

//update内通过判断若动画下一帧的进度(完成动画的百分比) 小于 当前帧运行时应该完成的进度(完成动画的百分比),
//则替换精灵的纹理,否则不替换,假设update每秒执行默认的60次
void Animate::update(float t)
//t代表当前帧运行时,动画完成的进度,eg:动画执行2秒,则t为0/(60*2),1/(60*2),2/(60*2)......120/(60*2)
{
	//判断是否进入了新的动画循环
    if( t < 1.0f ) {
        t *= _animation->getLoops();
        unsigned int loopNumber = (unsigned int)t;
        if( loopNumber > _executedLoops ) {
            _nextFrame = 0;
            _executedLoops++;
        }
        t = fmodf(t, 1.0f);
    }
	//获取存储精灵帧的向量容器,帧数信息
    auto& frames = _animation->getFrames();
    auto numberOfFrames = frames.size();
    SpriteFrame *frameToDisplay = nullptr;
	//从下一帧到结束帧进行遍历,替换精灵帧或跳出循环
    for( int i=_nextFrame; i < numberOfFrames; i++ ) {
		// 取出动画中下一帧播放的进度
        float splitTime = _splitTimes->at(i);// _splitTimes存储动画每一帧的进度百分比
		// 如果动画中下一帧播放的进度 小于 当前运行的动画播放进度,则需替换目标精灵的精灵帧 
        if( splitTime <= t ) {
            _currFrameIndex = i;
            AnimationFrame* frame = frames.at(_currFrameIndex);
            frameToDisplay = frame->getSpriteFrame();
			//设置目标精灵要显示的精灵帧
            static_cast(_target)->setSpriteFrame(frameToDisplay);

            const ValueMap& dict = frame->getUserInfo();
            if ( !dict.empty() )
            {
                if (_frameDisplayedEvent == nullptr)
                    _frameDisplayedEvent = new (std::nothrow) EventCustom(AnimationFrameDisplayedNotification);
                
                _frameDisplayedEventInfo.target = _target;
                _frameDisplayedEventInfo.userInfo = &dict;
                _frameDisplayedEvent->setUserData(&_frameDisplayedEventInfo);
                Director::getInstance()->getEventDispatcher()->dispatchEvent(_frameDisplayedEvent);
            }
			//下一帧索引加一
            _nextFrame = i+1;
        }
        else {
            break;
        }
    }
}


 
  

你可能感兴趣的:(cocos2dx)