mirror of https://github.com/axmolengine/axmol.git
449 lines
11 KiB
C++
449 lines
11 KiB
C++
/****************************************************************************
|
|
Copyright (c) 2013 cocos2d-x.org
|
|
|
|
https://axmolengine.github.io/
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
****************************************************************************/
|
|
|
|
#include "ActionTimeline/CCActionTimeline.h"
|
|
|
|
#include "CCComExtensionData.h"
|
|
|
|
USING_NS_AX;
|
|
|
|
NS_TIMELINE_BEGIN
|
|
|
|
#if 0
|
|
// ActionTimelineData
|
|
ActionTimelineData* ActionTimelineData::create(int actionTag)
|
|
{
|
|
ActionTimelineData * ret = new ActionTimelineData();
|
|
if (ret->init(actionTag))
|
|
{
|
|
ret->autorelease();
|
|
}
|
|
else
|
|
{
|
|
AX_SAFE_DELETE(ret);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
ActionTimelineData::ActionTimelineData()
|
|
: _actionTag(0)
|
|
{
|
|
}
|
|
|
|
bool ActionTimelineData::init(int actionTag)
|
|
{
|
|
_actionTag = actionTag;
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
// ActionTimeline
|
|
ActionTimeline* ActionTimeline::create()
|
|
{
|
|
ActionTimeline* ret = new ActionTimeline();
|
|
if (ret->init())
|
|
{
|
|
ret->autorelease();
|
|
return ret;
|
|
}
|
|
AX_SAFE_DELETE(ret);
|
|
return nullptr;
|
|
}
|
|
|
|
ActionTimeline::ActionTimeline()
|
|
: _duration(0)
|
|
, _time(0)
|
|
, _timeSpeed(1)
|
|
, _frameInternal(1 / 60.0f)
|
|
, _playing(false)
|
|
, _currentFrame(0)
|
|
, _startFrame(0)
|
|
, _endFrame(0)
|
|
, _frameEventListener(nullptr)
|
|
, _lastFrameListener(nullptr)
|
|
{}
|
|
|
|
ActionTimeline::~ActionTimeline() {}
|
|
|
|
bool ActionTimeline::init()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void ActionTimeline::play(std::string name, bool loop)
|
|
{
|
|
if (_animationInfos.find(name) == _animationInfos.end())
|
|
{
|
|
AXLOG("Can't find animation info for %s", name.c_str());
|
|
return;
|
|
}
|
|
|
|
AnimationInfo& index = _animationInfos[name];
|
|
gotoFrameAndPlay(index.startIndex, index.endIndex, loop);
|
|
}
|
|
|
|
void ActionTimeline::gotoFrameAndPlay(int startIndex)
|
|
{
|
|
gotoFrameAndPlay(startIndex, true);
|
|
}
|
|
|
|
void ActionTimeline::gotoFrameAndPlay(int startIndex, bool loop)
|
|
{
|
|
gotoFrameAndPlay(startIndex, _duration, loop);
|
|
}
|
|
|
|
void ActionTimeline::gotoFrameAndPlay(int startIndex, int endIndex, bool loop)
|
|
{
|
|
gotoFrameAndPlay(startIndex, endIndex, startIndex, loop);
|
|
}
|
|
|
|
void ActionTimeline::gotoFrameAndPlay(int startIndex, int endIndex, int currentFrameIndex, bool loop)
|
|
{
|
|
_startFrame = startIndex;
|
|
_endFrame = endIndex;
|
|
_currentFrame = currentFrameIndex;
|
|
_loop = loop;
|
|
_time = _currentFrame * _frameInternal;
|
|
|
|
resume();
|
|
gotoFrame(_currentFrame);
|
|
}
|
|
|
|
void ActionTimeline::gotoFrameAndPause(int startIndex)
|
|
{
|
|
_startFrame = _currentFrame = startIndex;
|
|
_time = _currentFrame * _frameInternal;
|
|
|
|
pause();
|
|
gotoFrame(_currentFrame);
|
|
}
|
|
|
|
void ActionTimeline::pause()
|
|
{
|
|
_playing = false;
|
|
}
|
|
|
|
void ActionTimeline::resume()
|
|
{
|
|
_playing = true;
|
|
}
|
|
|
|
bool ActionTimeline::isPlaying() const
|
|
{
|
|
return _playing;
|
|
}
|
|
|
|
void ActionTimeline::setCurrentFrame(int frameIndex)
|
|
{
|
|
if (frameIndex >= _startFrame && frameIndex <= _endFrame)
|
|
{
|
|
_currentFrame = frameIndex;
|
|
_time = _currentFrame * _frameInternal;
|
|
}
|
|
else
|
|
{
|
|
AXLOG("frame index is not between start frame and end frame");
|
|
}
|
|
}
|
|
|
|
ActionTimeline* ActionTimeline::clone() const
|
|
{
|
|
ActionTimeline* newAction = ActionTimeline::create();
|
|
newAction->setDuration(_duration);
|
|
newAction->setTimeSpeed(_timeSpeed);
|
|
|
|
for (auto&& timelines : _timelineMap)
|
|
{
|
|
for (auto&& timeline : timelines.second)
|
|
{
|
|
Timeline* newTimeline = timeline->clone();
|
|
newAction->addTimeline(newTimeline);
|
|
}
|
|
}
|
|
|
|
for (auto&& info : _animationInfos)
|
|
{
|
|
newAction->addAnimationInfo(info.second);
|
|
}
|
|
return newAction;
|
|
}
|
|
|
|
void ActionTimeline::step(float delta)
|
|
{
|
|
if (!_playing || _timelineMap.size() == 0 || _duration == 0)
|
|
{
|
|
return;
|
|
}
|
|
_time += delta * _timeSpeed;
|
|
float deltaCurrFrameTime = std::abs(_time - _currentFrame * _frameInternal);
|
|
if (deltaCurrFrameTime < _frameInternal)
|
|
return;
|
|
|
|
const float endtoffset = _time - _endFrame * _frameInternal;
|
|
if (endtoffset < _frameInternal)
|
|
{
|
|
_currentFrame = (int)(_time / _frameInternal);
|
|
stepToFrame(_currentFrame);
|
|
emitFrameEndCallFuncs(_currentFrame);
|
|
if (endtoffset >= 0 && _lastFrameListener != nullptr) // last frame
|
|
_lastFrameListener();
|
|
}
|
|
else
|
|
{
|
|
_playing = _loop;
|
|
if (!_playing)
|
|
{
|
|
_time = _endFrame * _frameInternal;
|
|
if (_currentFrame != _endFrame)
|
|
{
|
|
_currentFrame = _endFrame;
|
|
stepToFrame(_currentFrame);
|
|
emitFrameEndCallFuncs(_currentFrame);
|
|
if (_lastFrameListener != nullptr) // last frame
|
|
_lastFrameListener();
|
|
}
|
|
}
|
|
else
|
|
gotoFrameAndPlay(_startFrame, _endFrame, _loop);
|
|
}
|
|
}
|
|
|
|
typedef std::function<void(Node*)> tCallBack;
|
|
void foreachNodeDescendant(Node* parent, tCallBack callback)
|
|
{
|
|
callback(parent);
|
|
|
|
auto& children = parent->getChildren();
|
|
for (auto&& child : children)
|
|
{
|
|
foreachNodeDescendant(child, callback);
|
|
}
|
|
}
|
|
|
|
void ActionTimeline::startWithTarget(Node* target)
|
|
{
|
|
Action::startWithTarget(target);
|
|
this->setTag(target->getTag());
|
|
|
|
foreachNodeDescendant(target, [this, target](Node* child) {
|
|
ComExtensionData* data = dynamic_cast<ComExtensionData*>(child->getComponent("ComExtensionData"));
|
|
|
|
if (data)
|
|
{
|
|
int actionTag = data->getActionTag();
|
|
if (_timelineMap.find(actionTag) != _timelineMap.end())
|
|
{
|
|
auto timelines = this->_timelineMap[actionTag];
|
|
for (auto&& timeline : timelines)
|
|
{
|
|
timeline->setNode(child);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
void ActionTimeline::addTimeline(Timeline* timeline)
|
|
{
|
|
int tag = timeline->getActionTag();
|
|
if (_timelineMap.find(tag) == _timelineMap.end())
|
|
{
|
|
_timelineMap[tag] = Vector<Timeline*>();
|
|
}
|
|
|
|
if (!_timelineMap[tag].contains(timeline))
|
|
{
|
|
_timelineList.pushBack(timeline);
|
|
_timelineMap[tag].pushBack(timeline);
|
|
timeline->setActionTimeline(this);
|
|
}
|
|
}
|
|
|
|
void ActionTimeline::removeTimeline(Timeline* timeline)
|
|
{
|
|
int tag = timeline->getActionTag();
|
|
if (_timelineMap.find(tag) != _timelineMap.end())
|
|
{
|
|
if (_timelineMap[tag].contains(timeline))
|
|
{
|
|
_timelineMap[tag].eraseObject(timeline);
|
|
_timelineList.eraseObject(timeline);
|
|
timeline->setActionTimeline(nullptr);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ActionTimeline::addAnimationInfo(const AnimationInfo& animationInfo)
|
|
{
|
|
if (_animationInfos.find(animationInfo.name) != _animationInfos.end())
|
|
{
|
|
AXLOG("Animation (%s) already exists.", animationInfo.name.c_str());
|
|
return;
|
|
}
|
|
|
|
_animationInfos[animationInfo.name] = animationInfo;
|
|
addFrameEndCallFunc(animationInfo.endIndex, animationInfo.name, animationInfo.clipEndCallBack);
|
|
}
|
|
|
|
void ActionTimeline::removeAnimationInfo(std::string animationName)
|
|
{
|
|
auto clipIter = _animationInfos.find(animationName);
|
|
if (clipIter == _animationInfos.end())
|
|
{
|
|
AXLOG("AnimationInfo (%s) not exists.", animationName.c_str());
|
|
return;
|
|
}
|
|
|
|
removeFrameEndCallFunc((*clipIter).second.endIndex, animationName);
|
|
_animationInfos.erase(animationName);
|
|
}
|
|
|
|
bool ActionTimeline::IsAnimationInfoExists(std::string_view animationName)
|
|
{
|
|
return _animationInfos.find(animationName) != _animationInfos.end();
|
|
}
|
|
|
|
const AnimationInfo& ActionTimeline::getAnimationInfo(std::string_view animationName)
|
|
{
|
|
return _animationInfos.find(animationName)->second;
|
|
}
|
|
|
|
void ActionTimeline::setAnimationEndCallFunc(const std::string animationName, std::function<void()> func)
|
|
{
|
|
auto clipIter = _animationInfos.find(animationName);
|
|
if (clipIter == _animationInfos.end())
|
|
{
|
|
AXLOG("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;
|
|
}
|
|
|
|
void ActionTimeline::clearFrameEventCallFunc()
|
|
{
|
|
_frameEventListener = nullptr;
|
|
}
|
|
|
|
void ActionTimeline::setLastFrameCallFunc(std::function<void()> listener)
|
|
{
|
|
_lastFrameListener = listener;
|
|
}
|
|
|
|
void ActionTimeline::clearLastFrameCallFunc()
|
|
{
|
|
_lastFrameListener = nullptr;
|
|
}
|
|
|
|
void ActionTimeline::emitFrameEvent(Frame* frame)
|
|
{
|
|
if (_frameEventListener)
|
|
{
|
|
_frameEventListener(frame);
|
|
}
|
|
}
|
|
|
|
void ActionTimeline::addFrameEndCallFunc(int frameIndex, std::string_view funcKey, std::function<void()> func)
|
|
{
|
|
if (func != nullptr)
|
|
{
|
|
_frameEndCallFuncs[frameIndex][funcKey] = func;
|
|
}
|
|
}
|
|
|
|
void ActionTimeline::removeFrameEndCallFunc(int frameIndex, std::string_view 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::removeFrameEndCallFuncs(int frameIndex)
|
|
{
|
|
auto endClipCallsIter = _frameEndCallFuncs.find(frameIndex);
|
|
if (endClipCallsIter != _frameEndCallFuncs.end())
|
|
{
|
|
_frameEndCallFuncs.erase(endClipCallsIter);
|
|
}
|
|
}
|
|
|
|
void ActionTimeline::clearFrameEndCallFuncs()
|
|
{
|
|
_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)
|
|
return;
|
|
|
|
ssize_t size = _timelineList.size();
|
|
for (ssize_t i = 0; i < size; i++)
|
|
{
|
|
_timelineList.at(i)->gotoFrame(frameIndex);
|
|
}
|
|
}
|
|
|
|
void ActionTimeline::stepToFrame(int frameIndex)
|
|
{
|
|
ssize_t size = _timelineList.size();
|
|
for (ssize_t i = 0; i < size; i++)
|
|
{
|
|
_timelineList.at(i)->stepToFrame(frameIndex);
|
|
}
|
|
}
|
|
|
|
void ActionTimeline::start()
|
|
{
|
|
gotoFrameAndPlay(0);
|
|
}
|
|
|
|
void ActionTimeline::stop()
|
|
{
|
|
pause();
|
|
}
|
|
NS_TIMELINE_END
|