#include "CCBAnimationManager.h" #include "CCBReader.h" #include "CCNode+CCBRelativePositioning.h" #include "audio/include/SimpleAudioEngine.h" #include "CCBSelectorResolver.h" #include <string> #include <sstream> #include <set> using namespace cocos2d; using namespace std; using namespace cocos2d::extension; namespace cocosbuilder { // Implementation of CCBAinmationManager CCBAnimationManager::CCBAnimationManager() : _jsControlled(false) , _owner(nullptr) , _autoPlaySequenceId(0) , _rootNode(nullptr) , _rootContainerSize(Size::ZERO) , _delegate(nullptr) , _runningSequence(nullptr) { init(); } bool CCBAnimationManager::init() { _target = nullptr; _animationCompleteCallbackFunc = nullptr; return true; } CCBAnimationManager::~CCBAnimationManager() { // DictElement *pElement = nullptr; // CCDICT_FOREACH(_nodeSequences, pElement) // { // Node *node = (Node*)pElement->getIntKey(); // node->release(); // } // // CCDICT_FOREACH(_baseValues, pElement) // { // Node *node = (Node*)pElement->getIntKey(); // node->release(); // } if (_rootNode) { _rootNode->stopAllActions(); } setRootNode(nullptr); setDelegate(nullptr); for (auto iter = _objects.begin(); iter != _objects.end(); ++iter) { for (auto iter2 = iter->second.begin(); iter2 != iter->second.end(); ++iter2) { iter2->second->release(); } } CC_SAFE_RELEASE(_target); } Vector<CCBSequence*>& CCBAnimationManager::getSequences() { return _sequences; } void CCBAnimationManager::setSequences(const Vector<CCBSequence*>& seq) { _sequences = seq; } int CCBAnimationManager::getAutoPlaySequenceId() { return _autoPlaySequenceId; } void CCBAnimationManager::setAutoPlaySequenceId(int autoPlaySequenceId) { _autoPlaySequenceId = autoPlaySequenceId; } Node* CCBAnimationManager::getRootNode() { return _rootNode; } void CCBAnimationManager::setRootNode(Node *pRootNode) { _rootNode = pRootNode; } void CCBAnimationManager::setDocumentControllerName(const std::string &name) { _documentControllerName = name; } std::string CCBAnimationManager::getDocumentControllerName() { return _documentControllerName; } void CCBAnimationManager::addDocumentCallbackNode(Node *node) { _documentCallbackNodes.pushBack(node); } void CCBAnimationManager::addDocumentCallbackName(std::string name) { _documentCallbackNames.push_back(Value(name)); } void CCBAnimationManager::addDocumentCallbackControlEvents(Control::EventType eventType) { _documentCallbackControlEvents.push_back(Value(static_cast<int>(eventType))); } ValueVector& CCBAnimationManager::getDocumentCallbackNames() { return _documentCallbackNames; } Vector<Node*>& CCBAnimationManager::getDocumentCallbackNodes() { return _documentCallbackNodes; } ValueVector& CCBAnimationManager::getDocumentCallbackControlEvents() { return _documentCallbackControlEvents; } void CCBAnimationManager::addDocumentOutletNode(Node *node) { _documentOutletNodes.pushBack(node); } void CCBAnimationManager::addDocumentOutletName(std::string name) { _documentOutletNames.push_back(Value(name)); } ValueVector& CCBAnimationManager::getDocumentOutletNames() { return _documentOutletNames; } Vector<Node*>& CCBAnimationManager::getDocumentOutletNodes() { return _documentOutletNodes; } std::string CCBAnimationManager::getLastCompletedSequenceName() { return _lastCompletedSequenceName; } ValueVector& CCBAnimationManager::getKeyframeCallbacks() { return _keyframeCallbacks; } const Size& CCBAnimationManager::getRootContainerSize() { return _rootContainerSize; } void CCBAnimationManager::setRootContainerSize(const Size &rootContainerSize) { _rootContainerSize.setSize(rootContainerSize.width, rootContainerSize.height); } CCBAnimationManagerDelegate* CCBAnimationManager::getDelegate() { return _delegate; } void CCBAnimationManager::setDelegate(CCBAnimationManagerDelegate *pDelegate) { CC_SAFE_RELEASE(dynamic_cast<Ref*>(_delegate)); _delegate = pDelegate; CC_SAFE_RETAIN(dynamic_cast<Ref*>(_delegate)); } const char* CCBAnimationManager::getRunningSequenceName() { if (_runningSequence) { return _runningSequence->getName(); } return nullptr; } const Size& CCBAnimationManager::getContainerSize(Node *pNode) { if (pNode) { return pNode->getContentSize(); } else { return _rootContainerSize; } } // refer to CCBReader::readNodeGraph() for data structure of pSeq void CCBAnimationManager::addNode(Node *pNode, const std::unordered_map<int, Map<std::string, CCBSequenceProperty*>>& seq) { // pNode->retain(); _nodeSequences[pNode] = seq; } void CCBAnimationManager::setBaseValue(const Value& value, Node *pNode, const std::string& propName) { auto& props = _baseValues[pNode]; props[propName] = value; } const Value& CCBAnimationManager::getBaseValue(Node *pNode, const std::string& propName) { auto& props = _baseValues[pNode]; return props[propName]; } void CCBAnimationManager::setObject(Ref* obj, Node *pNode, const std::string& propName) { auto& props = _objects[pNode]; auto iter = props.find(propName); if (iter != props.end()) iter->second->release(); props[propName] = obj; obj->retain(); } Ref* CCBAnimationManager::getObject(Node *pNode, const std::string& propName) { auto& props = _objects[pNode]; auto iter = props.find(propName); if (iter != props.end()) return iter->second; return nullptr; } int CCBAnimationManager::getSequenceId(const char* pSequenceName) { string seqName(pSequenceName); for (auto& seq : _sequences) { if (seqName.compare(seq->getName()) == 0) { return seq->getSequenceId(); } } return -1; } CCBSequence* CCBAnimationManager::getSequence(int nSequenceId) { for (auto& seq : _sequences) { if (seq->getSequenceId() == nSequenceId) { return seq; } } return nullptr; } float CCBAnimationManager::getSequenceDuration(const char *pSequenceName) { int id = getSequenceId(pSequenceName); if (id != -1) return getSequence(id)->getDuration(); return 0; } void CCBAnimationManager::moveAnimationsFromNode(Node* fromNode, Node* toNode) { // Move base values auto baseValueIter = _baseValues.find(fromNode); if(baseValueIter != _baseValues.end()) { _baseValues[toNode] = baseValueIter->second; _baseValues.erase(baseValueIter); // fromNode->release(); // toNode->retain(); } auto objIter = _objects.find(fromNode); if (objIter != _objects.end()) { _objects[toNode] = objIter->second; _objects.erase(objIter); } // Move seqs auto seqsIter = _nodeSequences.find(fromNode); if (seqsIter != _nodeSequences.end()) { _nodeSequences[toNode] = seqsIter->second; _nodeSequences.erase(seqsIter); // fromNode->release(); // toNode->retain(); } } // Refer to CCBReader::readKeyframe() for the real type of value ActionInterval* CCBAnimationManager::getAction(CCBKeyframe *pKeyframe0, CCBKeyframe *pKeyframe1, const std::string& propName, Node *pNode) { float duration = pKeyframe1->getTime() - (pKeyframe0 ? pKeyframe0->getTime() : 0); if (propName == "rotationX") { return CCBRotateXTo::create(duration, pKeyframe1->getValue().asFloat()); } else if (propName == "rotationY") { return CCBRotateYTo::create(duration, pKeyframe1->getValue().asFloat()); } else if (propName == "rotation") { return CCBRotateTo::create(duration, pKeyframe1->getValue().asFloat()); } else if (propName == "opacity") { return FadeTo::create(duration, pKeyframe1->getValue().asByte()); } else if (propName == "color") { auto c = pKeyframe1->getValue().asValueMap(); unsigned char r = c["r"].asByte(); unsigned char g = c["g"].asByte(); unsigned char b = c["b"].asByte(); return TintTo::create(duration, r, g, b); } else if (propName == "visible") { if (pKeyframe1->getValue().asBool()) { return Sequence::createWithTwoActions(DelayTime::create(duration), Show::create()); } else { return Sequence::createWithTwoActions(DelayTime::create(duration), Hide::create()); } } else if (propName == "displayFrame") { return Sequence::createWithTwoActions(DelayTime::create(duration), CCBSetSpriteFrame::create(static_cast<SpriteFrame*>(pKeyframe1->getObject()))); } else if (propName == "position") { // Get position type auto& array = getBaseValue(pNode, propName).asValueVector(); CCBReader::PositionType type = (CCBReader::PositionType)array[2].asInt(); // Get relative position auto value = pKeyframe1->getValue().asValueVector(); float x = value[0].asFloat(); float y = value[1].asFloat(); Size containerSize = getContainerSize(pNode->getParent()); Vec2 absPos = getAbsolutePosition(Vec2(x,y), type, containerSize, propName); return MoveTo::create(duration, absPos); } else if (propName == "scale") { // Get position type auto& array = getBaseValue(pNode, propName).asValueVector(); CCBReader::ScaleType type = (CCBReader::ScaleType)array[2].asInt(); // Get relative scale auto value = pKeyframe1->getValue().asValueVector(); float x = value[0].asFloat(); float y = value[1].asFloat(); if (type == CCBReader::ScaleType::MULTIPLY_RESOLUTION) { float resolutionScale = CCBReader::getResolutionScale(); x *= resolutionScale; y *= resolutionScale; } return ScaleTo::create(duration, x, y); } else if (propName == "skew") { // Get relative skew auto& value = pKeyframe1->getValue().asValueVector(); float x = value[0].asFloat(); float y = value[1].asFloat(); return SkewTo::create(duration, x, y); } else { log("CCBReader: Failed to create animation for property: %s", propName.c_str()); } return nullptr; } void CCBAnimationManager::setAnimatedProperty(const std::string& propName, Node *pNode, const Value& value, Ref* obj, float fTweenDuration) { if (fTweenDuration > 0) { // Create a fake keyframe to generate the action from CCBKeyframe *kf1 = new (std::nothrow) CCBKeyframe(); kf1->autorelease(); kf1->setObject(obj); kf1->setValue(value); kf1->setTime(fTweenDuration); kf1->setEasingType(CCBKeyframe::EasingType::LINEAR); // Animate ActionInterval *tweenAction = getAction(nullptr, kf1, propName, pNode); pNode->runAction(tweenAction); } else { // Just set the value if (propName == "position") { // Get position type auto& array = getBaseValue(pNode, propName).asValueVector(); CCBReader::PositionType type = (CCBReader::PositionType)array[2].asInt(); // Get relative position auto& valueVector = value.asValueVector(); float x = valueVector[0].asFloat(); float y = valueVector[1].asFloat(); pNode->setPosition(getAbsolutePosition(Vec2(x,y), type, getContainerSize(pNode->getParent()), propName)); } else if (propName == "scale") { // Get scale type auto& array = getBaseValue(pNode, propName).asValueVector(); CCBReader::ScaleType type = (CCBReader::ScaleType)array[2].asInt(); // Get relative scale auto& valueVector = value.asValueVector(); float x = valueVector[0].asFloat(); float y = valueVector[1].asFloat(); setRelativeScale(pNode, x, y, type, propName); } else if(propName == "skew") { // Get relative scale auto& valueVector = value.asValueVector(); float x = valueVector[0].asFloat(); float y = valueVector[1].asFloat(); pNode->setSkewX(x); pNode->setSkewY(y); } else { // [node setValue:value forKey:name]; // TODO: only handle rotation, opacity, displayFrame, color if (propName == "rotation") { float rotate = value.asFloat(); pNode->setRotation(rotate); } else if(propName == "rotationX") { float rotate = value.asFloat(); pNode->setRotationSkewX(rotate); }else if(propName == "rotationY") { float rotate = value.asFloat(); pNode->setRotationSkewY(rotate); } else if (propName == "opacity") { unsigned char opacity = value.asByte(); pNode->setOpacity(opacity); } else if (propName == "displayFrame") { static_cast<Sprite*>(pNode)->setSpriteFrame(static_cast<SpriteFrame*>(obj)); } else if (propName == "color") { auto c = value.asValueMap(); unsigned char r = c["r"].asByte(); unsigned char g = c["g"].asByte(); unsigned char b = c["b"].asByte(); pNode->setColor(Color3B(r, g, b)); } else if (propName == "visible") { bool visible = value.asBool(); pNode->setVisible(visible); } else { log("unsupported property name is %s", propName.c_str()); CCASSERT(false, "unsupported property now"); } } } } void CCBAnimationManager::setFirstFrame(Node *pNode, CCBSequenceProperty *pSeqProp, float fTweenDuration) { auto& keyframes = pSeqProp->getKeyframes(); if (keyframes.empty()) { // Use base value (no animation) auto& baseValue = getBaseValue(pNode, pSeqProp->getName()); auto obj = getObject(pNode, pSeqProp->getName()); CCASSERT(!baseValue.isNull(), "No baseValue found for property"); setAnimatedProperty(pSeqProp->getName(), pNode, baseValue, obj, fTweenDuration); } else { // Use first keyframe CCBKeyframe *keyframe = keyframes.at(0); setAnimatedProperty(pSeqProp->getName(), pNode, keyframe->getValue(), keyframe->getObject(), fTweenDuration); } } ActionInterval* CCBAnimationManager::getEaseAction(ActionInterval *pAction, CCBKeyframe::EasingType easingType, float fEasingOpt) { if (dynamic_cast<Sequence*>(pAction)) { return pAction; } if (easingType == CCBKeyframe::EasingType::LINEAR) { return pAction; } else if (easingType == CCBKeyframe::EasingType::INSTANT) { return CCBEaseInstant::create(pAction); } else if (easingType == CCBKeyframe::EasingType::CUBIC_IN) { return EaseIn::create(pAction, fEasingOpt); } else if (easingType == CCBKeyframe::EasingType::CUBIC_OUT) { return EaseOut::create(pAction, fEasingOpt); } else if (easingType == CCBKeyframe::EasingType::CUBIC_INOUT) { return EaseInOut::create(pAction, fEasingOpt); } else if (easingType == CCBKeyframe::EasingType::BACK_IN) { return EaseBackIn::create(pAction); } else if (easingType == CCBKeyframe::EasingType::BACK_OUT) { return EaseBackOut::create(pAction); } else if (easingType == CCBKeyframe::EasingType::BACK_INOUT) { return EaseBackInOut::create(pAction); } else if (easingType == CCBKeyframe::EasingType::BOUNCE_IN) { return EaseBounceIn::create(pAction); } else if (easingType == CCBKeyframe::EasingType::BOUNCE_OUT) { return EaseBounceOut::create(pAction); } else if (easingType == CCBKeyframe::EasingType::BOUNCE_INOUT) { return EaseBounceInOut::create(pAction); } else if (easingType == CCBKeyframe::EasingType::ELASTIC_IN) { return EaseElasticIn::create(pAction, fEasingOpt); } else if (easingType == CCBKeyframe::EasingType::ELASTIC_OUT) { return EaseElasticOut::create(pAction, fEasingOpt); } else if (easingType == CCBKeyframe::EasingType::ELASTIC_INOUT) { return EaseElasticInOut::create(pAction, fEasingOpt); } else { log("CCBReader: Unknown easing type %d", static_cast<int>(easingType)); return pAction; } } Sequence* CCBAnimationManager::actionForCallbackChannel(CCBSequenceProperty* channel) { float lastKeyframeTime = 0; Vector<FiniteTimeAction*> actions; auto& keyframes = channel->getKeyframes(); ssize_t numKeyframes = keyframes.size(); for (long i = 0; i < numKeyframes; ++i) { CCBKeyframe *keyframe = keyframes.at(i); float timeSinceLastKeyframe = keyframe->getTime() - lastKeyframeTime; lastKeyframeTime = keyframe->getTime(); if(timeSinceLastKeyframe > 0) { actions.pushBack(DelayTime::create(timeSinceLastKeyframe)); } auto& keyVal = keyframe->getValue().asValueVector(); std::string selectorName = keyVal[0].asString(); CCBReader::TargetType selectorTarget = (CCBReader::TargetType)keyVal[1].asInt(); if(_jsControlled) { std::stringstream callbackName; callbackName << static_cast<int>(selectorTarget); callbackName << ":" + selectorName; auto callback = _keyframeCallFuncs.at(callbackName.str()); if (nullptr != callback) { CallFunc* callbackClone = callback->clone(); if (callbackClone != nullptr) { actions.pushBack(callbackClone); } } } else { Ref* target = nullptr; if(selectorTarget == CCBReader::TargetType::DOCUMENT_ROOT) target = _rootNode; else if (selectorTarget == CCBReader::TargetType::OWNER) target = _owner; if(target != nullptr) { if(!selectorName.empty()) { SEL_CallFuncN selCallFunc = 0; CCBSelectorResolver* targetAsCCBSelectorResolver = dynamic_cast<CCBSelectorResolver *>(target); if(targetAsCCBSelectorResolver != nullptr) { selCallFunc = targetAsCCBSelectorResolver->onResolveCCBCCCallFuncSelector(target, selectorName.c_str ()); } if(selCallFunc == 0) { CCLOG("Skipping selector '%s' since no CCBSelectorResolver is present.", selectorName.c_str()); } else { auto savedTarget = std::make_shared<Vector<Ref*>>(); savedTarget->pushBack(target); auto callback = CallFuncN::create([savedTarget, selCallFunc](Node* sender){ auto t = savedTarget->at(0); (t->*selCallFunc)(sender); }); actions.pushBack(callback); } } else { CCLOG("Unexpected empty selector."); } } } } if(actions.size() < 1) return nullptr; return Sequence::create(actions); } Sequence* CCBAnimationManager::actionForSoundChannel(CCBSequenceProperty* channel) { float lastKeyframeTime = 0; Vector<FiniteTimeAction*> actions; auto& keyframes = channel->getKeyframes(); ssize_t numKeyframes = keyframes.size(); for (int i = 0; i < numKeyframes; ++i) { CCBKeyframe *keyframe = keyframes.at(i); float timeSinceLastKeyframe = keyframe->getTime() - lastKeyframeTime; lastKeyframeTime = keyframe->getTime(); if(timeSinceLastKeyframe > 0) { actions.pushBack(DelayTime::create(timeSinceLastKeyframe)); } stringstream ss (stringstream::in | stringstream::out); auto& keyVal = keyframe->getValue().asValueVector(); std::string soundFile = keyVal[0].asString(); float pitch, pan, gain; ss << keyVal[1].asString(); ss >> pitch; ss.flush(); ss << keyVal[2].asString(); ss >> pan; ss.flush(); ss << keyVal[3].asString(); ss >> gain; ss.flush(); actions.pushBack(CCBSoundEffect::actionWithSoundFile(soundFile, pitch, pan, gain)); } if(actions.size() < 1) return nullptr; return Sequence::create(actions); } void CCBAnimationManager::runAction(Node *pNode, CCBSequenceProperty *pSeqProp, float fTweenDuration) { auto& keyframes = pSeqProp->getKeyframes(); ssize_t numKeyframes = keyframes.size(); if (numKeyframes > 1) { // Make an animation! Vector<FiniteTimeAction*> actions; CCBKeyframe *keyframeFirst = keyframes.at(0); float timeFirst = keyframeFirst->getTime() + fTweenDuration; if (timeFirst > 0) { actions.pushBack(DelayTime::create(timeFirst)); } for (ssize_t i = 0; i < numKeyframes - 1; ++i) { CCBKeyframe *kf0 = keyframes.at(i); CCBKeyframe *kf1 = keyframes.at(i+1); ActionInterval *action = getAction(kf0, kf1, pSeqProp->getName(), pNode); if (action) { // Apply easing action = getEaseAction(action, kf0->getEasingType(), kf0->getEasingOpt()); actions.pushBack(action); } } auto seq = Sequence::create(actions); pNode->runAction(seq); } } void CCBAnimationManager::runAnimations(const char *pName, float fTweenDuration) { runAnimationsForSequenceNamedTweenDuration(pName, fTweenDuration); } void CCBAnimationManager::runAnimations(const char *pName) { runAnimationsForSequenceNamed(pName); } void CCBAnimationManager::runAnimations(int nSeqId, float fTweenDuraiton) { runAnimationsForSequenceIdTweenDuration(nSeqId, fTweenDuraiton); } void CCBAnimationManager::runAnimationsForSequenceIdTweenDuration(int nSeqId, float fTweenDuration) { CCASSERT(nSeqId != -1, "Sequence id couldn't be found"); _rootNode->stopAllActions(); for (auto nodeSeqIter = _nodeSequences.begin(); nodeSeqIter != _nodeSequences.end(); ++nodeSeqIter) { Node *node = nodeSeqIter->first; node->stopAllActions(); // Refer to CCBReader::readKeyframe() for the real type of value auto seqs = nodeSeqIter->second; auto seqNodeProps = seqs[nSeqId]; std::set<std::string> seqNodePropNames; if (!seqNodeProps.empty()) { // Reset nodes that have sequence node properties, and run actions on them for (auto iter = seqNodeProps.begin(); iter != seqNodeProps.end(); ++iter) { const std::string propName = iter->first; CCBSequenceProperty *seqProp = iter->second; seqNodePropNames.insert(propName); setFirstFrame(node, seqProp, fTweenDuration); runAction(node, seqProp, fTweenDuration); } } // Reset the nodes that may have been changed by other timelines auto& nodeBaseValues = _baseValues[node]; if (!nodeBaseValues.empty()) { for (auto iter = nodeBaseValues.begin(); iter != nodeBaseValues.end(); ++iter) { if (seqNodePropNames.find(iter->first) == seqNodePropNames.end()) { setAnimatedProperty(iter->first, node, iter->second, nullptr, fTweenDuration); } } } auto& nodeObject = _objects[node]; if (!nodeObject.empty()) { for (auto iter = nodeObject.begin(); iter != nodeObject.end(); ++iter) { if (seqNodePropNames.find(iter->first) == seqNodePropNames.end()) { setAnimatedProperty(iter->first, node, Value(), iter->second, fTweenDuration); } } } } // Make callback at end of sequence CCBSequence *seq = getSequence(nSeqId); Action *completeAction = Sequence::createWithTwoActions(DelayTime::create(seq->getDuration() + fTweenDuration), CallFunc::create( CC_CALLBACK_0(CCBAnimationManager::sequenceCompleted,this))); _rootNode->runAction(completeAction); // Set the running scene if(seq->getCallbackChannel() != nullptr) { Action* action = (Action *)actionForCallbackChannel(seq->getCallbackChannel()); if(action != nullptr) { _rootNode->runAction(action); } } if(seq->getSoundChannel() != nullptr) { Action* action = (Action *)actionForSoundChannel(seq->getSoundChannel()); if(action != nullptr) { _rootNode->runAction(action); } } _runningSequence = getSequence(nSeqId); } void CCBAnimationManager::runAnimationsForSequenceNamedTweenDuration(const char *pName, float fTweenDuration) { int seqId = getSequenceId(pName); runAnimationsForSequenceIdTweenDuration(seqId, fTweenDuration); } void CCBAnimationManager::runAnimationsForSequenceNamed(const char *pName) { runAnimationsForSequenceNamedTweenDuration(pName, 0); } void CCBAnimationManager::debug() { } void CCBAnimationManager::setAnimationCompletedCallback(Ref *target, SEL_CallFunc callbackFunc) { if (target) { target->retain(); } if (_target) { _target->release(); } _target = target; _animationCompleteCallbackFunc = callbackFunc; } void CCBAnimationManager::setCallFunc(CallFunc* callFunc, const std::string &callbackNamed) { _keyframeCallFuncs.insert(callbackNamed, callFunc); } void CCBAnimationManager::sequenceCompleted() { const char *runningSequenceName = _runningSequence->getName(); int nextSeqId = _runningSequence->getChainedSequenceId(); _runningSequence = nullptr; if(_lastCompletedSequenceName != runningSequenceName) { _lastCompletedSequenceName = runningSequenceName; } if (nextSeqId != -1) { runAnimationsForSequenceIdTweenDuration(nextSeqId, 0); } if (_delegate) { // There may be another runAnimation() call in this delegate method // which will assign _runningSequence _delegate->completedAnimationSequenceNamed(runningSequenceName); } if (_target && _animationCompleteCallbackFunc) { (_target->*_animationCompleteCallbackFunc)(); } } // Custom actions /************************************************************ CCBSetSpriteFrame ************************************************************/ CCBSetSpriteFrame* CCBSetSpriteFrame::create(SpriteFrame *pSpriteFrame) { CCBSetSpriteFrame *ret = new (std::nothrow) CCBSetSpriteFrame(); if (ret) { if (ret->initWithSpriteFrame(pSpriteFrame)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool CCBSetSpriteFrame::initWithSpriteFrame(SpriteFrame *pSpriteFrame) { _spriteFrame = pSpriteFrame; CC_SAFE_RETAIN(_spriteFrame); return true; } CCBSetSpriteFrame::~CCBSetSpriteFrame() { CC_SAFE_RELEASE_NULL(_spriteFrame); } CCBSetSpriteFrame* CCBSetSpriteFrame::clone() const { // no copy constructor auto a = new (std::nothrow) CCBSetSpriteFrame(); a->initWithSpriteFrame(_spriteFrame); a->autorelease(); return a; } CCBSetSpriteFrame* CCBSetSpriteFrame::reverse() const { // returns a copy of itself return this->clone(); } void CCBSetSpriteFrame::update(float time) { static_cast<Sprite*>(_target)->setSpriteFrame(_spriteFrame); } /************************************************************ CCBSoundEffect ************************************************************/ CCBSoundEffect* CCBSoundEffect::actionWithSoundFile(const std::string &filename, float pitch, float pan, float gain) { CCBSoundEffect* pRet = new (std::nothrow) CCBSoundEffect(); if (pRet != nullptr && pRet->initWithSoundFile(filename, pitch, pan, gain)) { pRet->autorelease(); } else { CC_SAFE_DELETE(pRet); } return pRet; } CCBSoundEffect::~CCBSoundEffect() { } bool CCBSoundEffect::initWithSoundFile(const std::string &filename, float pitch, float pan, float gain) { _soundFile = filename; _pitch = pitch; _pan = pan; _gain = gain; return true; } CCBSoundEffect* CCBSoundEffect::clone() const { // no copy constructor auto a = new (std::nothrow) CCBSoundEffect(); a->initWithSoundFile(_soundFile, _pitch, _pan, _gain); a->autorelease(); return a; } CCBSoundEffect* CCBSoundEffect::reverse() const { // returns a copy of itself return this->clone(); } void CCBSoundEffect::update(float time) { CocosDenshion::SimpleAudioEngine::getInstance()->playEffect(_soundFile.c_str()); } /************************************************************ CCBRotateTo ************************************************************/ CCBRotateTo* CCBRotateTo::create(float fDuration, float fAngle) { CCBRotateTo *ret = new (std::nothrow) CCBRotateTo(); if (ret) { if (ret->initWithDuration(fDuration, fAngle)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool CCBRotateTo::initWithDuration(float fDuration, float fAngle) { if (ActionInterval::initWithDuration(fDuration)) { _dstAngle = fAngle; return true; } else { return false; } } CCBRotateTo* CCBRotateTo::clone() const { // no copy constructor auto a = new (std::nothrow) CCBRotateTo(); a->initWithDuration(_duration, _dstAngle); a->autorelease(); return a; } CCBRotateTo* CCBRotateTo::reverse() const { CCASSERT(false, "reverse() is not supported in CCBRotateTo"); return nullptr; } void CCBRotateTo::startWithTarget(Node *pNode) { ActionInterval::startWithTarget(pNode); _startAngle = _target->getRotation(); _diffAngle = _dstAngle - _startAngle; } void CCBRotateTo::update(float time) { _target->setRotation(_startAngle + (_diffAngle * time)) ; } /************************************************************ CCBRotateXTO ************************************************************/ CCBRotateXTo* CCBRotateXTo::create(float fDuration, float fAngle) { CCBRotateXTo *ret = new (std::nothrow) CCBRotateXTo(); if (ret) { if (ret->initWithDuration(fDuration, fAngle)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool CCBRotateXTo::initWithDuration(float fDuration, float fAngle) { if (ActionInterval::initWithDuration(fDuration)) { _dstAngle = fAngle; return true; } else { return false; } } void CCBRotateXTo::startWithTarget(Node *pNode) { //CCActionInterval::startWithTarget(pNode); _originalTarget = pNode; _target = pNode; _elapsed = 0.0f; _firstTick = true; _startAngle = _target->getRotationSkewX(); _diffAngle = _dstAngle - _startAngle; } CCBRotateXTo* CCBRotateXTo::clone() const { // no copy constructor auto a = new (std::nothrow) CCBRotateXTo(); a->initWithDuration(_duration, _dstAngle); a->autorelease(); return a; } CCBRotateXTo* CCBRotateXTo::reverse() const { CCASSERT(false, "reverse() is not supported in CCBRotateXTo"); return nullptr; } void CCBRotateXTo::update(float time) { _target->setRotationSkewX(_startAngle + (_diffAngle * time)); } /************************************************************ CCBRotateYTO ************************************************************/ CCBRotateYTo* CCBRotateYTo::create(float fDuration, float fAngle) { CCBRotateYTo *ret = new (std::nothrow) CCBRotateYTo(); if (ret) { if (ret->initWithDuration(fDuration, fAngle)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool CCBRotateYTo::initWithDuration(float fDuration, float fAngle) { if (ActionInterval::initWithDuration(fDuration)) { _dstAngle = fAngle; return true; } else { return false; } } CCBRotateYTo* CCBRotateYTo::clone() const { // no copy constructor auto a = new (std::nothrow) CCBRotateYTo(); a->initWithDuration(_duration, _dstAngle); a->autorelease(); return a; } CCBRotateYTo* CCBRotateYTo::reverse() const { CCASSERT(false, "reverse() is not supported in CCBRotateXTo"); return nullptr; } void CCBRotateYTo::startWithTarget(Node *pNode) { // ActionInterval::startWithTarget(pNode); _originalTarget = pNode; _target = pNode; _elapsed = 0.0f; _firstTick = true; _startAngle = _target->getRotationSkewY(); _diffAngle = _dstAngle - _startAngle; } void CCBRotateYTo::update(float time) { _target->setRotationSkewY(_startAngle + (_diffAngle * time)); } /************************************************************ CCBEaseInstant ************************************************************/ CCBEaseInstant* CCBEaseInstant::create(ActionInterval *pAction) { CCBEaseInstant *pRet = new (std::nothrow) CCBEaseInstant(); if (pRet && pRet->initWithAction(pAction)) { pRet->autorelease(); } else { CC_SAFE_RELEASE_NULL(pRet); } return pRet; } CCBEaseInstant* CCBEaseInstant::clone() const { // no copy constructor auto a = new (std::nothrow) CCBEaseInstant(); a->initWithAction(_inner); a->autorelease(); return a; } CCBEaseInstant* CCBEaseInstant::reverse() const { return CCBEaseInstant::create(_inner->reverse()); } void CCBEaseInstant::update(float dt) { if (dt < 0) { _inner->update(0); } else { _inner->update(1); } } }