#include "REDAnimationManager.h" #include "CCNodeLoader.h" #include "REDReader.h" #include "CCNode+REDRelativePositioning.h" #include "audio/include/AudioEngine.h" #include "REDSelectorResolver.h" #include #include #include #include #include "common/CocosConfig.h" #include "BezierEqualPointsAction.hpp" #include "REDActionInstant.h" #include "RedWise.hpp" using namespace cocos2d; using namespace std; using namespace cocos2d::extension; using namespace experimental; namespace redream { // Implementation of REDAinmationManager #define LE_CHR(a,b,c,d) ( ((a)<<24) | ((b)<<16) | ((c)<<8) | (d) ) static int animationTag = LE_CHR('c','c','b','i'); REDAnimationManager::REDAnimationManager() : _owner(nullptr) , _autoPlaySequenceId(0) , _rootNode(nullptr) , _rootContainerSize(Size::ZERO) , _delegate(nullptr) , _runningSequence(std::make_pair(nullptr, nullptr)) , _speed(1.0f) , _listen(nullptr) , _lastTag(0) , _nowTag(0) { init(); } REDAnimationManager *REDAnimationManager::fromNode(Node *node) { return dynamic_cast(node->getUserObject()); } bool REDAnimationManager::init() { _target = nullptr; _animationCompleteCallbackFunc = nullptr; return true; } REDAnimationManager::~REDAnimationManager() { // 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(); } if (!_needResetSpriteFrames.empty()) { _needResetSpriteFrames.clear(); } 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& REDAnimationManager::getSequences() { return _sequences; } void REDAnimationManager::setSequences(const Vector& seq) { _sequences = seq; } int REDAnimationManager::getAutoPlaySequenceId() { return _autoPlaySequenceId; } void REDAnimationManager::setAutoPlaySequenceId(int autoPlaySequenceId) { _autoPlaySequenceId = autoPlaySequenceId; } Node* REDAnimationManager::getRootNode() { return _rootNode; } void REDAnimationManager::setRootNode(Node *pRootNode) { _rootNode = pRootNode; } void REDAnimationManager::setDocumentControllerName(const std::string &name) { _documentControllerName = name; } std::string REDAnimationManager::getDocumentControllerName() { return _documentControllerName; } void REDAnimationManager::addDocumentCallbackNode(Node *node) { _documentCallbackNodes.pushBack(node); } void REDAnimationManager::addDocumentCallbackName(std::string name) { _documentCallbackNames.push_back(Value(name)); } void REDAnimationManager::addDocumentCallbackControlEvents(Control::EventType eventType) { _documentCallbackControlEvents.push_back(Value(static_cast(eventType))); } ValueVector& REDAnimationManager::getDocumentCallbackNames() { return _documentCallbackNames; } Vector& REDAnimationManager::getDocumentCallbackNodes() { return _documentCallbackNodes; } ValueVector& REDAnimationManager::getDocumentCallbackControlEvents() { return _documentCallbackControlEvents; } void REDAnimationManager::addDocumentOutletNode(Node *node) { _documentOutletNodes.pushBack(node); } void REDAnimationManager::addDocumentOutletName(std::string name) { _documentOutletNames.push_back(Value(name)); } ValueVector& REDAnimationManager::getDocumentOutletNames() { return _documentOutletNames; } Vector& REDAnimationManager::getDocumentOutletNodes() { return _documentOutletNodes; } std::string REDAnimationManager::getLastCompletedSequenceName() { return _lastCompletedSequenceName; } ValueVector& REDAnimationManager::getKeyframeCallbacks() { return _keyframeCallbacks; } const Size& REDAnimationManager::getRootContainerSize() { return _rootContainerSize; } void REDAnimationManager::setRootContainerSize(const Size &rootContainerSize) { _rootContainerSize.setSize(rootContainerSize.width, rootContainerSize.height); } REDAnimationManagerDelegate* REDAnimationManager::getDelegate() { return _delegate; } void REDAnimationManager::setDelegate(REDAnimationManagerDelegate *pDelegate) { CC_SAFE_RELEASE(dynamic_cast(_delegate)); _delegate = pDelegate; CC_SAFE_RETAIN(dynamic_cast(_delegate)); } const char* REDAnimationManager::getRunningSequenceName() { if (_runningSequence.first) { return _runningSequence.first->getName(); } return nullptr; } const Size& REDAnimationManager::getContainerSize(Node *pNode) { if (pNode) { return pNode->getContentSize(); } else { return _rootContainerSize; } } // refer to REDReader::readNodeGraph() for data structure of pSeq void REDAnimationManager::addNode(Node *pNode, const std::unordered_map>& seq) { // pNode->retain(); _nodeSequences[pNode] = seq; } void REDAnimationManager::setBaseValue(const Value& value, Node *pNode, const std::string& propName) { auto& props = _baseValues[pNode]; props[propName] = value; } const Value& REDAnimationManager::getBaseValue(Node *pNode, const std::string& propName) { auto& props = _baseValues[pNode]; return props[propName]; } void REDAnimationManager::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* REDAnimationManager::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 REDAnimationManager::getSequenceId(const char* pSequenceName) { string seqName(pSequenceName); for (auto& seq : _sequences) { if (seqName.compare(seq->getName()) == 0) { return seq->getSequenceId(); } } return -1; } REDSequence* REDAnimationManager::getSequence(int nSequenceId) { for (auto& seq : _sequences) { if (seq->getSequenceId() == nSequenceId) { return seq; } } return nullptr; } float REDAnimationManager::getSequenceDuration(const char *pSequenceName) { int id = getSequenceId(pSequenceName); if (id != -1) return getSequence(id)->getDuration(); return 0; } std::string REDAnimationManager::getREDFileName(){ return _ccbFileName; } void REDAnimationManager::setREDFileName(std::string filename){ _ccbFileName = filename; } void REDAnimationManager::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 REDReader::readKeyframe() for the real type of value ActionInterval* REDAnimationManager::getAction(REDKeyframe *pKeyframe0, REDKeyframe *pKeyframe1, const std::string& propName, Node *pNode) { float duration = pKeyframe1->getTime() - (pKeyframe0 ? pKeyframe0->getTime() : 0); if (propName == "rotationX") { return REDRotateXTo::create(duration, pKeyframe1->getValue().asFloat()); } else if (propName == "rotationY") { return REDRotateYTo::create(duration, pKeyframe1->getValue().asFloat()); } else if (propName == "rotation") { return REDRotateTo::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), REDSetSpriteFrame::create(static_cast(pKeyframe1->getObject()))); } else if (propName == "position") { /* // Get position type auto& array = getBaseValue(pNode, propName).asValueVector(); REDReader::PositionType type = (REDReader::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);*/ auto& array = getBaseValue(pNode, propName).asValueVector(); PositionReferenceCorner corner = (PositionReferenceCorner)array[2].asInt(); PositionUnit xUnit = (PositionUnit)array[3].asInt(); PositionUnit yUnit = (PositionUnit)array[4].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(1.0f, 1.0f, Vec2(x,y), corner, xUnit, yUnit, containerSize); // return MoveTo::create(duration, absPos); std::vector equalPoints = pKeyframe0->getEqualPoints(); std::vector newEqualPoints = {}; for (Vec2 point : equalPoints) { Vec2 newPoint = getAbsolutePosition(1.0f, 1.0f, point, corner, xUnit, yUnit, containerSize); newEqualPoints.push_back(newPoint); } if (!newEqualPoints.empty()) { // 有贝塞尔信息 return BezierEqualPointsAction::create(duration, newEqualPoints); } else { // 没有贝塞尔信息,直线运动 return MoveTo::create(duration, absPos); } } else if (propName == "scale") { // Get position type auto& array = getBaseValue(pNode, propName).asValueVector(); REDReader::ScaleType type = (REDReader::ScaleType)array[2].asInt(); // Get relative scale auto value = pKeyframe1->getValue().asValueVector(); float x = value[0].asFloat(); float y = value[1].asFloat(); if (type == REDReader::ScaleType::MULTIPLY_RESOLUTION) { float resolutionScale = REDReader::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 if (propName == "frame") { auto value0 = pKeyframe1->getValue().asValueMap(); std::string anim = value0["animation"].asString(); bool loop = value0["loop"].asBool(); spine::SkeletonFrame frame; frame.animation = anim; frame.progress = 0.0f; frame.loop = loop; return Sequence::createWithTwoActions(DelayTime::create(duration), spine::SpineActionInstant::create(frame)); //TODO // log("REDReader: TODO implement the spine action !!!"); }else if (propName == "animation") { // Get sequence id int value = pKeyframe1->getValue().asInt(); return Sequence::createWithTwoActions(DelayTime::create(duration), REDAnimation::create(value)); } else if (propName == "frameIndex") { return REDFrameIndexTo::create(duration, pKeyframe0->getValue().asByte(), pKeyframe1->getValue().asByte()); } else if (propName == "posVar"){ //粒子发射器大小 auto& value = pKeyframe1->getValue().asValueVector(); float x = value[0].asFloat(); float y = value[1].asFloat(); return REDParticlePosVarTo::create(duration, Vec2(x,y)); } else if (propName == "gravity"){ // 粒子重力 auto& value = pKeyframe1->getValue().asValueVector(); float x = value[0].asFloat(); float y = value[1].asFloat(); return REDGravityTo::create(duration, Vec2(x,y)); } else if(propName == "speed"){ // 粒子速度 auto& value = pKeyframe1->getValue().asValueVector(); float x = value[0].asFloat(); float y = value[1].asFloat(); return REDParticleSpeedTo::create(duration, Vec2(x,y)); } else if(propName == "life"){ // 粒子生命 auto& value = pKeyframe1->getValue().asValueVector(); float x = value[0].asFloat(); float y = value[1].asFloat(); return REDParticleLifeTo::create(duration, Vec2(x,y)); } else if(propName == "startSize"){ // 初始尺寸 auto& value = pKeyframe1->getValue().asValueVector(); float x = value[0].asFloat(); float y = value[1].asFloat(); return REDParticleStartSizeTo::create(duration, Vec2(x,y)); } else if(propName == "endSize"){ // 结束尺寸 auto& value = pKeyframe1->getValue().asValueVector(); float x = value[0].asFloat(); float y = value[1].asFloat(); return REDParticleEndSizeTo::create(duration, Vec2(x,y)); } else if(propName == "startSpin"){ // 开始旋转角度: auto& value = pKeyframe1->getValue().asValueVector(); float x = value[0].asFloat(); float y = value[1].asFloat(); return REDParticleStartSpinTo::create(duration, Vec2(x,y)); } else if(propName == "endSpin"){ // 结束旋转角度 auto& value = pKeyframe1->getValue().asValueVector(); float x = value[0].asFloat(); float y = value[1].asFloat(); return REDParticleEndSpinTo::create(duration, Vec2(x,y)); } else if(propName == "angle"){ // 发射角度 auto& value = pKeyframe1->getValue().asValueVector(); float x = value[0].asFloat(); float y = value[1].asFloat(); return REDParticleAngleTo::create(duration, Vec2(x,y)); } else if(propName == "tangentialAccel"){ // 切向加速度 auto& value = pKeyframe1->getValue().asValueVector(); float x = value[0].asFloat(); float y = value[1].asFloat(); return REDParticleTangentialAccelTo::create(duration, Vec2(x,y)); } else if(propName == "radialAccel"){ // 径向加速度: auto& value = pKeyframe1->getValue().asValueVector(); float x = value[0].asFloat(); float y = value[1].asFloat(); return REDParticleRadialAccelTo::create(duration, Vec2(x,y)); } else if(propName == "startRadius"){ // 开始半径: auto& value = pKeyframe1->getValue().asValueVector(); float x = value[0].asFloat(); float y = value[1].asFloat(); return REDParticleStartRadiusTo::create(duration, Vec2(x,y)); } else if(propName == "endRadius"){ // 结束半径 auto& value = pKeyframe1->getValue().asValueVector(); float x = value[0].asFloat(); float y = value[1].asFloat(); return REDParticleEndRadiusTo::create(duration, Vec2(x,y)); } else if(propName == "rotatePerSecond"){ // 旋转: auto& value = pKeyframe1->getValue().asValueVector(); float x = value[0].asFloat(); float y = value[1].asFloat(); return REDParticleRotatePerSecondTo::create(duration, Vec2(x,y)); } else if(propName == "enabled"){ if (pKeyframe1->getValue().asBool()) { return Sequence::createWithTwoActions(DelayTime::create(duration), Enable::create()); } else { return Sequence::createWithTwoActions(DelayTime::create(duration), Disable::create()); } } else if(propName == "string"){ std::string text = pKeyframe1->getValue().asString(); return Sequence::createWithTwoActions(DelayTime::create(duration), REDLabelString::actionWithText(text)); } else if (propName == "useMaterial") { if (pKeyframe1->getValue().asBool()) { return Sequence::createWithTwoActions(DelayTime::create(duration), EnableMaterial::create()); } else { return Sequence::createWithTwoActions(DelayTime::create(duration), DisableMaterial::create()); } } else if (propName == "bakeAnimation") { RedBakeNodeFrame frame; frame.animationName = pKeyframe1->getValue().asValueVector()[0].asString(); frame.elapsedTime = 0; frame.loop = pKeyframe1->getValue().asValueVector()[2].asBool();; return Sequence::createWithTwoActions(DelayTime::create(duration), RedBakeAnimationInstantAction::create(frame)); } else { log("REDReader: Failed to create animation for property: %s", propName.c_str()); } return nullptr; } void REDAnimationManager::setAnimatedProperty(const std::string& propName, Node *pNode, const Value& value, Ref* obj, float fTweenDuration, bool isBaseValue) { if (fTweenDuration > 0) { // Create a fake keyframe to generate the action from REDKeyframe *kf1 = new (std::nothrow) REDKeyframe(); kf1->autorelease(); kf1->setObject(obj); kf1->setValue(value); kf1->setTime(fTweenDuration); kf1->setEasingType(REDKeyframe::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(); REDReader::PositionType type = (REDReader::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)); pNode->setPosition(getAbsolutePosition(Vec2(x,y), type, getContainerSize(pNode->getParent()), propName));*/ // Get position type auto& array = getBaseValue(pNode, propName).asValueVector(); PositionReferenceCorner corner = (PositionReferenceCorner)array[2].asInt(); PositionUnit xUnit = (PositionUnit)array[3].asInt(); PositionUnit yUnit = (PositionUnit)array[4].asInt(); // Get relative position auto& valueVector = value.asValueVector(); float x = valueVector[0].asFloat(); float y = valueVector[1].asFloat(); pNode->setPosition(getAbsolutePosition(1.0f, 1.0f, Vec2(x,y), corner, xUnit, yUnit, getContainerSize(pNode->getParent()))); } else if (propName == "scale") { // Get scale type auto& array = getBaseValue(pNode, propName).asValueVector(); REDReader::ScaleType type = (REDReader::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 if (propName == "animation") { int sequenceId = value.asInt(); REDAnimationManager *animationManager = REDAnimationManager::fromNode(pNode); if(animationManager) { if(sequenceId == -2 || sequenceId == -1) animationManager->refreshStatusOnFirstFream(animationManager->getAutoPlaySequenceId(), 0); else animationManager->refreshStatusOnFirstFream(sequenceId, 0); } } else if (propName == "frame") { auto frame = value.asValueMap(); std::string anim = frame["animation"].asString(); auto node = static_cast(pNode); if(strcmp(anim.c_str(), "Null") == 0 || strcmp(anim.c_str(), "") == 0){ node->setEmptyAnimations(0); node->update(0); } else { node->clearTrack(); node->setAnimation(0, anim, false); node->update(0); node->clearTrack(); } } 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(pNode)->setSpriteFrame(static_cast(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 if (propName == "frameIndex") { unsigned char frameIndex = value.asByte(); static_cast(pNode)->setFrameIndex(frameIndex); } else if (propName == "posVar"){ // 粒子发射器尺寸 auto& valueVector = value.asValueVector(); float gx = valueVector[0].asFloat(); float gy = valueVector[1].asFloat(); static_cast(pNode)->setPosVar(Vec2(gx, gy)); } else if (propName == "gravity") { // 粒子重力 auto& valueVector = value.asValueVector(); float gx = valueVector[0].asFloat(); float gy = valueVector[1].asFloat(); static_cast(pNode)->setGravity(Vec2(gx, gy)); } else if (propName == "speed") { // 粒子速度 auto& valueVector = value.asValueVector(); float speed = valueVector[0].asFloat(); float speedVar = valueVector[1].asFloat(); static_cast(pNode)->setSpeed(speed); static_cast(pNode)->setSpeedVar(speedVar); } else if(propName == "life"){ // 粒子生命 auto& valueVector = value.asValueVector(); float speed = valueVector[0].asFloat(); float speedVar = valueVector[1].asFloat(); static_cast(pNode)->setLife(speed); static_cast(pNode)->setLifeVar(speedVar); } else if(propName == "startSize"){ // 初始尺寸 auto& valueVector = value.asValueVector(); float speed = valueVector[0].asFloat(); float speedVar = valueVector[1].asFloat(); static_cast(pNode)->setStartSize(speed); static_cast(pNode)->setStartSizeVar(speedVar); } else if(propName == "endSize"){ // 结束尺寸 auto& valueVector = value.asValueVector(); float speed = valueVector[0].asFloat(); float speedVar = valueVector[1].asFloat(); static_cast(pNode)->setEndSize(speed); static_cast(pNode)->setEndSizeVar(speedVar); } else if(propName == "startSpin"){ // 开始旋转角度: auto& valueVector = value.asValueVector(); float speed = valueVector[0].asFloat(); float speedVar = valueVector[1].asFloat(); static_cast(pNode)->setStartSpin(speed); static_cast(pNode)->setStartSpinVar(speedVar); } else if(propName == "endSpin"){ // 结束旋转角度 auto& valueVector = value.asValueVector(); float speed = valueVector[0].asFloat(); float speedVar = valueVector[1].asFloat(); static_cast(pNode)->setEndSpin(speed); static_cast(pNode)->setEndSpinVar(speedVar); } else if(propName == "angle"){ // 发射角度 auto& valueVector = value.asValueVector(); float speed = valueVector[0].asFloat(); float speedVar = valueVector[1].asFloat(); static_cast(pNode)->setAngle(speed); static_cast(pNode)->setAngleVar(speedVar); } else if(propName == "tangentialAccel"){ // 切向加速度 auto& valueVector = value.asValueVector(); float speed = valueVector[0].asFloat(); float speedVar = valueVector[1].asFloat(); static_cast(pNode)->setTangentialAccel(speed); static_cast(pNode)->setTangentialAccelVar(speedVar); } else if(propName == "radialAccel"){ // 径向加速度: auto& valueVector = value.asValueVector(); float speed = valueVector[0].asFloat(); float speedVar = valueVector[1].asFloat(); static_cast(pNode)->setRadialAccel(speed); static_cast(pNode)->setRadialAccelVar(speedVar); } else if(propName == "startRadius"){ // 开始半径: auto& valueVector = value.asValueVector(); float speed = valueVector[0].asFloat(); float speedVar = valueVector[1].asFloat(); static_cast(pNode)->setStartSpin(speed); static_cast(pNode)->setStartSpinVar(speedVar); } else if(propName == "endRadius"){ // 结束半径 auto& valueVector = value.asValueVector(); float speed = valueVector[0].asFloat(); float speedVar = valueVector[1].asFloat(); static_cast(pNode)->setEndRadius(speed); static_cast(pNode)->setEndRadiusVar(speedVar); } else if(propName == "rotatePerSecond"){ // 旋转: auto& valueVector = value.asValueVector(); float speed = valueVector[0].asFloat(); float speedVar = valueVector[1].asFloat(); static_cast(pNode)->setRotatePerSecond(speed); static_cast(pNode)->setRotatePerSecondVar(speedVar); } else if (propName == "enabled") { bool enabled = value.asBool(); static_cast(pNode)->setEnabled(enabled); } else if(propName == "string"){ auto value = getBaseValue(pNode, propName); static_cast(pNode)->setString(value.asString()); } else if (propName == "useMaterial") { auto isUseMaterial = value.asBool(); static_cast(pNode)->setMaterialEnable(isUseMaterial); } else if (propName == "bakeAnimation") { RedBakeNodeFrame frame; frame.animationName = value.asValueVector()[0].asString(); frame.elapsedTime = 0; frame.loop = value.asValueVector()[2].asBool(); RedBakeNode *bakeNode = dynamic_cast(pNode); bakeNode->setBakeFrame(frame); } else { log("unsupported property name is %s", propName.c_str()); CCASSERT(false, "unsupported property now"); } } } } void REDAnimationManager::setFirstFrame(Node *pNode, REDSequenceProperty *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, false); } else { // Use first keyframe REDKeyframe *keyframe = keyframes.at(0); setAnimatedProperty(pSeqProp->getName(), pNode, keyframe->getValue(), keyframe->getObject(), fTweenDuration, false); } } ActionInterval* REDAnimationManager::getEaseAction(ActionInterval *pAction, REDKeyframe::EasingType easingType, float* fEasingOpt) { if (dynamic_cast(pAction)) { return pAction; } if (easingType == REDKeyframe::EasingType::LINEAR) { return pAction; } else if (easingType == REDKeyframe::EasingType::INSTANT) { return REDEaseInstant::create(pAction); } else if (easingType == REDKeyframe::EasingType::CUBIC_IN) { return EaseIn::create(pAction, *fEasingOpt); } else if (easingType == REDKeyframe::EasingType::CUBIC_OUT) { return EaseOut::create(pAction, *fEasingOpt); } else if (easingType == REDKeyframe::EasingType::CUBIC_INOUT) { return EaseInOut::create(pAction, *fEasingOpt); } else if (easingType == REDKeyframe::EasingType::BACK_IN) { return EaseBackIn::create(pAction); } else if (easingType == REDKeyframe::EasingType::BACK_OUT) { return EaseBackOut::create(pAction); } else if (easingType == REDKeyframe::EasingType::BACK_INOUT) { return EaseBackInOut::create(pAction); } else if (easingType == REDKeyframe::EasingType::BOUNCE_IN) { return EaseBounceIn::create(pAction); } else if (easingType == REDKeyframe::EasingType::BOUNCE_OUT) { return EaseBounceOut::create(pAction); } else if (easingType == REDKeyframe::EasingType::BOUNCE_INOUT) { return EaseBounceInOut::create(pAction); } else if (easingType == REDKeyframe::EasingType::ELASTIC_IN) { return EaseElasticIn::create(pAction, *fEasingOpt); } else if (easingType == REDKeyframe::EasingType::ELASTIC_OUT) { return EaseElasticOut::create(pAction, *fEasingOpt); } else if (easingType == REDKeyframe::EasingType::ELASTIC_INOUT) { return EaseElasticInOut::create(pAction, *fEasingOpt); } //add new else if (easingType == REDKeyframe::EasingType::SineIn) { return EaseSineIn::create(pAction); } else if (easingType == REDKeyframe::EasingType::SineOut) { return EaseSineOut::create(pAction); } else if (easingType == REDKeyframe::EasingType::SineInOut) { return EaseSineInOut::create(pAction); } else if (easingType == REDKeyframe::EasingType::ExponentialIn) { return EaseExponentialIn::create(pAction); } else if (easingType == REDKeyframe::EasingType::ExponentialOut) { return EaseExponentialOut::create(pAction); } else if (easingType == REDKeyframe::EasingType::ExponentialInOut) { return EaseExponentialInOut::create(pAction); } else if (easingType == REDKeyframe::EasingType::CircleActionIn) { return EaseCircleActionIn::create(pAction); } else if (easingType == REDKeyframe::EasingType::CircleActionOut) { return EaseCircleActionOut::create(pAction); } else if (easingType == REDKeyframe::EasingType::CircleActionInOut) { return EaseCircleActionInOut::create(pAction); } else if (easingType == REDKeyframe::EasingType::QuadraticActionIn) { return EaseQuadraticActionIn::create(pAction); } else if (easingType == REDKeyframe::EasingType::QuadraticActionOut) { return EaseQuadraticActionOut::create(pAction); } else if (easingType == REDKeyframe::EasingType::QuadraticActionInOut) { return EaseQuadraticActionInOut::create(pAction); } else if (easingType == REDKeyframe::EasingType::CubicActionIn) { return EaseCubicActionIn::create(pAction); } else if (easingType == REDKeyframe::EasingType::CubicActionOut) { return EaseCubicActionOut::create(pAction); } else if (easingType == REDKeyframe::EasingType::CubicActionInOut) { return EaseCubicActionInOut::create(pAction); } else if (easingType == REDKeyframe::EasingType::QuarticActionIn) { return EaseQuarticActionIn::create(pAction); } else if (easingType == REDKeyframe::EasingType::QuarticActionOut) { return EaseQuarticActionOut::create(pAction); } else if (easingType == REDKeyframe::EasingType::QuarticActionInOut) { return EaseQuarticActionInOut::create(pAction); } else if (easingType == REDKeyframe::EasingType::QuinticActionIn) { return EaseQuinticActionIn::create(pAction); } else if (easingType == REDKeyframe::EasingType::QuinticActionOut) { return EaseQuinticActionOut::create(pAction); } else if (easingType == REDKeyframe::EasingType::QuinticActionInOut) { return EaseQuinticActionInOut::create(pAction); } else if (easingType == REDKeyframe::EasingType::Custom) { auto ease = EaseBezierByTimeAction::create(pAction); ease->setBezierParamer(fEasingOpt[0], fEasingOpt[1], fEasingOpt[2], fEasingOpt[3]); return ease; } else { log("REDReader: Unknown easing type %d", static_cast(easingType)); return pAction; } } Sequence* REDAnimationManager::actionForCallbackChannel(REDSequenceProperty* channel) { float lastKeyframeTime = 0; Vector actions; auto& keyframes = channel->getKeyframes(); ssize_t numKeyframes = keyframes.size(); for (long i = 0; i < numKeyframes; ++i) { REDKeyframe *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(); REDReader::TargetType selectorTarget = (REDReader::TargetType)keyVal[1].asInt(); Ref* target = nullptr; if(selectorTarget == REDReader::TargetType::DOCUMENT_ROOT) target = _rootNode; else if (selectorTarget == REDReader::TargetType::OWNER) target = _owner; if (selectorTarget == REDReader::TargetType::REDWISE_EVENT) { CallFunc* wiseCall = CallFunc::create([=](){ EventCustom wiseEvent("REDAnimationManager_ActionForCallbackChannel_RedWiseEvent"); string name = selectorName; wiseEvent.setUserData(&name); Director::getInstance()->getEventDispatcher()->dispatchEvent(&wiseEvent); }); actions.pushBack(wiseCall); continue; } if(target != nullptr) { if(!selectorName.empty()) { SEL_CallFuncN selCallFunc = 0; REDSelectorResolver* targetAsREDSelectorResolver = dynamic_cast(target); if(targetAsREDSelectorResolver != nullptr) { selCallFunc = targetAsREDSelectorResolver->onResolveREDCCCallFuncSelector(target, selectorName.c_str ()); } if(selCallFunc == 0) { CCLOG("Skipping selector '%s' since no REDSelectorResolver is present.", selectorName.c_str()); } else { auto savedTarget = std::make_shared>(); savedTarget->pushBack(target); ///bug : 若actions不析构,将会导致target无法释放,出现内存泄漏 auto callback = CallFuncN::create([savedTarget, selectorName,selCallFunc](Node* sender){ Director::getInstance()->getEventDispatcher()->dispatchCustomEvent("__CCCallFuncSelector__"+selectorName); 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* REDAnimationManager::actionForSoundChannel(REDSequenceProperty* channel) { float lastKeyframeTime = 0; Vector actions; auto& keyframes = channel->getKeyframes(); ssize_t numKeyframes = keyframes.size(); for (int i = 0; i < numKeyframes; ++i) { REDKeyframe *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 = 0.0f, pan = 0.0f, gain = 0.0f; 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(REDSoundEffect::actionWithSoundFile(soundFile, pitch, pan, gain)); } if(actions.size() < 1) return nullptr; return Sequence::create(actions); } Sequence* REDAnimationManager::actionForWiseChannel(REDSequenceProperty* channel) { float lastKeyframeTime = 0; Vector actions; auto& keyframes = channel->getKeyframes(); ssize_t numKeyframes = keyframes.size(); for (int i = 0; i < numKeyframes; ++i) { REDKeyframe *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 btnFileName = keyVal.at(0).asString(); std::string eventName = keyVal.at(1).asString(); bool forcePostEvent = keyVal.at(2).asBool(); const ValueVector& params = keyVal.at(3).asValueVector(); actions.pushBack(REDWiseEffect::actionWithConfig(btnFileName, eventName, forcePostEvent, params)); } if(actions.size() < 1) return nullptr; return Sequence::create(actions); } void REDAnimationManager::runAction(Node *pNode, REDSequenceProperty *pSeqProp, float fTweenDuration) { auto& keyframes = pSeqProp->getKeyframes(); ssize_t numKeyframes = keyframes.size(); const char* propType = pSeqProp->getName(); if (numKeyframes > 1) { // Make an animation! Vector actions; REDKeyframe *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) { REDKeyframe *kf0 = keyframes.at(i); REDKeyframe *kf1 = keyframes.at(i+1); if(i == 0 && (strcmp(propType, "animation") == 0 || strcmp(propType, "frame") == 0 || strcmp(propType, "string") == 0 || strcmp(propType, "bakeAnimation") == 0)){ //第一个关键帧,子red文件和spine动画需要处理一下 ActionInterval *action = getAction(kf0, kf0, pSeqProp->getName(), pNode); actions.pushBack(action); } ActionInterval *action = getAction(kf0, kf1, pSeqProp->getName(), pNode); if (action) { // Apply easing action = getEaseAction(action, kf0->getEasingType(), kf0->getEasingOpt()); actions.pushBack(action); } } //add song auto seq = Sequence::create(actions); auto speed = Speed::create(seq, _speed); speed->setTag(101); pNode->runAction(speed); } else if (numKeyframes == 1 && (strcmp(propType, "animation") == 0 || strcmp(propType, "frame") == 0 || strcmp(propType, "bakeAnimation"))) { // Make an animation! Vector actions; REDKeyframe *keyframeFirst = keyframes.at(0); float timeFirst = keyframeFirst->getTime() + fTweenDuration; if (timeFirst > 0) { actions.pushBack(DelayTime::create(timeFirst)); } ActionInterval *action = getAction(keyframeFirst, keyframeFirst, pSeqProp->getName(), pNode); actions.pushBack(action); //add song auto seq = Sequence::create(actions); auto speed = Speed::create(seq, _speed); speed->setTag(101); pNode->runAction(speed); } } void REDAnimationManager::updateSpeed(float speed, Node* node) { std::vector actions; _rootNode->getActionManager()->getActionsByTag(101, node, actions); std::vector::iterator iter = actions.begin(); while (iter != actions.end()) { Speed* sp = dynamic_cast(*iter); if (sp != nullptr) { sp->setSpeed(_speed); } iter ++; } Vector children = node->getChildren(); Vector::iterator iter2 = children.begin(); while (iter2 != children.end()) { updateSpeed(speed, *iter2); iter2 ++; } } void REDAnimationManager::updateSpeed(float speed) { _speed = speed; updateSpeed(speed, _rootNode); } void REDAnimationManager::runAnimations(const char *pName, float fTweenDuration) { runAnimationsForSequenceNamedTweenDuration(pName, fTweenDuration); } void REDAnimationManager::runAnimations(const char *pName) { runAnimationsForSequenceNamed(pName); } void REDAnimationManager::runAnimationsWithTag(int nSeqId, int tag){ _lastTag = _nowTag; _nowTag = tag; runAnimationsForSequenceIdTweenDuration(nSeqId, 0); } void REDAnimationManager::runAnimationsWithListen(int nSeqId, REDAnimationManagerDelegate* listen){ runAnimationsForSequenceIdTweenDuration(nSeqId, 0, nullptr, listen); } void REDAnimationManager::runAnimations(int nSeqId, float fTweenDuraiton) { runAnimationsForSequenceIdTweenDuration(nSeqId, fTweenDuraiton); } void REDAnimationManager::refreshStatusOnFirstFream(int nSeqId, float fTweenDuration){ REDSequence* lastSeq = _runningSequence.first; auto lastCallback = _runningSequence.second; _runningSequence.first = nullptr; _runningSequence.second = nullptr; stopRootNodeAction(lastSeq, lastCallback); resetAllChildrenAnimtion(nSeqId, fTweenDuration, false); } void REDAnimationManager::runAnimationsForSequenceIdTweenDuration(int nSeqId, float fTweenDuration, const std::function &callback, REDAnimationManagerDelegate* listen) { REDSequence *seq = getSequence(nSeqId); CCASSERT(seq, "Sequence id couldn't be found"); REDSequence* lastSeq = _runningSequence.first; auto lastCallback = _runningSequence.second; _runningSequence.first = seq; _runningSequence.second = callback; stopRootNodeAction(lastSeq, lastCallback); resetAllChildrenAnimtion(nSeqId, fTweenDuration, true); _listen = listen; // Set the running scene if(seq->getCallbackChannel() != nullptr) { Action* action = (Action *)actionForCallbackChannel(seq->getCallbackChannel()); if(action != nullptr) { action->setTag(animationTag); _rootNode->runAction(action); _runningActions[_rootNode].pushBack(action); } } if(seq->getSoundChannel() != nullptr) { Action* action = (Action *)actionForSoundChannel(seq->getSoundChannel()); if(action != nullptr) { action->setTag(animationTag); _rootNode->runAction(action); _runningActions[_rootNode].pushBack(action); } } if (seq->getWiseChannel() != nullptr) { Action* action = (Action *)actionForWiseChannel(seq->getWiseChannel()); if (action != nullptr) { action->setTag(animationTag); _rootNode->runAction(action); _runningActions[_rootNode].pushBack(action); } } // Make callback at end of sequence Action *completeAction = Sequence::createWithTwoActions(DelayTime::create(seq->getDuration() + fTweenDuration), CallFunc::create(std::bind(&REDAnimationManager::sequenceCompleted, this, callback))); completeAction->setTag(animationTag); _rootNode->runAction(completeAction); _runningActions[_rootNode].pushBack(completeAction); } //add by djd Spawn* REDAnimationManager::getNodeAniByName(const char *pName, Node* pNode,Vec2 orginPos){ Spawn *tAction = nullptr; int nSeqId = getSequenceId(pName); for (auto nodeSeqIter = _nodeSequences.begin(); nodeSeqIter != _nodeSequences.end(); ++nodeSeqIter) { Node *node = nodeSeqIter->first; if (node != pNode) { continue; } // Refer to REDReader::readKeyframe() for the real type of value auto seqs = nodeSeqIter->second; auto seqNodeProps = seqs[nSeqId]; if (!seqNodeProps.empty()) { // Reset nodes that have sequence node properties, and run actions on them Vector seqList; for (auto iter = seqNodeProps.begin(); iter != seqNodeProps.end(); ++iter) { const std::string propName = iter->first; REDSequenceProperty *pSeqProp = iter->second; auto& keyframes = pSeqProp->getKeyframes(); ssize_t numKeyframes = keyframes.size(); if (numKeyframes > 1) { // Make an animation! Vector actions; REDKeyframe *keyframeFirst = keyframes.at(0); float timeFirst = keyframeFirst->getTime(); if (timeFirst > 0) { actions.pushBack(DelayTime::create(timeFirst)); } for (ssize_t i = 0; i < numKeyframes - 1; ++i) { REDKeyframe *kf0 = keyframes.at(i); REDKeyframe *kf1 = keyframes.at(i+1); ActionInterval *action = nullptr; //重写position if (strcmp(pSeqProp->getName(), "position") == 0) { float duration = kf1->getTime() - (kf0 ? kf0->getTime() : 0); // Get position type auto& array = getBaseValue(pNode, propName).asValueVector(); REDReader::PositionType type = (REDReader::PositionType)array[2].asInt(); // Get relative position auto value = kf1->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); action = MoveTo::create(duration, Vec2(absPos.x + orginPos.x, absPos.y + orginPos.y)); }else{ 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); seqList.pushBack(seq); } } tAction = Spawn::create(seqList); } break; } return tAction; } void REDAnimationManager::runAnimationsForSequenceNamedTweenDuration(const char *pName, float fTweenDuration, const std::function &callback) { int seqId = getSequenceId(pName); if (seqId != -1) { runAnimationsForSequenceIdTweenDuration(seqId, fTweenDuration, callback); }else{ CCASSERT(false, "Sequence id couldn't be found"); } } void REDAnimationManager::runAnimationsForSequenceNamed(const char *pName) { runAnimationsForSequenceNamedTweenDuration(pName, 0); } void REDAnimationManager::debug() { } void REDAnimationManager::setAnimationCompletedCallback(Ref *target, SEL_CallFunc callbackFunc) { if (target) { target->retain(); } if (_target) { _target->release(); } _target = target; _animationCompleteCallbackFunc = callbackFunc; } void REDAnimationManager::setCallFunc(CallFunc* callFunc, const std::string &callbackNamed) { _keyframeCallFuncs.insert(callbackNamed, callFunc); } void REDAnimationManager::sequenceCompleted(const std::function &callback) { REDSequence* sequence = _runningSequence.first; const char *runningSequenceName = sequence->getName(); int seqId = sequence->getSequenceId(); int nextSeqId = sequence->getChainedSequenceId(); _runningSequence.first = nullptr; _runningSequence.second = nullptr; if(_lastCompletedSequenceName != runningSequenceName) { _lastCompletedSequenceName = runningSequenceName; } if (nextSeqId != -1) { if(callback) { callback(_rootNode, AnimationCompleteType::CHAINED); } REDAnimationManagerDelegate* animationManagerDelegate = dynamic_cast(_rootNode); if (animationManagerDelegate) { // 方式1 新加的 用强转触发 //播完时间线,自动播放下一条 animationManagerDelegate->completedAnimationAndPlayNextSequenceNamed(runningSequenceName, seqId, _nowTag); animationManagerDelegate->completedAnimationSequenceNamed(runningSequenceName, seqId, _nowTag); } else if (_delegate) { // 方式2 原有的 用代理触发 //播完时间线,自动播放下一条 _delegate->completedAnimationAndPlayNextSequenceNamed(runningSequenceName, seqId, _nowTag); _delegate->completedAnimationSequenceNamed(runningSequenceName, seqId, _nowTag); } if(_listen){ //播完时间线,自动播放下一条 auto listen = _listen; _listen = nullptr; listen->completedAnimationAndPlayNextSequenceNamed(runningSequenceName, seqId, _nowTag); listen->completedAnimationSequenceNamed(runningSequenceName, seqId, _nowTag); } runAnimationsForSequenceIdTweenDuration(nextSeqId, 0, callback); } else { if(callback){ callback(_rootNode, AnimationCompleteType::COMPLETED); } REDAnimationManagerDelegate* animationManagerDelegate = dynamic_cast(_rootNode); if (animationManagerDelegate) { // 方式1 新加的 用强转触发 animationManagerDelegate->completedAnimationSequenceNamed(runningSequenceName, seqId, _nowTag); } else if (_delegate) { // 方式2 原有的 // There may be another runAnimation() call in this delegate method // which will assign _runningSequence _delegate->completedAnimationSequenceNamed(runningSequenceName, seqId, _nowTag); } if(_listen){ auto listen = _listen; _listen = nullptr; listen->completedAnimationSequenceNamed(runningSequenceName, seqId, _nowTag); } } } void REDAnimationManager::stopAllNodeAction(){ _lastTag = _nowTag; REDSequence* lastSeq = _runningSequence.first; auto lastCallback = _runningSequence.second; _runningSequence.first = nullptr; _runningSequence.second = nullptr; stopRootNodeAction(lastSeq, lastCallback); for (auto nodeSeqIter = _nodeSequences.begin(); nodeSeqIter != _nodeSequences.end(); ++nodeSeqIter) { Node *node = nodeSeqIter->first; node->stopAllActions(); } } //MARK: - 私有封装 void REDAnimationManager::stopRootNodeAction(REDSequence* sequence, std::function callback){ // REDSequence* sequence = _runningSequence.first; if(sequence) { // if(_runningSequence.second){ // _runningSequence.second(_rootNode, AnimationCompleteType::STOPED); // } if(callback){ callback(_rootNode, AnimationCompleteType::STOPED); } const char *runningSequenceName = sequence->getName(); int seqId = sequence->getSequenceId(); REDAnimationManagerDelegate* animationManagerDelegate = dynamic_cast(_rootNode); if (animationManagerDelegate) { // 方式1 新加的 用强转触发 animationManagerDelegate->stopAnimationSequenceNamed(runningSequenceName, seqId, _lastTag); } else if (_delegate) { // 方式2 原有的 用代理触发 _delegate->stopAnimationSequenceNamed(runningSequenceName, seqId, _lastTag); } if(_listen){ auto listen = _listen; _listen = nullptr; listen->stopAnimationSequenceNamed(runningSequenceName, seqId, _lastTag); } } // _runningSequence.first = nullptr; // _runningSequence.second = nullptr; for(const auto &pair:_runningActions) { for(const auto action:pair.second) pair.first->stopAction(action); } _runningActions.clear(); } void REDAnimationManager::resetAllChildrenAnimtion(int nSeqId, float fTweenDuration, bool isRunAction){ for (auto nodeSeqIter = _nodeSequences.begin(); nodeSeqIter != _nodeSequences.end(); ++nodeSeqIter) { Node *node = nodeSeqIter->first; node->stopAllActions(); // Refer to REDReader::readKeyframe() for the real type of value auto seqs = nodeSeqIter->second; auto seqNodeProps = seqs[nSeqId]; std::set 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; REDSequenceProperty *seqProp = iter->second; seqNodePropNames.insert(propName); setFirstFrame(node, seqProp, fTweenDuration); if(isRunAction){ 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,true); } } } 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,true); } } } } } //void REDAnimationManager::addListen(REDAnimationManagerDelegate* pDelegate){ // _listen = pDelegate; //} // //void REDAnimationManager::removeListen(REDAnimationManagerDelegate* pDelegate){ // _listen = nullptr; //} #pragma mark - Begin BatchNode ///add by songqingyu void REDAnimationManager::setREDRootPath(std::string redRootPath){ _redRootPath = redRootPath; } void REDAnimationManager::setReaderPlist(std::unordered_set plistSt,std::unordered_set replacePlistSt){ _readerPlistSt = plistSt; _repleacePlistSt=replacePlistSt; } void REDAnimationManager::addDisplayFrameKeykframe(REDKeyframe* kf){ _needResetSpriteFrames.pushBack(kf); } void REDAnimationManager::addSpriteFrameForNode(cocos2d::Node* pNode,const std::string& propName,const std::string& spriteFile,const std::string& spriteSheet){ _needResetObjProps[pNode][propName] = {spriteFile,spriteSheet}; } void REDAnimationManager::resetSpriteFrameOfAllChildrenAnimtion(){ for (REDKeyframe *kf : _needResetSpriteFrames) { const ValueVector& vv = kf->getValue().asValueVector(); std::string spriteSheet = vv[0].asString(); std::string spriteFile = vv[1].asString(); kf->setObject(getSpriteFrameByName(spriteFile, spriteSheet)); } for (auto it : _needResetObjProps) { for (auto pp : it.second) { SpriteFrame* sf = dynamic_cast(getObject(it.first, pp.first)); if (sf) { SpriteFrame* tmp = getSpriteFrameByName(pp.second[0], pp.second[1]); if(sf != tmp && tmp){ setObject(tmp, it.first, pp.first); } } } } } /// cocos2d::SpriteFrame* REDAnimationManager::getSpriteFrameByName(const string& spriteFile,const string& spriteSheet,bool useDefaultEmpty){ cocos2d::SpriteFrame* spriteFrame = nullptr; SpriteFrameCache* frameCache = SpriteFrameCache::getInstance(); TextureCache* textCache = Director::getInstance()->getTextureCache(); spriteFrame = frameCache->getSpriteFrameByName(spriteFile,_readerPlistSt); if (spriteFrame == nullptr) { if (CocosConfig::getIgnoreCCBPath()) { string spFile = _redRootPath + spriteFile; Texture2D * texture = textCache->addImage(spFile.c_str()); if(texture != NULL) { Rect bounds = Rect(0, 0, texture->getContentSize().width, texture->getContentSize().height); spriteFrame = SpriteFrame::createWithTexture(texture, bounds); if (spriteFrame) { spriteFrame->setTextureFilename(spriteFile); } } } else{ if (spriteSheet.empty()) { string spFile = _redRootPath + spriteFile; Texture2D * texture = textCache->addImage(spFile.c_str()); if(texture != NULL) { Rect bounds = Rect(0, 0, texture->getContentSize().width, texture->getContentSize().height); spriteFrame = SpriteFrame::createWithTexture(texture, bounds); if (spriteFrame) { spriteFrame->setTextureFilename(spFile); } } } else { string spSheet = _redRootPath + spriteSheet; frameCache->addSpriteFramesWithFile(spSheet); spriteFrame = frameCache->getSpriteFrameByName(spriteFile,{spSheet}); } } } //add by djd 防止崩溃,用默认空白图 if (!spriteFrame&&useDefaultEmpty) { string spFile = CocosConfig::getDefaultEmptyPic(); Texture2D * texture = textCache->addImage(spFile.c_str()); if(texture != NULL) { Rect bounds = Rect(0, 0, texture->getContentSize().width, texture->getContentSize().height); spriteFrame = SpriteFrame::createWithTexture(texture, bounds); if (spriteFrame) { spriteFrame->setTextureFilename(spFile); } } } return spriteFrame; } ///add by songqingyu #pragma mark End BatchNode - // Custom actions /************************************************************ REDSetSpriteFrame ************************************************************/ REDSetSpriteFrame* REDSetSpriteFrame::create(SpriteFrame *pSpriteFrame) { REDSetSpriteFrame *ret = new (std::nothrow) REDSetSpriteFrame(); if (ret) { if (ret->initWithSpriteFrame(pSpriteFrame)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDSetSpriteFrame::initWithSpriteFrame(SpriteFrame *pSpriteFrame) { _spriteFrame = pSpriteFrame; CC_SAFE_RETAIN(_spriteFrame); return true; } REDSetSpriteFrame::~REDSetSpriteFrame() { CC_SAFE_RELEASE_NULL(_spriteFrame); } REDSetSpriteFrame* REDSetSpriteFrame::clone() const { // no copy constructor auto a = new (std::nothrow) REDSetSpriteFrame(); a->initWithSpriteFrame(_spriteFrame); a->autorelease(); return a; } REDSetSpriteFrame* REDSetSpriteFrame::reverse() const { // returns a copy of itself return this->clone(); } void REDSetSpriteFrame::update(float time) { ActionInstant::update(time); static_cast(_target)->setSpriteFrame(_spriteFrame); } /************************************************************ REDSoundEffect ************************************************************/ REDSoundEffect* REDSoundEffect::actionWithSoundFile(const std::string &filename, float pitch, float pan, float gain) { REDSoundEffect* pRet = new (std::nothrow) REDSoundEffect(); if (pRet != nullptr && pRet->initWithSoundFile(filename, pitch, pan, gain)) { pRet->autorelease(); } else { CC_SAFE_DELETE(pRet); } return pRet; } /************************************************************ REDWiseEffect ************************************************************/ REDWiseEffect* REDWiseEffect::actionWithConfig(const std::string &btnFileName, const std::string &eventName, bool forcePostEvent, const ValueVector ¶ms) { REDWiseEffect* pRet = new (std::nothrow) REDWiseEffect(); if (pRet != nullptr && pRet->initWithConfig(btnFileName, eventName, forcePostEvent, params)) { pRet->autorelease(); } else { CC_SAFE_RELEASE(pRet); } return pRet; } REDWiseEffect::~REDWiseEffect() {} bool REDWiseEffect::initWithConfig(const std::string &btnFileName, const std::string &eventName, bool forcePostEvent, const ValueVector ¶ms) { _btnFileName = btnFileName; _eventName = eventName; _forcePostEvent = forcePostEvent; _params = params; return true; } REDWiseEffect* REDWiseEffect::clone() const { // no copy constructor auto a = new (std::nothrow) REDWiseEffect(); a->initWithConfig(_btnFileName, _eventName, _forcePostEvent, _params); a->autorelease(); return a; } REDWiseEffect* REDWiseEffect::reverse() const { // returns a copy of itself return this->clone(); } void REDWiseEffect::update(float time) { ActionInstant::update(time); if (!CocosConfig::getCCBAudioEnable()) return; std::vector params; for (const auto & paramVector : _params) { const auto & vec = paramVector.asValueVector(); std::string key = vec.at(0).asString(); float value = vec.at(1).asFloat(); RWRedreamParam param; param.name = key; param.value = value; param.min = 0.0f; param.max = 0.0f; params.push_back(param); } RedWise::getInstance()->postEventByBnk(_btnFileName, _eventName, params, _forcePostEvent); } /************************************************************ REDAnimation ************************************************************/ REDAnimation* REDAnimation::create(int animationId) { REDAnimation *ret = new (std::nothrow) REDAnimation(); if (ret) { if (ret->initWithAnimationId(animationId)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDAnimation::initWithAnimationId(int animationId) { _animationId = animationId; return true; } REDAnimation::~REDAnimation() { } REDAnimation* REDAnimation::clone() const { // no copy constructor auto a = new (std::nothrow) REDAnimation(); a->initWithAnimationId(_animationId); a->autorelease(); return a; } REDAnimation* REDAnimation::reverse() const { // returns a copy of itself return this->clone(); } void REDAnimation::update(float time) { REDAnimationManager *manager = REDAnimationManager::fromNode(_target); if(manager){ if(_animationId == -2 || _animationId == -1){ // 选择了默认或者空,去获取自动播放的时间线 _animationId = manager->getAutoPlaySequenceId(); } if(_animationId == -1){ //没有回去到auto时间线 manager->refreshStatusOnFirstFream(_animationId, 0.0f); } else { manager->runAnimationsForSequenceIdTweenDuration(_animationId, 0.0f); } } } REDSoundEffect::~REDSoundEffect() { } bool REDSoundEffect::initWithSoundFile(const std::string &filename, float pitch, float pan, float gain) { _soundFile = filename; _pitch = pitch; _pan = pan; _gain = gain; return true; } REDSoundEffect* REDSoundEffect::clone() const { // no copy constructor auto a = new (std::nothrow) REDSoundEffect(); a->initWithSoundFile(_soundFile, _pitch, _pan, _gain); a->autorelease(); return a; } REDSoundEffect* REDSoundEffect::reverse() const { // returns a copy of itself return this->clone(); } void REDSoundEffect::update(float time) { ActionInstant::update(time); if (!CocosConfig::getCCBAudioEnable()) return; // AudioEngine::play2d(_soundFile); ///强制改为播放wwise const std::string& eventName = _soundFile.substr(0, _soundFile.rfind(".")); RedWise::getInstance()->postEvent(eventName); } /************************************************************ REDLabelString ************************************************************/ REDLabelString* REDLabelString::actionWithText(const std::string &text) { REDLabelString* pRet = new (std::nothrow) REDLabelString(); if (pRet != nullptr && pRet->initWithText(text)) { pRet->autorelease(); } else { CC_SAFE_DELETE(pRet); } return pRet; } REDLabelString::~REDLabelString() { } bool REDLabelString::initWithText(const std::string &text) { _text = text; return true; } REDLabelString* REDLabelString::clone() const { // no copy constructor auto a = new (std::nothrow) REDLabelString(); a->initWithText(_text); a->autorelease(); return a; } REDLabelString* REDLabelString::reverse() const { // returns a copy of itself return this->clone(); } void REDLabelString::update(float time) { ActionInstant::update(time); auto label = static_cast(_target); auto model = label->getLocalizationModel(); if(model.isLocalization) { if(model.isCustom) { auto text = LocalizationMgr::getInstance()->getString(_text, model.customFilePath); static_cast(_target)->setString(text); } else { auto text = LocalizationMgr::getInstance()->getString(_text, LOCALIZATION_DEFAULT_FILE); static_cast(_target)->setString(text); } } else { static_cast(_target)->setString(_text); } } /************************************************************ REDRotateTo ************************************************************/ REDRotateTo* REDRotateTo::create(float fDuration, float fAngle) { REDRotateTo *ret = new (std::nothrow) REDRotateTo(); if (ret) { if (ret->initWithDuration(fDuration, fAngle)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDRotateTo::initWithDuration(float fDuration, float fAngle) { if (ActionInterval::initWithDuration(fDuration)) { _dstAngle = fAngle; return true; } else { return false; } } REDRotateTo* REDRotateTo::clone() const { // no copy constructor auto a = new (std::nothrow) REDRotateTo(); a->initWithDuration(_duration, _dstAngle); a->autorelease(); return a; } REDRotateTo* REDRotateTo::reverse() const { CCASSERT(false, "reverse() is not supported in REDRotateTo"); return nullptr; } void REDRotateTo::startWithTarget(Node *pNode) { ActionInterval::startWithTarget(pNode); _startAngle = _target->getRotation(); _diffAngle = _dstAngle - _startAngle; } void REDRotateTo::update(float time) { _target->setRotation(_startAngle + (_diffAngle * time)) ; } /************************************************************ REDRotateXTO ************************************************************/ REDRotateXTo* REDRotateXTo::create(float fDuration, float fAngle) { REDRotateXTo *ret = new (std::nothrow) REDRotateXTo(); if (ret) { if (ret->initWithDuration(fDuration, fAngle)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDRotateXTo::initWithDuration(float fDuration, float fAngle) { if (ActionInterval::initWithDuration(fDuration)) { _dstAngle = fAngle; return true; } else { return false; } } void REDRotateXTo::startWithTarget(Node *pNode) { //CCActionInterval::startWithTarget(pNode); _originalTarget = pNode; _target = pNode; _elapsed = 0.0f; _firstTick = true; _startAngle = _target->getRotationSkewX(); _diffAngle = _dstAngle - _startAngle; } REDRotateXTo* REDRotateXTo::clone() const { // no copy constructor auto a = new (std::nothrow) REDRotateXTo(); a->initWithDuration(_duration, _dstAngle); a->autorelease(); return a; } REDRotateXTo* REDRotateXTo::reverse() const { CCASSERT(false, "reverse() is not supported in REDRotateXTo"); return nullptr; } void REDRotateXTo::update(float time) { _target->setRotationSkewX(_startAngle + (_diffAngle * time)); } /************************************************************ REDRotateYTO ************************************************************/ REDRotateYTo* REDRotateYTo::create(float fDuration, float fAngle) { REDRotateYTo *ret = new (std::nothrow) REDRotateYTo(); if (ret) { if (ret->initWithDuration(fDuration, fAngle)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDRotateYTo::initWithDuration(float fDuration, float fAngle) { if (ActionInterval::initWithDuration(fDuration)) { _dstAngle = fAngle; return true; } else { return false; } } REDRotateYTo* REDRotateYTo::clone() const { // no copy constructor auto a = new (std::nothrow) REDRotateYTo(); a->initWithDuration(_duration, _dstAngle); a->autorelease(); return a; } REDRotateYTo* REDRotateYTo::reverse() const { CCASSERT(false, "reverse() is not supported in REDRotateXTo"); return nullptr; } void REDRotateYTo::startWithTarget(Node *pNode) { // ActionInterval::startWithTarget(pNode); _originalTarget = pNode; _target = pNode; _elapsed = 0.0f; _firstTick = true; _startAngle = _target->getRotationSkewY(); _diffAngle = _dstAngle - _startAngle; } void REDRotateYTo::update(float time) { _target->setRotationSkewY(_startAngle + (_diffAngle * time)); } /************************************************************ REDFrameIndexTo ************************************************************/ REDFrameIndexTo* REDFrameIndexTo::create(float fDuration, int startIndex, int endIndex) { REDFrameIndexTo *ret = new (std::nothrow) REDFrameIndexTo(); if (ret) { if (ret->initWithDuration(fDuration, startIndex, endIndex)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDFrameIndexTo::initWithDuration(float fDuration, int startIndex, int endIndex) { if (ActionInterval::initWithDuration(fDuration)) { _startIndex = startIndex; _endIndex = endIndex; return true; } else { return false; } } REDFrameIndexTo* REDFrameIndexTo::clone() const { auto a = new (std::nothrow) REDFrameIndexTo(); a->initWithDuration(_duration, _startIndex, _endIndex); a->autorelease(); return a; } REDFrameIndexTo* REDFrameIndexTo::reverse() const { CCASSERT(false, "reverse() is not supported in REDFrameIndexTo"); return nullptr; } void REDFrameIndexTo::startWithTarget(cocos2d::Node *pNode) { ActionInterval::startWithTarget(pNode); _diffIndex = _endIndex - _startIndex; } void REDFrameIndexTo::update(float time) { auto fasp = dynamic_cast(_target); CCASSERT(fasp != nullptr, "REDFrameIndexTo 只支持 ZGFrameActionSprite类型的图片"); auto frameIndex = (int)(_startIndex + (_diffIndex * time)); fasp->setFrameIndex(frameIndex); } /************************************************************ REDParticlePosVarTo ************************************************************/ REDParticlePosVarTo* REDParticlePosVarTo::create(float fDuration, cocos2d::Vec2 pos){ REDParticlePosVarTo *ret = new (std::nothrow) REDParticlePosVarTo(); if (ret) { if (ret->initWithDuration(fDuration, pos)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDParticlePosVarTo::initWithDuration(float fDuration, cocos2d::Vec2 pos){ if (ActionInterval::initWithDuration(fDuration)) { _endGravity = pos; return true; } else { return false; } } REDParticlePosVarTo* REDParticlePosVarTo::clone() const { // no copy constructor auto a = new (std::nothrow) REDParticlePosVarTo(); a->initWithDuration(_duration, _endGravity); a->autorelease(); return a; } REDParticlePosVarTo* REDParticlePosVarTo::reverse() const { CCASSERT(false, "reverse() is not supported in REDParticlePosVarTo"); return nullptr; } void REDParticlePosVarTo::startWithTarget(cocos2d::Node *pNode) { ActionInterval::startWithTarget(pNode); _startGravity = dynamic_cast(pNode)->getPosVar(); _diffGravity = _endGravity - _startGravity; } void REDParticlePosVarTo::update(float time){ auto fasp = dynamic_cast(_target); CCASSERT(fasp != nullptr, "REDGravityTo 只支持 ZMLCCParticleSystem"); auto gravity = _startGravity + (_diffGravity * time); fasp->setPosVar(gravity); } /************************************************************ REDGravityTo ************************************************************/ REDGravityTo* REDGravityTo::create(float fDuration, cocos2d::Vec2 gravity){ REDGravityTo *ret = new (std::nothrow) REDGravityTo(); if (ret) { if (ret->initWithDuration(fDuration, gravity)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDGravityTo::initWithDuration(float fDuration, cocos2d::Vec2 gravity){ if (ActionInterval::initWithDuration(fDuration)) { _endGravity = gravity; return true; } else { return false; } } REDGravityTo* REDGravityTo::clone() const { // no copy constructor auto a = new (std::nothrow) REDGravityTo(); a->initWithDuration(_duration, _endGravity); a->autorelease(); return a; } REDGravityTo* REDGravityTo::reverse() const { CCASSERT(false, "reverse() is not supported in REDGravityTo"); return nullptr; } void REDGravityTo::startWithTarget(cocos2d::Node *pNode) { ActionInterval::startWithTarget(pNode); _startGravity = dynamic_cast(pNode)->getGravity(); _diffGravity = _endGravity - _startGravity; } void REDGravityTo::update(float time){ auto fasp = dynamic_cast(_target); CCASSERT(fasp != nullptr, "REDGravityTo 只支持 ZMLCCParticleSystem"); auto gravity = _startGravity + (_diffGravity * time); fasp->setGravity(gravity); } /************************************************************ REDParticleSpeedTo ************************************************************/ //粒子速度 REDParticleSpeedTo* REDParticleSpeedTo::create(float fDuration, cocos2d::Vec2 gravity){ REDParticleSpeedTo *ret = new (std::nothrow) REDParticleSpeedTo(); if (ret) { if (ret->initWithDuration(fDuration, gravity)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDParticleSpeedTo::initWithDuration(float fDuration, cocos2d::Vec2 folatVar){ if (ActionInterval::initWithDuration(fDuration)) { _endFloatVar = folatVar; return true; } else { return false; } } REDParticleSpeedTo* REDParticleSpeedTo::clone() const { // no copy constructor auto a = new (std::nothrow) REDParticleSpeedTo(); a->initWithDuration(_duration, _endFloatVar); a->autorelease(); return a; } REDParticleSpeedTo* REDParticleSpeedTo::reverse() const { CCASSERT(false, "reverse() is not supported in REDParticleSpeedTo"); return nullptr; } void REDParticleSpeedTo::startWithTarget(cocos2d::Node *pNode) { ActionInterval::startWithTarget(pNode); float a = dynamic_cast(pNode)->getSpeed(); float aVar = dynamic_cast(pNode)->getSpeedVar(); _startFloatVar = Vec2(a, aVar); _diffFloatVar = _endFloatVar - _startFloatVar; } void REDParticleSpeedTo::update(float time){ auto par = dynamic_cast(_target); CCASSERT(par != nullptr, "REDParticleSpeedTo 只支持 ZMLCCParticleSystem"); auto floatVar = _startFloatVar + (_diffFloatVar * time); par->setSpeed(floatVar.x); par->setSpeedVar(floatVar.y); } /************************************************************ REDParticleLifeTo ************************************************************/ //粒子生命 REDParticleLifeTo* REDParticleLifeTo::create(float fDuration, cocos2d::Vec2 folatVar){ REDParticleLifeTo *ret = new (std::nothrow) REDParticleLifeTo(); if (ret) { if (ret->initWithDuration(fDuration, folatVar)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDParticleLifeTo::initWithDuration(float fDuration, cocos2d::Vec2 folatVar){ if (ActionInterval::initWithDuration(fDuration)) { _endFloatVar = folatVar; return true; } else { return false; } } REDParticleLifeTo* REDParticleLifeTo::clone() const { // no copy constructor auto a = new (std::nothrow) REDParticleLifeTo(); a->initWithDuration(_duration, _endFloatVar); a->autorelease(); return a; } REDParticleLifeTo* REDParticleLifeTo::reverse() const { CCASSERT(false, "reverse() is not supported in REDParticleLifeTo"); return nullptr; } void REDParticleLifeTo::startWithTarget(cocos2d::Node *pNode) { ActionInterval::startWithTarget(pNode); float a = dynamic_cast(pNode)->getLife(); float aVar = dynamic_cast(pNode)->getLifeVar(); _startFloatVar = Vec2(a, aVar); _diffFloatVar = _endFloatVar - _startFloatVar; } void REDParticleLifeTo::update(float time){ auto par = dynamic_cast(_target); CCASSERT(par != nullptr, "REDParticleSpeedTo 只支持 ZMLCCParticleSystem"); auto floatVar = _startFloatVar + (_diffFloatVar * time); par->setLife(floatVar.x); par->setLifeVar(floatVar.y); } /************************************************************ REDParticleStartSizeTo ************************************************************/ //粒子初始尺寸 REDParticleStartSizeTo* REDParticleStartSizeTo::create(float fDuration, cocos2d::Vec2 folatVar){ REDParticleStartSizeTo *ret = new (std::nothrow) REDParticleStartSizeTo(); if (ret) { if (ret->initWithDuration(fDuration, folatVar)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDParticleStartSizeTo::initWithDuration(float fDuration, cocos2d::Vec2 folatVar){ if (ActionInterval::initWithDuration(fDuration)) { _endFloatVar = folatVar; return true; } else { return false; } } REDParticleStartSizeTo* REDParticleStartSizeTo::clone() const { // no copy constructor auto a = new (std::nothrow) REDParticleStartSizeTo(); a->initWithDuration(_duration, _endFloatVar); a->autorelease(); return a; } REDParticleStartSizeTo* REDParticleStartSizeTo::reverse() const { CCASSERT(false, "reverse() is not supported in REDParticleStartSizeTo"); return nullptr; } void REDParticleStartSizeTo::startWithTarget(cocos2d::Node *pNode) { ActionInterval::startWithTarget(pNode); float a = dynamic_cast(pNode)->getStartSize(); float aVar = dynamic_cast(pNode)->getStartSizeVar(); _startFloatVar = Vec2(a, aVar); _diffFloatVar = _endFloatVar - _startFloatVar; } void REDParticleStartSizeTo::update(float time){ auto par = dynamic_cast(_target); CCASSERT(par != nullptr, "REDParticleSpeedTo 只支持 ZMLCCParticleSystem"); auto floatVar = _startFloatVar + (_diffFloatVar * time); par->setStartSize(floatVar.x); par->setStartSizeVar(floatVar.y); } /************************************************************ REDParticleEndSizeTo ************************************************************/ //粒子结束时的尺寸大小 REDParticleEndSizeTo* REDParticleEndSizeTo::create(float fDuration, cocos2d::Vec2 folatVar){ REDParticleEndSizeTo *ret = new (std::nothrow) REDParticleEndSizeTo(); if (ret) { if (ret->initWithDuration(fDuration, folatVar)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDParticleEndSizeTo::initWithDuration(float fDuration, cocos2d::Vec2 folatVar){ if (ActionInterval::initWithDuration(fDuration)) { _endFloatVar = folatVar; return true; } else { return false; } } REDParticleEndSizeTo* REDParticleEndSizeTo::clone() const { // no copy constructor auto a = new (std::nothrow) REDParticleEndSizeTo(); a->initWithDuration(_duration, _endFloatVar); a->autorelease(); return a; } REDParticleEndSizeTo* REDParticleEndSizeTo::reverse() const { CCASSERT(false, "reverse() is not supported in REDParticleEndSizeTo"); return nullptr; } void REDParticleEndSizeTo::startWithTarget(cocos2d::Node *pNode) { ActionInterval::startWithTarget(pNode); float a = dynamic_cast(pNode)->getEndSize(); float aVar = dynamic_cast(pNode)->getEndSizeVar(); _startFloatVar = Vec2(a, aVar); _diffFloatVar = _endFloatVar - _startFloatVar; } void REDParticleEndSizeTo::update(float time){ auto par = dynamic_cast(_target); CCASSERT(par != nullptr, "REDParticleSpeedTo 只支持 ZMLCCParticleSystem"); auto floatVar = _startFloatVar + (_diffFloatVar * time); par->setEndSize(floatVar.x); par->setEndSizeVar(floatVar.y); } /************************************************************ REDParticleStartSpinTo ************************************************************/ //粒子速度 REDParticleStartSpinTo* REDParticleStartSpinTo::create(float fDuration, cocos2d::Vec2 folatVar){ REDParticleStartSpinTo *ret = new (std::nothrow) REDParticleStartSpinTo(); if (ret) { if (ret->initWithDuration(fDuration, folatVar)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDParticleStartSpinTo::initWithDuration(float fDuration, cocos2d::Vec2 folatVar){ if (ActionInterval::initWithDuration(fDuration)) { _endFloatVar = folatVar; return true; } else { return false; } } REDParticleStartSpinTo* REDParticleStartSpinTo::clone() const { // no copy constructor auto a = new (std::nothrow) REDParticleStartSpinTo(); a->initWithDuration(_duration, _endFloatVar); a->autorelease(); return a; } REDParticleStartSpinTo* REDParticleStartSpinTo::reverse() const { CCASSERT(false, "reverse() is not supported in REDParticleStartSpinTo"); return nullptr; } void REDParticleStartSpinTo::startWithTarget(cocos2d::Node *pNode) { ActionInterval::startWithTarget(pNode); float a = dynamic_cast(pNode)->getStartSpin(); float aVar = dynamic_cast(pNode)->getStartSpinVar(); _startFloatVar = Vec2(a, aVar); _diffFloatVar = _endFloatVar - _startFloatVar; } void REDParticleStartSpinTo::update(float time){ auto par = dynamic_cast(_target); CCASSERT(par != nullptr, "REDParticleSpeedTo 只支持 ZMLCCParticleSystem"); auto floatVar = _startFloatVar + (_diffFloatVar * time); par->setStartSpin(floatVar.x); par->setStartSpinVar(floatVar.y); } /************************************************************ REDParticleEndSpinTo ************************************************************/ //粒子结束角度 REDParticleEndSpinTo* REDParticleEndSpinTo::create(float fDuration, cocos2d::Vec2 folatVar){ REDParticleEndSpinTo *ret = new (std::nothrow) REDParticleEndSpinTo(); if (ret) { if (ret->initWithDuration(fDuration, folatVar)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDParticleEndSpinTo::initWithDuration(float fDuration, cocos2d::Vec2 folatVar){ if (ActionInterval::initWithDuration(fDuration)) { _endFloatVar = folatVar; return true; } else { return false; } } REDParticleEndSpinTo* REDParticleEndSpinTo::clone() const { // no copy constructor auto a = new (std::nothrow) REDParticleEndSpinTo(); a->initWithDuration(_duration, _endFloatVar); a->autorelease(); return a; } REDParticleEndSpinTo* REDParticleEndSpinTo::reverse() const { CCASSERT(false, "reverse() is not supported in REDParticleEndSpinTo"); return nullptr; } void REDParticleEndSpinTo::startWithTarget(cocos2d::Node *pNode) { ActionInterval::startWithTarget(pNode); float a = dynamic_cast(pNode)->getEndSpin(); float aVar = dynamic_cast(pNode)->getEndSpinVar(); _startFloatVar = Vec2(a, aVar); _diffFloatVar = _endFloatVar - _startFloatVar; } void REDParticleEndSpinTo::update(float time){ auto par = dynamic_cast(_target); CCASSERT(par != nullptr, "REDParticleSpeedTo 只支持 ZMLCCParticleSystem"); auto floatVar = _startFloatVar + (_diffFloatVar * time); par->setEndSpin(floatVar.x); par->setEndSpinVar(floatVar.y); } /************************************************************ REDParticleAngleTo ************************************************************/ //粒子发射角度 REDParticleAngleTo* REDParticleAngleTo::create(float fDuration, cocos2d::Vec2 gravity){ REDParticleAngleTo *ret = new (std::nothrow) REDParticleAngleTo(); if (ret) { if (ret->initWithDuration(fDuration, gravity)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDParticleAngleTo::initWithDuration(float fDuration, cocos2d::Vec2 folatVar){ if (ActionInterval::initWithDuration(fDuration)) { _endFloatVar = folatVar; return true; } else { return false; } } REDParticleAngleTo* REDParticleAngleTo::clone() const { // no copy constructor auto a = new (std::nothrow) REDParticleAngleTo(); a->initWithDuration(_duration, _endFloatVar); a->autorelease(); return a; } REDParticleAngleTo* REDParticleAngleTo::reverse() const { CCASSERT(false, "reverse() is not supported in REDParticleAngleTo"); return nullptr; } void REDParticleAngleTo::startWithTarget(cocos2d::Node *pNode) { ActionInterval::startWithTarget(pNode); float a = dynamic_cast(pNode)->getAngle(); float aVar = dynamic_cast(pNode)->getAngleVar(); _startFloatVar = Vec2(a, aVar); _diffFloatVar = _endFloatVar - _startFloatVar; } void REDParticleAngleTo::update(float time){ auto par = dynamic_cast(_target); CCASSERT(par != nullptr, "REDParticleSpeedTo 只支持 ZMLCCParticleSystem"); auto floatVar = _startFloatVar + (_diffFloatVar * time); par->setAngle(floatVar.x); par->setAngleVar(floatVar.y); } /************************************************************ REDParticleTangentialAccelTo ************************************************************/ //粒子重力模式切向加速度 REDParticleTangentialAccelTo* REDParticleTangentialAccelTo::create(float fDuration, cocos2d::Vec2 gravity){ REDParticleTangentialAccelTo *ret = new (std::nothrow) REDParticleTangentialAccelTo(); if (ret) { if (ret->initWithDuration(fDuration, gravity)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDParticleTangentialAccelTo::initWithDuration(float fDuration, cocos2d::Vec2 folatVar){ if (ActionInterval::initWithDuration(fDuration)) { _endFloatVar = folatVar; return true; } else { return false; } } REDParticleTangentialAccelTo* REDParticleTangentialAccelTo::clone() const { // no copy constructor auto a = new (std::nothrow) REDParticleTangentialAccelTo(); a->initWithDuration(_duration, _endFloatVar); a->autorelease(); return a; } REDParticleTangentialAccelTo* REDParticleTangentialAccelTo::reverse() const { CCASSERT(false, "reverse() is not supported in REDParticleTangentialAccelTo"); return nullptr; } void REDParticleTangentialAccelTo::startWithTarget(cocos2d::Node *pNode) { ActionInterval::startWithTarget(pNode); float a = dynamic_cast(pNode)->getTangentialAccel(); float aVar = dynamic_cast(pNode)->getTangentialAccelVar(); _startFloatVar = Vec2(a, aVar); _diffFloatVar = _endFloatVar - _startFloatVar; } void REDParticleTangentialAccelTo::update(float time){ auto par = dynamic_cast(_target); CCASSERT(par != nullptr, "REDParticleSpeedTo 只支持 ZMLCCParticleSystem"); auto floatVar = _startFloatVar + (_diffFloatVar * time); par->setTangentialAccel(floatVar.x); par->setTangentialAccelVar(floatVar.y); } /************************************************************ REDParticleRadialAccelTo ************************************************************/ //粒子径向加速度 REDParticleRadialAccelTo* REDParticleRadialAccelTo::create(float fDuration, cocos2d::Vec2 gravity){ REDParticleRadialAccelTo *ret = new (std::nothrow) REDParticleRadialAccelTo(); if (ret) { if (ret->initWithDuration(fDuration, gravity)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDParticleRadialAccelTo::initWithDuration(float fDuration, cocos2d::Vec2 folatVar){ if (ActionInterval::initWithDuration(fDuration)) { _endFloatVar = folatVar; return true; } else { return false; } } REDParticleRadialAccelTo* REDParticleRadialAccelTo::clone() const { // no copy constructor auto a = new (std::nothrow) REDParticleRadialAccelTo(); a->initWithDuration(_duration, _endFloatVar); a->autorelease(); return a; } REDParticleRadialAccelTo* REDParticleRadialAccelTo::reverse() const { CCASSERT(false, "reverse() is not supported in REDParticleRadialAccelTo"); return nullptr; } void REDParticleRadialAccelTo::startWithTarget(cocos2d::Node *pNode) { ActionInterval::startWithTarget(pNode); float a = dynamic_cast(pNode)->getRadialAccel(); float aVar = dynamic_cast(pNode)->getRadialAccelVar(); _startFloatVar = Vec2(a, aVar); _diffFloatVar = _endFloatVar - _startFloatVar; } void REDParticleRadialAccelTo::update(float time){ auto par = dynamic_cast(_target); CCASSERT(par != nullptr, "REDParticleSpeedTo 只支持 ZMLCCParticleSystem"); auto floatVar = _startFloatVar + (_diffFloatVar * time); par->setRadialAccel(floatVar.x); par->setRadialAccelVar(floatVar.y); } /************************************************************ REDParticleStartRadiusTo ************************************************************/ //粒子半径模式开始半径 REDParticleStartRadiusTo* REDParticleStartRadiusTo::create(float fDuration, cocos2d::Vec2 gravity){ REDParticleStartRadiusTo *ret = new (std::nothrow) REDParticleStartRadiusTo(); if (ret) { if (ret->initWithDuration(fDuration, gravity)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDParticleStartRadiusTo::initWithDuration(float fDuration, cocos2d::Vec2 folatVar){ if (ActionInterval::initWithDuration(fDuration)) { _endFloatVar = folatVar; return true; } else { return false; } } REDParticleStartRadiusTo* REDParticleStartRadiusTo::clone() const { // no copy constructor auto a = new (std::nothrow) REDParticleStartRadiusTo(); a->initWithDuration(_duration, _endFloatVar); a->autorelease(); return a; } REDParticleStartRadiusTo* REDParticleStartRadiusTo::reverse() const { CCASSERT(false, "reverse() is not supported in REDParticleStartRadiusTo"); return nullptr; } void REDParticleStartRadiusTo::startWithTarget(cocos2d::Node *pNode) { ActionInterval::startWithTarget(pNode); float a = dynamic_cast(pNode)->getStartRadius(); float aVar = dynamic_cast(pNode)->getStartRadiusVar(); _startFloatVar = Vec2(a, aVar); _diffFloatVar = _endFloatVar - _startFloatVar; } void REDParticleStartRadiusTo::update(float time){ auto par = dynamic_cast(_target); CCASSERT(par != nullptr, "REDParticleSpeedTo 只支持 ZMLCCParticleSystem"); auto floatVar = _startFloatVar + (_diffFloatVar * time); par->setStartRadius(floatVar.x); par->setStartRadiusVar(floatVar.y); } /************************************************************ REDParticleEndRadiusTo ************************************************************/ //粒子半径模式结束半径 REDParticleEndRadiusTo* REDParticleEndRadiusTo::create(float fDuration, cocos2d::Vec2 gravity){ REDParticleEndRadiusTo *ret = new (std::nothrow) REDParticleEndRadiusTo(); if (ret) { if (ret->initWithDuration(fDuration, gravity)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDParticleEndRadiusTo::initWithDuration(float fDuration, cocos2d::Vec2 folatVar){ if (ActionInterval::initWithDuration(fDuration)) { _endFloatVar = folatVar; return true; } else { return false; } } REDParticleEndRadiusTo* REDParticleEndRadiusTo::clone() const { // no copy constructor auto a = new (std::nothrow) REDParticleEndRadiusTo(); a->initWithDuration(_duration, _endFloatVar); a->autorelease(); return a; } REDParticleEndRadiusTo* REDParticleEndRadiusTo::reverse() const { CCASSERT(false, "reverse() is not supported in REDParticleEndRadiusTo"); return nullptr; } void REDParticleEndRadiusTo::startWithTarget(cocos2d::Node *pNode) { ActionInterval::startWithTarget(pNode); float a = dynamic_cast(pNode)->getEndRadius(); float aVar = dynamic_cast(pNode)->getEndRadiusVar(); _startFloatVar = Vec2(a, aVar); _diffFloatVar = _endFloatVar - _startFloatVar; } void REDParticleEndRadiusTo::update(float time){ auto par = dynamic_cast(_target); CCASSERT(par != nullptr, "REDParticleSpeedTo 只支持 ZMLCCParticleSystem"); auto floatVar = _startFloatVar + (_diffFloatVar * time); par->setEndRadius(floatVar.x); par->setEndRadiusVar(floatVar.y); } /************************************************************ REDParticleRotatePerSecondTo ************************************************************/ //粒子速度 REDParticleRotatePerSecondTo* REDParticleRotatePerSecondTo::create(float fDuration, cocos2d::Vec2 gravity){ REDParticleRotatePerSecondTo *ret = new (std::nothrow) REDParticleRotatePerSecondTo(); if (ret) { if (ret->initWithDuration(fDuration, gravity)) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } } return ret; } bool REDParticleRotatePerSecondTo::initWithDuration(float fDuration, cocos2d::Vec2 folatVar){ if (ActionInterval::initWithDuration(fDuration)) { _endFloatVar = folatVar; return true; } else { return false; } } REDParticleRotatePerSecondTo* REDParticleRotatePerSecondTo::clone() const { // no copy constructor auto a = new (std::nothrow) REDParticleRotatePerSecondTo(); a->initWithDuration(_duration, _endFloatVar); a->autorelease(); return a; } REDParticleRotatePerSecondTo* REDParticleRotatePerSecondTo::reverse() const { CCASSERT(false, "reverse() is not supported in REDParticleSpeedTo"); return nullptr; } void REDParticleRotatePerSecondTo::startWithTarget(cocos2d::Node *pNode) { ActionInterval::startWithTarget(pNode); float a = dynamic_cast(pNode)->getRotatePerSecond(); float aVar = dynamic_cast(pNode)->getRotatePerSecondVar(); _startFloatVar = Vec2(a, aVar); _diffFloatVar = _endFloatVar - _startFloatVar; } void REDParticleRotatePerSecondTo::update(float time){ auto par = dynamic_cast(_target); CCASSERT(par != nullptr, "REDParticleSpeedTo 只支持 ZMLCCParticleSystem"); auto floatVar = _startFloatVar + (_diffFloatVar * time); par->setRotatePerSecond(floatVar.x); par->setRotatePerSecondVar(floatVar.y); } /************************************************************ REDEaseInstant ************************************************************/ REDEaseInstant* REDEaseInstant::create(ActionInterval *pAction) { REDEaseInstant *pRet = new (std::nothrow) REDEaseInstant(); if (pRet && pRet->initWithAction(pAction)) { pRet->autorelease(); } else { CC_SAFE_RELEASE_NULL(pRet); } return pRet; } REDEaseInstant* REDEaseInstant::clone() const { // no copy constructor auto a = new (std::nothrow) REDEaseInstant(); a->initWithAction(_inner); a->autorelease(); return a; } REDEaseInstant* REDEaseInstant::reverse() const { return REDEaseInstant::create(_inner->reverse()); } void REDEaseInstant::update(float dt) { if (dt < 0) { _inner->update(0); } else { _inner->update(1); } } /************************************************************ EaseBezierByTimeAction ************************************************************/ float crt(float v) { if (v < 0) { return -pow(-v, 1 / 3.0); } else { return pow(v, 1 / 3.0); } } float max(float a, float b){ return a > b ? a : b; } float cardano(float xx1, float xx2, float x) { float pa = x - 0; float pb = x - xx1; float pc = x - xx2; float pd = x - 1; // to [t^3 + at^2 + bt + c] form: float pa3 = pa * 3; float pb3 = pb * 3; float pc3 = pc * 3; float d = -pa + pb3 - pc3 + pd; float rd = 1 / d; float r3 = 1 / 3.0; float a = (pa3 - 6 * pb + pc3) * rd; float a3 = a * r3; float b = (-pa3 + pb3) * rd; float c = pa * rd; // then, determine p and q: float p = (3 * b - a * a) * r3; float p3 = p * r3; float q = (2 * a * a * a - 9 * a * b + 27 * c) / 27.0; float q2 = q / 2.0; // and determine the discriminant: float discriminant = q2 * q2 + p3 * p3 * p3; // and some reserved variables float u1; float v1; float x1; float x2; float x3; // If the discriminant is negative, use polar coordinates // to get around square roots of negative numbers if (discriminant < 0) { float mp3 = -p * r3; float mp33 = mp3 * mp3 * mp3; float r = sqrt(mp33); // compute cosphi corrected for IEEE float rounding: float t = -q / (2.0 * r); float cosphi = t < -1 ? -1 : t > 1 ? 1 : t; float phi = acos(cosphi); float crtr = crt(r); float t1 = 2 * crtr; float tau = 2 * M_PI; x1 = t1 * cos(phi * r3) - a3; x2 = t1 * cos((phi + tau) * r3) - a3; x3 = t1 * cos((phi + 2 * tau) * r3) - a3; // choose best percentage x1 = (float)((int)(x1*10000)/10000.0); x2 = (float)((int)(x2*10000)/10000.0); x3 = (float)((int)(x3*10000)/10000.0); if (0 <= x1 && x1 <= 1) { if (0 <= x2 && x2 <= 1) { if (0 <= x3 && x3 <= 1) { return max(max(x1, x2), x3); } else { return max(x1, x2); } } else if (0 <= x3 && x3 <= 1) { return max(x1, x3); } else { return x1; } } else { if (0 <= x2 && x2 <= 1) { if (0 <= x3 && x3 <= 1) { return max(x2, x3); } else { return x2; } } else { return x3; } } } else if (discriminant == 0) { u1 = q2 < 0 ? crt(-q2) : -crt(q2); x1 = 2 * u1 - a3; x2 = -u1 - a3; // choose best percentage if (0 <= x1 && x1 <= 1) { if (0 <= x2 && x2 <= 1) { return max(x1, x2); } else { return x1; } } else { return x2; } } // one real root, and two imaginary roots else { float sd = sqrt(discriminant); u1 = crt(-q2 + sd); v1 = crt(q2 + sd); x1 = u1 - v1 - a3; return x1; } } /// 贝塞尔曲线的计算,200710 by zml /// @param x1 起始控制点的X /// @param y1 起始控制点的Y /// @param x2 结束控制点的X /// @param y2 结束控制点的Y /// @param x 输入的时间 /// @return 更新后的时间 float bezierByTime( float x1, float y1, float x2, float y2, float x ){ float percent = cardano(x1, x2, x); // t return ((1 - percent) * (y1 + (y2 - y1) * percent) * 3 + percent * percent) * percent; } EaseBezierByTimeAction* EaseBezierByTimeAction::create(cocos2d::ActionInterval* action) { EaseBezierByTimeAction *ret = new (std::nothrow) EaseBezierByTimeAction(); if (ret && ret->initWithAction(action)) { ret->autorelease(); return ret; } delete ret; return nullptr; } void EaseBezierByTimeAction::setBezierParamer( float p0, float p1, float p2, float p3) { _p0 = p0; _p1 = p1; _p2 = p2; _p3 = p3; } EaseBezierByTimeAction* EaseBezierByTimeAction::clone() const { // no copy constructor if (_inner) { auto ret = EaseBezierByTimeAction::create(_inner->clone()); if (ret) { ret->setBezierParamer(_p0,_p1,_p2,_p3); } return ret; } return nullptr; } void EaseBezierByTimeAction::update(float time) { _inner->update(bezierByTime(_p0,_p1,_p2,_p3,time)); } EaseBezierByTimeAction* EaseBezierByTimeAction::reverse() const { EaseBezierByTimeAction* reverseAction = EaseBezierByTimeAction::create(_inner->reverse()); reverseAction->setBezierParamer(_p3,_p2,_p1,_p0); return reverseAction; } #pragma mark - RedBakeAnimationInstantAction RedBakeAnimationInstantAction* RedBakeAnimationInstantAction::create(const RedBakeNodeFrame& frame) { auto ret = new (std::nothrow) RedBakeAnimationInstantAction(); if (ret && ret->init(frame)) { ret->autorelease(); return ret; } delete ret; ret = nullptr; return nullptr; } bool RedBakeAnimationInstantAction::init(const RedBakeNodeFrame& frame) { _bakeFrame = frame; return true; } void RedBakeAnimationInstantAction::update(float time) { auto bakeNode = dynamic_cast(_target); if (bakeNode == nullptr) { return; } if (_bakeFrame.animationName.empty()) { return; } bakeNode->playAnimation(_bakeFrame.animationName, _bakeFrame.loop); } RedBakeAnimationInstantAction* RedBakeAnimationInstantAction::clone() const { auto ret = new (std::nothrow) RedBakeAnimationInstantAction(); if (ret && ret->init(_bakeFrame)) { ret->autorelease(); return ret; } delete ret; ret = nullptr; return nullptr; } RedBakeAnimationInstantAction* RedBakeAnimationInstantAction::reverse() const { return this->clone(); } }