mirror of https://github.com/axmolengine/axmol.git
Merge pull request #13770 from geron-cn/v3
add Frame End Call Back and Animation Clip End Call Back
This commit is contained in:
commit
6bf54a3eda
|
@ -207,6 +207,7 @@ void ActionTimeline::step(float delta)
|
|||
{
|
||||
_currentFrame = (int)(_time / _frameInternal);
|
||||
stepToFrame(_currentFrame);
|
||||
emitFrameEndCallFuncs(_currentFrame);
|
||||
if (endtoffset >= 0 && _lastFrameListener != nullptr) // last frame
|
||||
_lastFrameListener();
|
||||
}
|
||||
|
@ -220,6 +221,7 @@ void ActionTimeline::step(float delta)
|
|||
{
|
||||
_currentFrame = _endFrame;
|
||||
stepToFrame(_currentFrame);
|
||||
emitFrameEndCallFuncs(_currentFrame);
|
||||
if (_lastFrameListener != nullptr) // last frame
|
||||
_lastFrameListener();
|
||||
}
|
||||
|
@ -306,16 +308,20 @@ void ActionTimeline::addAnimationInfo(const AnimationInfo& animationInfo)
|
|||
}
|
||||
|
||||
_animationInfos[animationInfo.name] = animationInfo;
|
||||
addFrameEndCallFunc(animationInfo.endIndex, animationInfo.name, animationInfo.clipEndCallBack);
|
||||
}
|
||||
|
||||
void ActionTimeline::removeAnimationInfo(std::string animationName)
|
||||
{
|
||||
if (_animationInfos.find(animationName) == _animationInfos.end())
|
||||
auto clipIter = _animationInfos.find(animationName);
|
||||
if (clipIter == _animationInfos.end())
|
||||
{
|
||||
CCLOG("AnimationInfo (%s) not exists.", animationName.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
auto clipEndCall = (*clipIter).second.clipEndCallBack;
|
||||
removeFrameEndCall((*clipIter).second.endIndex, animationName);
|
||||
_animationInfos.erase(animationName);
|
||||
}
|
||||
|
||||
|
@ -324,11 +330,23 @@ bool ActionTimeline::IsAnimationInfoExists(const std::string& animationName)
|
|||
return _animationInfos.find(animationName) != _animationInfos.end();
|
||||
}
|
||||
|
||||
AnimationInfo ActionTimeline::getAnimationInfo(const std::string &animationName)
|
||||
const AnimationInfo& ActionTimeline::getAnimationInfo(const std::string &animationName)
|
||||
{
|
||||
return _animationInfos.find(animationName)->second;
|
||||
}
|
||||
|
||||
void ActionTimeline::setAnimationEndCallBack(const std::string animationName, std::function<void()> func)
|
||||
{
|
||||
auto clipIter = _animationInfos.find(animationName);
|
||||
if (clipIter == _animationInfos.end())
|
||||
{
|
||||
CCLOG("AnimationInfo (%s) not exists.", animationName.c_str());
|
||||
return;
|
||||
}
|
||||
clipIter->second.clipEndCallBack = func;
|
||||
addFrameEndCallFunc(clipIter->second.endIndex, animationName, func);
|
||||
}
|
||||
|
||||
void ActionTimeline::setFrameEventCallFunc(std::function<void(Frame *)> listener)
|
||||
{
|
||||
_frameEventListener = listener;
|
||||
|
@ -357,6 +375,52 @@ void ActionTimeline::emitFrameEvent(Frame* frame)
|
|||
}
|
||||
}
|
||||
|
||||
void ActionTimeline::addFrameEndCallFunc(int frameIndex, const std::string& funcKey, std::function<void()> func)
|
||||
{
|
||||
if (func != nullptr)
|
||||
{
|
||||
_frameEndCallFuncs[frameIndex][funcKey] = func;
|
||||
}
|
||||
}
|
||||
|
||||
void ActionTimeline::removeFrameEndCall(int frameIndex, const std::string& funcKey)
|
||||
{
|
||||
auto endClipCallsIter = _frameEndCallFuncs.find(frameIndex);
|
||||
if (endClipCallsIter != _frameEndCallFuncs.end())
|
||||
{
|
||||
auto funcIter = (*endClipCallsIter).second.find(funcKey);
|
||||
if (funcIter != (*endClipCallsIter).second.end())
|
||||
(*endClipCallsIter).second.erase(funcKey);
|
||||
if ((*endClipCallsIter).second.empty())
|
||||
_frameEndCallFuncs.erase(endClipCallsIter);
|
||||
}
|
||||
}
|
||||
|
||||
void ActionTimeline::removeFrameEndCall(int frameIndex)
|
||||
{
|
||||
auto endClipCallsIter = _frameEndCallFuncs.find(frameIndex);
|
||||
if (endClipCallsIter != _frameEndCallFuncs.end())
|
||||
{
|
||||
_frameEndCallFuncs.erase(endClipCallsIter);
|
||||
}
|
||||
}
|
||||
|
||||
void ActionTimeline::clearFrameEndCalls()
|
||||
{
|
||||
_frameEndCallFuncs.clear();
|
||||
}
|
||||
|
||||
void ActionTimeline::emitFrameEndCallFuncs(int frameIndex)
|
||||
{
|
||||
auto clipEndCallsIter = _frameEndCallFuncs.find(frameIndex);
|
||||
if (clipEndCallsIter != _frameEndCallFuncs.end())
|
||||
{
|
||||
auto clipEndCalls = (*clipEndCallsIter).second;
|
||||
for (auto call : clipEndCalls)
|
||||
(call).second();
|
||||
}
|
||||
}
|
||||
|
||||
void ActionTimeline::gotoFrame(int frameIndex)
|
||||
{
|
||||
if(_target == nullptr)
|
||||
|
@ -377,4 +441,5 @@ void ActionTimeline::stepToFrame(int frameIndex)
|
|||
_timelineList.at(i)->stepToFrame(frameIndex);
|
||||
}
|
||||
}
|
||||
|
||||
NS_TIMELINE_END
|
||||
|
|
|
@ -31,19 +31,29 @@ THE SOFTWARE.
|
|||
|
||||
NS_TIMELINE_BEGIN
|
||||
|
||||
struct AnimationInfo
|
||||
typedef struct AnimationInfo
|
||||
{
|
||||
AnimationInfo():startIndex(0),endIndex(0){}
|
||||
AnimationInfo(const std::string& otherName, int otherStartIndex, int otherEndIndex)
|
||||
:name(otherName),
|
||||
startIndex(otherStartIndex),
|
||||
endIndex(otherEndIndex)
|
||||
AnimationInfo()
|
||||
:startIndex(0)
|
||||
,endIndex(0)
|
||||
{
|
||||
}
|
||||
|
||||
AnimationInfo(const std::string& otherName, int otherStartIndex, int otherEndIndex)
|
||||
:name(otherName)
|
||||
,startIndex(otherStartIndex)
|
||||
,endIndex(otherEndIndex)
|
||||
{
|
||||
}
|
||||
|
||||
std::string name;
|
||||
int startIndex;
|
||||
int endIndex;
|
||||
};
|
||||
|
||||
//need set call back before clip added to ActionTimeline
|
||||
// or see @ActionTimeline::setAnimationEndCallBack
|
||||
std::function<void()> clipEndCallBack;
|
||||
} AnimationClip;
|
||||
|
||||
class CC_STUDIO_DLL ActionTimelineData : public cocos2d::Ref
|
||||
{
|
||||
|
@ -145,7 +155,9 @@ public:
|
|||
virtual void addAnimationInfo(const AnimationInfo& animationInfo);
|
||||
virtual void removeAnimationInfo(std::string animationName);
|
||||
virtual bool IsAnimationInfoExists(const std::string& animationName);
|
||||
virtual AnimationInfo getAnimationInfo(const std::string& animationName);
|
||||
virtual const AnimationInfo& getAnimationInfo(const std::string& animationName);
|
||||
// add a frame end call back to animation's end frame @addFrameEndCallFunc, make animationName as the key of func
|
||||
virtual void setAnimationEndCallBack(const std::string animationName, std::function<void()> func);
|
||||
|
||||
/** Set ActionTimeline's frame event callback function */
|
||||
void setFrameEventCallFunc(std::function<void(Frame *)> listener);
|
||||
|
@ -155,6 +167,15 @@ public:
|
|||
void setLastFrameCallFunc(std::function<void()> listener);
|
||||
void clearLastFrameCallFunc();
|
||||
|
||||
// add a call back after played frameIndex
|
||||
virtual void addFrameEndCallFunc(int frameIndex, const std::string& funcKey, std::function<void()> func);
|
||||
// clear frame call back func after frameIndex
|
||||
virtual void removeFrameEndCall(int frameIndex, const std::string& funcKey);
|
||||
// clear frame call backs after frameIndex
|
||||
virtual void removeFrameEndCall(int frameIndex);
|
||||
// clear all frame call backs in this actiontimeline
|
||||
virtual void clearFrameEndCalls();
|
||||
|
||||
/** Inherit from Action. */
|
||||
|
||||
/** Returns a clone of ActionTimeline */
|
||||
|
@ -172,6 +193,9 @@ protected:
|
|||
virtual void gotoFrame(int frameIndex);
|
||||
virtual void stepToFrame(int frameIndex);
|
||||
|
||||
// emit call back after frameIndex played
|
||||
virtual void emitFrameEndCallFuncs(int frameIndex);
|
||||
|
||||
/** emit frame event, call it when enter a frame*/
|
||||
virtual void emitFrameEvent(Frame* frame);
|
||||
|
||||
|
@ -190,6 +214,7 @@ protected:
|
|||
|
||||
std::function<void(Frame*)> _frameEventListener;
|
||||
std::function<void()> _lastFrameListener;
|
||||
std::map<int, std::map<std::string, std::function<void()> > > _frameEndCallFuncs;
|
||||
std::map<std::string, AnimationInfo> _animationInfos;
|
||||
};
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "renderer/CCCustomCommand.h"
|
||||
#include "VisibleRect.h"
|
||||
#include "editor-support/cocostudio/CCComExtensionData.h"
|
||||
#include "ui/CocosGUI.h"
|
||||
|
||||
|
||||
USING_NS_CC;
|
||||
|
@ -24,6 +25,7 @@ CocoStudioActionTimelineTests::CocoStudioActionTimelineTests()
|
|||
ADD_TEST_CASE(TestActionTimelineSkeleton);
|
||||
ADD_TEST_CASE(TestTimelineExtensionData);
|
||||
ADD_TEST_CASE(TestActionTimelineBlendFuncFrame);
|
||||
ADD_TEST_CASE(TestAnimationClipEndCallBack);
|
||||
}
|
||||
|
||||
CocoStudioActionTimelineTests::~CocoStudioActionTimelineTests()
|
||||
|
@ -597,3 +599,81 @@ std::string TestActionTimelineBlendFuncFrame::title() const
|
|||
{
|
||||
return "Test ActionTimeline BlendFunc Frame";
|
||||
}
|
||||
|
||||
//TestAnimationClipEndCallBack
|
||||
void TestAnimationClipEndCallBack::onEnter()
|
||||
{
|
||||
ActionTimelineBaseTest::onEnter();
|
||||
Node* node = CSLoader::createNode("ActionTimeline/DemoPlayer_skeleton.csb");
|
||||
ActionTimeline* action = CSLoader::createTimeline("ActionTimeline/DemoPlayer_skeleton.csb");
|
||||
node->runAction(action);
|
||||
node->setScale(0.2f);
|
||||
node->setPosition(150, 150);
|
||||
|
||||
// test for frame end call back
|
||||
action->addFrameEndCallFunc(5, "CallBackAfterFifthFrame", [this]{
|
||||
auto text = ui::Text::create();
|
||||
text->setString("CallBackAfterFifthFrame");
|
||||
text->setPosition(Vec2(100, 40));
|
||||
text->setLocalZOrder(1000);
|
||||
this->runAction(Sequence::create(
|
||||
CallFunc::create([this, text]{this->addChild(text); }),
|
||||
DelayTime::create(3),
|
||||
CallFunc::create([text]{text->removeFromParent(); }),
|
||||
nullptr));
|
||||
});
|
||||
action->addFrameEndCallFunc(5, "AnotherCallBackAfterFifthFrame", [this]{
|
||||
auto text = ui::Text::create();
|
||||
text->setString("AnotherCallBackAfterFifthFrame");
|
||||
text->setPosition(Vec2(100, 70));
|
||||
this->runAction(Sequence::create(
|
||||
CallFunc::create([this, text]{this->addChild(text); }),
|
||||
DelayTime::create(3),
|
||||
CallFunc::create([text]{text->removeFromParent(); }),
|
||||
nullptr));
|
||||
});
|
||||
action->addFrameEndCallFunc(7, "CallBackAfterSenvnthFrame", [this]{
|
||||
auto text = ui::Text::create();
|
||||
text->setString("CallBackAfterSenvnthFrame");
|
||||
text->setPosition(Vec2(100, 100));
|
||||
this->runAction(Sequence::create(
|
||||
CallFunc::create([this, text]{this->addChild(text); }),
|
||||
DelayTime::create(3),
|
||||
CallFunc::create([text]{text->removeFromParent(); }),
|
||||
nullptr));
|
||||
});
|
||||
|
||||
// test for animation clip end call back
|
||||
action->setAnimationEndCallBack("stand", [this]{
|
||||
auto text = ui::Text::create();
|
||||
text->setString("CallBackAfterStandAnimationClip");
|
||||
text->setPosition(Vec2(100, 130));
|
||||
this->runAction(Sequence::create(
|
||||
CallFunc::create([this, text]{this->addChild(text); }),
|
||||
DelayTime::create(3),
|
||||
CallFunc::create([text]{text->removeFromParent(); }),
|
||||
nullptr));
|
||||
});
|
||||
|
||||
AnimationClip animClip("testClip", 3, 13);
|
||||
animClip.clipEndCallBack = ([this,node]{
|
||||
auto text = ui::Text::create();
|
||||
text->setString("testClip");
|
||||
text->setPosition(Vec2(100, 140));
|
||||
this->runAction(Sequence::create(
|
||||
CallFunc::create([this, text]{this->addChild(text); }),
|
||||
DelayTime::create(3),
|
||||
CallFunc::create([text]{text->removeFromParent(); }),
|
||||
nullptr));
|
||||
});
|
||||
action->addAnimationInfo(animClip);
|
||||
|
||||
action->setTimeSpeed(0.2f);
|
||||
addChild(node);
|
||||
action->gotoFrameAndPlay(0);
|
||||
}
|
||||
|
||||
std::string TestAnimationClipEndCallBack::title() const
|
||||
{
|
||||
return "Test ActionTimeline Frame End Call Back\n and Animation Clip End Call Back";
|
||||
}
|
||||
|
|
|
@ -146,4 +146,13 @@ public:
|
|||
virtual void onEnter() override;
|
||||
virtual std::string title() const override;
|
||||
};
|
||||
|
||||
class TestAnimationClipEndCallBack : public ActionTimelineBaseTest
|
||||
{
|
||||
public:
|
||||
CREATE_FUNC(TestAnimationClipEndCallBack);
|
||||
|
||||
virtual void onEnter() override;
|
||||
virtual std::string title() const override;
|
||||
};
|
||||
#endif // __ANIMATION_SCENE_H__
|
||||
|
|
Loading…
Reference in New Issue