// // ToySpriteAnimator.cpp // SteveMaggieCpp // // Created by Katarzyna Kalinowska-Górska on 01.06.2017. // // #include #include "ToySpriteAnimator.h" #include "ToyJSONParseUtils.h" #include "ToyMathUtils.h" #include "ToyClipToAction.h" #include "ToyResourceUtilities.h" // TODO tu by lepiej bylo podawac obiekt z nazwanymi parametrami zamiast parametry po kolei w funkcjach - REFACTOR!!!! void ToySpriteAnimator::runAnimationForName(std::string animationName, std::vector sprites, const rapidjson::Value* params) { auto scale = 1/cocos2d::Director::getInstance()->getContentScaleFactor(); if(animationName == "fadeInAnimation"){ ToySpriteAnimator::fadeInAnimation(sprites); } else if(animationName == "fadeOutAnimation"){ ToySpriteAnimator::fadeOutAnimation(sprites); } else if(animationName == "clipToAnimation"){ const auto& paramsArray = params->GetArray(); auto durations = ToyJSONParseUtils::parseFloatArray(paramsArray[0]); auto rects = ToyJSONParseUtils::parseRectArray(paramsArray[1]); ToyMathUtils::multiplyRectPositionsArray(rects, scale); ToySpriteAnimator::clipToAnimation(sprites, durations, rects); } //TODO obsluzyc new positions jako obiekt punkt albo array else if(animationName == "moveToAnimation"){ const auto& paramsArray = params->GetArray(); auto duration = paramsArray[0].GetFloat(); auto newPositions = ToyJSONParseUtils::parsePointArray(paramsArray[1]); ToyMathUtils::multiplyPointArray(newPositions, scale); if(paramsArray.Size() > 2){ std::string easeOption = paramsArray[2].GetString(); ToySpriteAnimator::moveToAnimation(sprites, duration, newPositions, easeOption); } else { ToySpriteAnimator::moveToAnimation(sprites, duration, newPositions); } } else if(animationName == "moveByAnimation"){ const auto& paramsArray = params->GetArray(); auto duration = paramsArray[0].GetFloat(); auto deltaPosition = ToyJSONParseUtils::getPoint(paramsArray[1]); if(paramsArray.Size() > 2){ std::string easeOption = paramsArray[2].GetString(); ToySpriteAnimator::moveByAnimation(sprites, duration, deltaPosition, easeOption); } else { ToySpriteAnimator::moveByAnimation(sprites, duration, deltaPosition); } } else if(animationName == "jumpAnimation"){ const auto& paramsArray = params->GetArray(); auto durations = ToyJSONParseUtils::parseFloatArray(paramsArray[0]); auto deltas = ToyJSONParseUtils::parsePointArray(paramsArray[1]); auto heights = ToyJSONParseUtils::parseFloatArray(paramsArray[2]); if(paramsArray.Size() > 3){ auto jumps = ToyJSONParseUtils::parseIntArray(paramsArray[3]); ToySpriteAnimator::jumpAnimation(sprites, durations, deltas, heights, jumps); } else { ToySpriteAnimator::jumpAnimation(sprites, durations, deltas, heights); } // it should be like below (bad design of function arguments in scenario files) // auto durations = ToyJSONParseUtils::parseMemberFloatArray(params, "durations"); // auto deltas = ToyJSONParseUtils::parseMemberPointArray(params, "deltas"); // auto heights = ToyJSONParseUtils::parseMemberFloatArray(params, "heights"); } else if(animationName == "bezierByAnimation"){ const auto& paramsArray = params->GetArray(); std::vector> bezierPathsDeltaXs; std::vector> bezierPathsDeltaYs; for(const auto& value : paramsArray[0].GetArray()){ bezierPathsDeltaXs.push_back(ToyJSONParseUtils::parseFloatArray(value)); } for(const auto& value : paramsArray[1].GetArray()){ bezierPathsDeltaYs.push_back(ToyJSONParseUtils::parseFloatArray(value)); } auto durations = ToyJSONParseUtils::parseFloatArray(paramsArray[2]); ToySpriteAnimator::bezierByAnimation(sprites, bezierPathsDeltaXs, bezierPathsDeltaYs, durations); } else if(animationName == "floatAnimation"){ const auto& paramsArray = params->GetArray(); auto delays = ToyJSONParseUtils::parseFloatArray(paramsArray[0]); std::vector> dxRanges; std::vector> dyRanges; for(const auto& value : paramsArray[1].GetArray()){ dxRanges.push_back(ToyJSONParseUtils::parseFloatArray(value)); } for(const auto& value : paramsArray[2].GetArray()){ dyRanges.push_back(ToyJSONParseUtils::parseFloatArray(value)); } float bezierTime = 2.4; if(paramsArray.Size() > 3){ bezierTime = paramsArray[3].GetFloat(); } ToySpriteAnimator::floatAnimation(sprites, delays, dxRanges, dyRanges, bezierTime); } else if(animationName == "windTugAnimation"){ if(params){ const auto& paramsArray = params->GetArray(); auto skewAnglesX = ToyJSONParseUtils::parseFloatArray(paramsArray[0]); auto skewAnglesY = ToyJSONParseUtils::parseFloatArray(paramsArray[1]); ToySpriteAnimator::windTugAnimation(sprites, skewAnglesX, skewAnglesY); } else { ToySpriteAnimator::windTugAnimation(sprites, std::vector(0), std::vector(0)); } } else if(animationName == "windTugAnimationWithRotation"){ if(params){ const auto& paramsArray = params->GetArray(); auto skewAnglesX = ToyJSONParseUtils::parseFloatArray(paramsArray[0]); auto skewAnglesY = ToyJSONParseUtils::parseFloatArray(paramsArray[1]); if(paramsArray.Size() > 2){ auto delays = ToyJSONParseUtils::parseFloatArray(paramsArray[2]); ToySpriteAnimator::windTugAnimationWithRotation(sprites, skewAnglesX, skewAnglesY, delays); } else { ToySpriteAnimator::windTugAnimationWithRotation(sprites, skewAnglesX, skewAnglesY); } } else { ToySpriteAnimator::windTugAnimationWithRotation(sprites, std::vector(0), std::vector(0)); } } else if(animationName == "bounceAnimation"){ if(params){ const auto& paramsArray = params->GetArray(); auto delays = ToyJSONParseUtils::parseFloatArray(paramsArray[0]); auto rotationDurations = ToyJSONParseUtils::parseFloatArray(paramsArray[1]); auto rotationAngles = ToyJSONParseUtils::parseFloatArray(paramsArray[2]); std::vector wholeDurations; if(paramsArray.Size() > 3){ wholeDurations = ToyJSONParseUtils::parseFloatArray(paramsArray[3]); } if(paramsArray.Size() > 4){ auto roundUp = paramsArray[4].GetArray()[0].GetBool(); ToySpriteAnimator::bounceAnimation(sprites, delays, rotationDurations, rotationAngles, wholeDurations,roundUp); } else { ToySpriteAnimator::bounceAnimation(sprites, delays, rotationDurations, rotationAngles, wholeDurations); } } else { ToySpriteAnimator::bounceAnimation(sprites); } } else if(animationName == "swipeAnimation"){ const auto& paramsArray = params->GetArray(); if(paramsArray.Size() > 0){ auto delayConst = paramsArray[0].GetFloat(); if(paramsArray.Size() > 1){ auto animationAnchorPoint = ToyJSONParseUtils::getPoint(paramsArray[1]); if(paramsArray.Size() > 2){ auto rotationDir = paramsArray[2].GetInt(); if(paramsArray.Size() > 3){ cocos2d::Vec2 moveDir = ToyJSONParseUtils::getPoint(paramsArray[3]); ToySpriteAnimator::swipeAnimation(sprites, delayConst, animationAnchorPoint, rotationDir, moveDir); } else { ToySpriteAnimator::swipeAnimation(sprites, delayConst, animationAnchorPoint, rotationDir); } } else { ToySpriteAnimator::swipeAnimation(sprites, delayConst, animationAnchorPoint); } } else { ToySpriteAnimator::swipeAnimation(sprites, delayConst); } } else { ToySpriteAnimator::swipeAnimation(sprites); } } else if(animationName == "rotateByAnimation"){ const auto& paramsArray = params->GetArray(); auto duration = paramsArray[0].GetFloat(); auto rotationAngle = paramsArray[1].GetFloat(); if(paramsArray.Size() > 2){ std::string easeOption = paramsArray[2].GetString(); ToySpriteAnimator::rotateByAnimation(sprites, duration, rotationAngle, easeOption); } else { ToySpriteAnimator::rotateByAnimation(sprites, duration, rotationAngle); } } else if(animationName == "frameAnimation"){ const auto& paramsArray = params->GetArray(); auto imageFileArray = ToyJSONParseUtils::parseStringArray(paramsArray[0]); std::string folder = ""; if(paramsArray.Size() > 1){ folder = paramsArray[1].GetString(); } folder = ToyResourceUtilities::getInstance().getFullPathForDownloadedFile(folder); ToySpriteAnimator::frameAnimation(sprites[0], imageFileArray, folder); } else if(animationName == "simpleRotateAnimation"){ const auto& paramsArray = params->GetArray(); auto delays = ToyJSONParseUtils::parseFloatArray(paramsArray[0]); auto animationAnchorPoints = ToyJSONParseUtils::parsePointArray(paramsArray[1]); auto rotationAngles = ToyJSONParseUtils::parseFloatArray(paramsArray[2]); auto rotationDurations = ToyJSONParseUtils::parseFloatArray(paramsArray[3]); auto repeatTimes = ToyJSONParseUtils::parseIntArray(paramsArray[4]); ToySpriteAnimator::simpleRotateAnimation(sprites, delays, animationAnchorPoints, rotationAngles, rotationDurations, repeatTimes); } else if(animationName == "fullRotateAnimation"){ const auto& paramsArray = params->GetArray(); auto crazy = paramsArray[0].GetBool(); auto durations = ToyJSONParseUtils::parseFloatArray(paramsArray[1]); ToySpriteAnimator::fullRotateAnimation(sprites, crazy, durations); } else if(animationName == "crazyRotateAnimation"){ ToySpriteAnimator::crazyRotateAnimation(sprites); } else if(animationName == "rotateForeverAnimation"){ const auto& paramsArray = params->GetArray(); auto lapDurations = ToyJSONParseUtils::parseFloatArray(paramsArray[0]); ToySpriteAnimator::rotateForeverAnimation(sprites, lapDurations); } else if(animationName == "scaleUpDownAnimation"){ if(params){ const auto& paramsArray = params->GetArray(); if(paramsArray.Size() > 0){ auto upperScale = paramsArray[0].GetFloat(); if(paramsArray.Size() > 1){ auto scaleUpDownDuration = paramsArray[1].GetFloat(); if(paramsArray.Size() > 2){ auto times = paramsArray[2].GetInt(); ToySpriteAnimator::scaleUpDownAnimation(sprites, upperScale, scaleUpDownDuration, times); } else { ToySpriteAnimator::scaleUpDownAnimation(sprites, upperScale, scaleUpDownDuration); } } else { ToySpriteAnimator::scaleUpDownAnimation(sprites, upperScale); } } else { ToySpriteAnimator::scaleUpDownAnimation(sprites); } } else { ToySpriteAnimator::scaleUpDownAnimation(sprites); } } else if(animationName == "sinusoidalMoveAnimation"){ const auto& paramsArray = params->GetArray(); auto duration = paramsArray[0].GetFloat(); auto newPositions = ToyJSONParseUtils::parsePointArray(paramsArray[1]); ToyMathUtils::multiplyPointArray(newPositions, cocos2d::Director::getInstance()->getContentScaleFactor()); auto amplitudes = ToyJSONParseUtils::parseFloatArray(paramsArray[2]); ToySpriteAnimator::sinusoidalMoveAnimation(sprites, duration, newPositions, amplitudes); } else if(animationName == "trainRunForeverAnimation"){ const auto& paramsArray = params->GetArray(); auto duration = paramsArray[0].GetFloat(); ToySpriteAnimator::trainRunForeverAnimation(sprites, duration); } } void ToySpriteAnimator::frameAnimation(cocos2d::Node* sprite, std::vector imageFileArray, std::string folder) { auto animationTag = RF_ANIMATION_TAG_BASE + RF_ANIMATION_TAG_FRAME_ANIMATION; if(!sprite->getActionByTag(animationTag)){ auto animation = cocos2d::Animation::create(); for(int i = 0; i < imageFileArray.size(); ++i){ animation->addSpriteFrameWithFile(folder + imageFileArray[i]); } animation->setDelayPerUnit(0.08); auto action = cocos2d::RepeatForever::create(cocos2d::Animate::create(animation)); action->setTag(animationTag); sprite->runAction(action); } } void ToySpriteAnimator::clipToAnimation(std::vector sprites, std::vector durations, std::vector textureRects) { for(int i = 0; i < sprites.size(); ++i){ auto action = ClipTo::create(durations[i], textureRects[i]); sprites[i]->runAction(action); } } void ToySpriteAnimator::fadeInAnimation(std::vector sprites) { for(int i = 0; i < sprites.size(); ++i){ auto action = cocos2d::FadeIn::create(0.2); sprites[i]->runAction(action); } } void ToySpriteAnimator::fadeOutAnimation(std::vector sprites) { for(int i = 0; i < sprites.size(); ++i){ auto action = cocos2d::FadeOut::create(0.2); sprites[i]->runAction(action); } } void ToySpriteAnimator::moveToAnimation(std::vector sprites, float duration, std::vector newPositions, std::string easeOption) { for(int i = 0; i < sprites.size(); ++i){ auto action = ToySpriteAnimator::actionWithEaseOption(cocos2d::MoveTo::create(duration, newPositions[i]), easeOption); sprites[i]->runAction(action); } } void ToySpriteAnimator::moveByAnimation(std::vector sprites, float duration, cocos2d::Vec2 deltaPosition, std::string easeOption) { for(int i = 0; i < sprites.size(); ++i){ auto action = ToySpriteAnimator::actionWithEaseOption(cocos2d::MoveBy::create(duration, deltaPosition), easeOption); sprites[i]->runAction(action); } } void ToySpriteAnimator::rotateByAnimation(std::vector sprites, float duration, float rotationAngle, std::string easeOption) { for(int i = 0; i < sprites.size(); ++i){ auto action = ToySpriteAnimator::actionWithEaseOption(cocos2d::RotateBy::create(duration, rotationAngle), easeOption); sprites[i]->runAction(action); } } void ToySpriteAnimator::bezierByAnimation(std::vector sprites, std::vector> bezierPathsDeltaXs, std::vector> bezierPathsDeltaYs, std::vector durations) { for(int i = 0; i < sprites.size(); ++i){ auto duration = durations.size() > i ? durations[i] : 2; cocos2d::ccBezierConfig bezierConfig; bezierConfig.endPosition = cocos2d::Point(bezierPathsDeltaXs[i][2], bezierPathsDeltaYs[i][2]); bezierConfig.controlPoint_1 = cocos2d::Point(bezierPathsDeltaXs[i][0], bezierPathsDeltaYs[i][0]); bezierConfig.controlPoint_2 = cocos2d::Point(bezierPathsDeltaXs[i][1], bezierPathsDeltaYs[i][1]); sprites[i]->runAction(cocos2d::EaseInOut::create(cocos2d::BezierBy::create(duration, bezierConfig), 2)); } } void ToySpriteAnimator::simpleRotateAnimation(std::vector sprites, std::vector delays, std::vector animationAnchorPoints, std::vector rotationAngles, std::vector rotationDurations, std::vector repeatTimes) { for(int i = 0; i < sprites.size(); ++i){ auto oldPos = sprites[i]->getPosition(); auto oldAnchorPoint = sprites[i]->getAnchorPoint(); sprites[i]->setAnchorPoint(animationAnchorPoints[i]);//(new cc.p(0.75, 1)); sprites[i]->setPosition(cocos2d::Point(oldPos.x + sprites[i]->getBoundingBox().size.width*(animationAnchorPoints[i].x - oldAnchorPoint.x), oldPos.y + sprites[i]->getBoundingBox().size.height*(animationAnchorPoints[i].y - oldAnchorPoint.y))); auto callback = [](cocos2d::Node* pSprite, cocos2d::Point pOldAnchorPoint, cocos2d::Point pOldPos){ pSprite->setAnchorPoint(pOldAnchorPoint); pSprite->setPosition(pOldPos); }; auto boundCallback = std::bind(callback, sprites[i], oldAnchorPoint, oldPos); sprites[i]->runAction(cocos2d::Sequence::create(cocos2d::DelayTime::create(delays[i]), cocos2d::Repeat::create(cocos2d::Sequence::create(cocos2d::EaseInOut::create(cocos2d::RotateBy::create(rotationDurations[i], rotationAngles[i]),1.2), cocos2d::EaseInOut::create(cocos2d::RotateBy::create(rotationDurations[i], -2*rotationAngles[i]),1.2), cocos2d::EaseInOut::create(cocos2d::RotateBy::create(rotationDurations[i], rotationAngles[i]),1.2), nullptr), repeatTimes[i]), cocos2d::CallFunc::create(boundCallback), nullptr)); } } void ToySpriteAnimator::trainRunForeverAnimation(std::vector sprites, float lapDuration){ for(int i = 0; i < sprites.size(); ++i){ if(sprites[i]->getActionByTag(RF_ANIMATION_TAG_TRAIN_RUN_FOREVER_ANIMATION) == nullptr){ auto action = cocos2d::RepeatForever::create(cocos2d::Sequence::create(cocos2d::MoveTo::create(lapDuration, cocos2d::Vec2(-sprites[i]->getBoundingBox().size.width, sprites[i]->getPositionY())), cocos2d::CallFunc::create(std::bind([&](cocos2d::Node* pSprite){ pSprite->setPositionX(cocos2d::Director::getInstance()->getWinSize().width + pSprite->getBoundingBox().size.width/2); }, sprites[i])), nullptr)); action->setTag(RF_ANIMATION_TAG_TRAIN_RUN_FOREVER_ANIMATION); sprites[i]->runAction(action); } } } void ToySpriteAnimator::crazyRotateAnimation(std::vector sprites) { std::vector defaultDurations(sprites.size(), 0.2); ToySpriteAnimator::fullRotateAnimation(sprites, true, defaultDurations); } void ToySpriteAnimator::fullRotateAnimation(std::vector sprites, bool crazy, std::vector durations) { for(int i = 0; i < sprites.size(); ++i){ cocos2d::Action* action = NULL; if(crazy){ action = cocos2d::Sequence::create(cocos2d::Spawn::create(cocos2d::ScaleTo::create(0.2,1.1), cocos2d::RotateBy::create(0.4,360), nullptr),cocos2d::ScaleTo::create(0.2,1), nullptr); } else { action = cocos2d::RotateBy::create(durations[i],360); } sprites[i]->runAction(action); } } void ToySpriteAnimator::rotateForeverAnimation(std::vector sprites, std::vector oneLapDurations) { for(int i = 0; i < sprites.size(); ++i){ auto action = cocos2d::RepeatForever::create(cocos2d::RotateBy::create(oneLapDurations[i], 360)); action->setTag(RF_ANIMATION_TAG_BASE + RF_ANIMATION_TAG_ROTATE_FOREVER_ANIMATION); sprites[i]->runAction(action); } } void ToySpriteAnimator::scaleUpDownAnimation(std::vector sprites, float upperScale, float scaleUpDownDuration, int times) { for(int i = 0; i < sprites.size(); ++i){ cocos2d::Action* action = NULL; if(times == 0){ action = cocos2d::RepeatForever::create(cocos2d::Sequence::create(cocos2d::ScaleTo::create(scaleUpDownDuration/2, upperScale), cocos2d::ScaleTo::create(scaleUpDownDuration/2,1), nullptr)); action->setTag(RF_ANIMATION_TAG_BASE + RF_ANIMATION_TAG_SCALE_UP_DOWN_ANIMATION); } else { action = cocos2d::Repeat::create(cocos2d::Sequence::create(cocos2d::ScaleTo::create(0.2, upperScale), cocos2d::ScaleTo::create(0.2,1), nullptr), times); } sprites[i]->runAction(action); } } //TODO change the scenario file where we have only one jumps number instead of an array void ToySpriteAnimator::jumpAnimation(std::vector sprites, std::vector durations, std::vector deltas, std::vector heights) { std::vector zeros(sprites.size(),0); ToySpriteAnimator::jumpAnimation(sprites, durations, deltas, heights, zeros); } void ToySpriteAnimator::jumpAnimation(std::vector sprites, std::vector durations, std::vector deltas, std::vector heights, std::vector jumps) { for(int i = 0; i < sprites.size(); ++i){ if(jumps[i] == 0){ auto action = cocos2d::RepeatForever::create(cocos2d::JumpBy::create(durations[i], cocos2d::Point(deltas[i].x, deltas[i].y), heights[i], 3)); action->setTag(RF_ANIMATION_TAG_BASE + RF_ANIMATION_TAG_JUMP_ANIMATION); sprites[i]->runAction(action); } else { sprites[i]->runAction(cocos2d::JumpBy::create(durations[i], deltas[i], heights[i], jumps[i])); } } } void ToySpriteAnimator::floatAnimation(std::vector sprites, std::vector delays, std::vector> dxRanges, std::vector> dyRanges, float bezierTime) { for(int i = 0; i < sprites.size(); ++i){ int delay = 0; if(delays.size() > i){ delay = delays[i]; } ToySpriteAnimator::singleSpriteFloatAnimation(sprites[i], delay, dxRanges[i], dyRanges[i], bezierTime); } } void ToySpriteAnimator::singleSpriteFloatAnimation(cocos2d::Node* sprite, float delay, std::vector dxRange, std::vector dyRange, float bezierTime) { float randomDXs[] = {0,0}; float randomDYs[] = {0,0}; for(int j = 0; j < 2; ++j){ randomDXs[j] = ToyMathUtils::getRandom(dxRange[0], dxRange[1]); randomDYs[j] = ToyMathUtils::getRandom(dyRange[0], dyRange[1]); } cocos2d::ccBezierConfig bezierConfig; bezierConfig.endPosition = cocos2d::Point(0,0); bezierConfig.controlPoint_1 = cocos2d::Point(randomDXs[0], randomDYs[0]); bezierConfig.controlPoint_2 = cocos2d::Point(randomDXs[1], randomDYs[1]); auto rotationAngle = ToyMathUtils::getRandom(4, 10); rotationAngle = ToyMathUtils::getRandomInt(0,1) > 0 ? -rotationAngle : rotationAngle; //todo all params like thias to f args + defaults auto totalBezierTime = bezierTime + ToyMathUtils::getRandom(-0.4, 0.4);; auto totalRotationTime = bezierTime + ToyMathUtils::getRandom(-0.4, 0.4); for(int j = 0; j < 3; ++j){ auto reverseDir = ToyMathUtils::getRandomInt(0,1); if(reverseDir > 0){ if(j == 0){ bezierConfig.controlPoint_1 = cocos2d::Point(-bezierConfig.controlPoint_1.x, -bezierConfig.controlPoint_1.y); } else if(j == 1){ bezierConfig.controlPoint_2 = cocos2d::Point(-bezierConfig.controlPoint_2.x, -bezierConfig.controlPoint_2.y); } else if(j == 2){ bezierConfig.endPosition = cocos2d::Point(-bezierConfig.endPosition.x, -bezierConfig.endPosition.y); } } } auto bezierAnimation = cocos2d::EaseInOut::create(cocos2d::BezierBy::create(totalBezierTime - delay, bezierConfig), 2); // cocos2d::log("binding dx[0]: %f dx[1]: %f", dxRange[0], dxRange[1]); // cocos2d::log("binding dy[0]: %f dy[1]: %f", dyRange[0], dyRange[1]); auto action = cocos2d::Sequence::create(cocos2d::Spawn::create(cocos2d::Sequence::create(cocos2d::DelayTime::create(delay),bezierAnimation, nullptr), cocos2d::Sequence::create(cocos2d::RotateBy::create(totalRotationTime/4, rotationAngle), cocos2d::RotateBy::create(totalRotationTime/2, -2*rotationAngle), cocos2d::RotateBy::create(totalRotationTime/4, rotationAngle), nullptr), nullptr), cocos2d::CallFunc::create(std::bind(ToySpriteAnimator::singleSpriteFloatAnimation, sprite, delay, dxRange, dyRange, bezierTime)), nullptr); action->setTag(RF_ANIMATION_TAG_BASE + RF_ANIMATION_TAG_FLOAT_ANIMATION); auto actionParameters = dynamic_cast(sprite->getUserObject()); if(actionParameters == nullptr){ actionParameters = new AnimationUserData(); // actionParameters->autorelease(); //TODO memory leaks? does is work? sprite->setUserObject(actionParameters); } if(actionParameters->floatAnimationData == nullptr){ actionParameters->floatAnimationData = new FloatAnimationData(); // actionParameters->floatAnimationData->autorelease(); } actionParameters->floatAnimationData->delay = delay; actionParameters->floatAnimationData->dxRange = dxRange; actionParameters->floatAnimationData->dyRange = dyRange; actionParameters->floatAnimationData->bezierTime = bezierTime; sprite->runAction(action); } void ToySpriteAnimator::windTugAnimation(std::vector sprites, std::vector skewAnglesX, std::vector skewAnglesY) //note: the anchor point has to be top middle more or less { for(int i = 0; i < sprites.size(); ++i){ float skewAngleX = 12, skewAngleY = 4; if(skewAnglesX.size() > i){ skewAngleX = skewAnglesX[i]; } if(skewAnglesY.size() > i){ skewAngleY = skewAnglesY[i]; } auto action = cocos2d::RepeatForever::create(cocos2d::Sequence::create(cocos2d::EaseInOut::create(cocos2d::SkewBy::create(1, skewAngleX, skewAngleY), 1.2), cocos2d::EaseInOut::create(cocos2d::SkewBy::create(1, -skewAngleX, -skewAngleY), 1.2), nullptr)); action->setTag(RF_ANIMATION_TAG_BASE + RF_ANIMATION_TAG_WIND_TUG_ANIMATION); sprites[i]->runAction(action); } } void ToySpriteAnimator::windTugAnimationWithRotation(std::vector sprites, std::vector skewAnglesX, std::vector skewAnglesY, std::vector delays) { for(int i = 0; i < sprites.size(); ++i){ float skewAngleX = 12, skewAngleY = 4; if(skewAnglesX.size() > i){ skewAngleX = skewAnglesX[i]; } if(skewAnglesY.size() > i){ skewAngleY = skewAnglesY[i]; } float delay = 0; if(delays.size() > i){ delay = delays[i]; } float rotateAngle = (skewAngleX+skewAngleY)*2/3.0; auto action = cocos2d::RepeatForever::create(cocos2d::Sequence::create(cocos2d::DelayTime::create(delay), cocos2d::Spawn::create(cocos2d::EaseInOut::create(cocos2d::SkewBy::create(1, skewAngleX, skewAngleY), 1.2), cocos2d::EaseInOut::create(cocos2d::RotateBy::create(1, rotateAngle), 1.2), nullptr), cocos2d::Spawn::create(cocos2d::EaseInOut::create(cocos2d::SkewBy::create(1, -skewAngleX, -skewAngleY), 1.2), cocos2d::EaseInOut::create(cocos2d::RotateBy::create(1, -rotateAngle), 1.2), nullptr), nullptr)); action->setTag(RF_ANIMATION_TAG_BASE + RF_ANIMATION_TAG_WIND_TUG_ANIMATION); sprites[i]->runAction(action); } } void ToySpriteAnimator::bounceAnimation(std::vector sprites, std::vector delays, std::vector rotationDurations, std::vector rotationAngles,std::vector wholeDurations, bool roundUp) { for(int i = 0; i < sprites.size(); ++i){ float delay = 0; if(delays.size() > i){ delay = delays[i]; } float rotationAngle = 5; if(rotationAngles.size() > i){ rotationAngle = rotationAngles[i]; } float rotationDuration = 0.05; if(rotationDurations.size() > i){ rotationDuration = rotationDurations[i]; } float times = 0; if(wholeDurations.size() > i && wholeDurations[i] != 0){ float sequenceDuration = 4*rotationDuration; times = (wholeDurations[i] - delay) / sequenceDuration; if(roundUp == 1){ times = ceil(times); } else { times = floor(times); } } auto actionParameters = dynamic_cast(sprites[i]->getUserObject()); if(!actionParameters){ actionParameters = new AnimationUserData(); sprites[i]->setUserObject(actionParameters); } if(!actionParameters->bounceAnimationData){ actionParameters->bounceAnimationData = new BounceAnimationData(); } actionParameters->bounceAnimationData->delay = delay; actionParameters->bounceAnimationData->rotationAngle = rotationAngle; actionParameters->bounceAnimationData->rotationDuration = rotationDuration; actionParameters->bounceAnimationData->wholeDuration = wholeDurations.size() > i ? wholeDurations[i] : 0; actionParameters->bounceAnimationData->roundUp = roundUp; auto action = cocos2d::Sequence::create(cocos2d::DelayTime::create(delay), cocos2d::RotateBy::create(rotationDuration,rotationAngle), cocos2d::RotateBy::create(2*rotationDuration,-2*rotationAngle), cocos2d::RotateBy::create(rotationDuration,rotationAngle), nullptr); if(times == 0){ auto rfaction = cocos2d::RepeatForever::create(action); rfaction->setTag(RF_ANIMATION_TAG_BASE + RF_ANIMATION_TAG_BOUNCE_ANIMATION); if(sprites[i]->getActionByTag(rfaction->getTag()) == nullptr){ sprites[i]->runAction(rfaction); } } else { sprites[i]->runAction(cocos2d::Sequence::create(cocos2d::DelayTime::create(delay), cocos2d::Repeat::create(action, times), nullptr)); } } } void ToySpriteAnimator::swipeAnimation(std::vector sprites, float delayConst, cocos2d::Point animationAnchorPoint, int rotationDir, cocos2d::Vec2 moveDir) { for(int i = 0; i < sprites.size(); ++i){ auto oldPos = sprites[i]->getPosition(); auto oldAnchorPoint = sprites[i]->getAnchorPoint(); sprites[i]->setAnchorPoint(cocos2d::Point(animationAnchorPoint.x, animationAnchorPoint.y));//(new cc.p(0.75, 1)); sprites[i]->setPosition(cocos2d::Point(oldPos.x + sprites[i]->getBoundingBox().size.width*(animationAnchorPoint.x - oldAnchorPoint.x), oldPos.y + sprites[i]->getBoundingBox().size.height*(animationAnchorPoint.y - oldAnchorPoint.y))); auto callback = [](cocos2d::Node* pSprite, cocos2d::Point pOldAnchorPoint, cocos2d::Point pOldPos){ pSprite->setAnchorPoint(pOldAnchorPoint); pSprite->setPosition(pOldPos); }; auto boundCallback = std::bind(callback, sprites[i], oldAnchorPoint, oldPos); auto action = cocos2d::Sequence::create(cocos2d::DelayTime::create(delayConst*i), cocos2d::RotateBy::create(0.2, 20*rotationDir), cocos2d::Spawn::create(cocos2d::RotateBy::create(0.4, -80*rotationDir), cocos2d::MoveBy::create(0.4, cocos2d::Point(20*moveDir.x, 30*moveDir.y)), nullptr), cocos2d::Spawn::create(cocos2d::RotateBy::create(0.4, 60*rotationDir), cocos2d::MoveBy::create(0.4, cocos2d::Point(-20*moveDir.x, -30*moveDir.y)), nullptr), cocos2d::CallFunc::create(boundCallback), nullptr); sprites[i]->runAction(action); } } void ToySpriteAnimator::sinusoidalMoveAnimation(std::vector sprites, float duration, std::vector moveDestinations, std::vector amplitudes, std::string easeOption) { for(int i = 0; i < sprites.size(); ++i){ //TODO: easeoption? auto moveToAction = cocos2d::MoveTo::create(duration, moveDestinations[i]); float amplitude = amplitudes[i]; auto dX = sqrt(amplitude/2); auto dY = dX; float sinDuration = 0.2; auto moveByAction1 = cocos2d::MoveBy::create(sinDuration, cocos2d::Vec2(dX, dY)); auto moveByAction2 = cocos2d::MoveBy::create(sinDuration, cocos2d::Vec2(-dX, -dY)); auto sinAction = cocos2d::Repeat::create(cocos2d::Sequence::create(moveByAction1, moveByAction2, nullptr), 100); static const int SinActionTag = 100; sinAction->setTag(SinActionTag); std::function boundCallback = std::bind([](cocos2d::Node* sprite, int actionTag){ sprite->stopActionByTag(actionTag); }, sprites[i], SinActionTag); auto wholeAction = cocos2d::Sequence::create(cocos2d::Spawn::create(moveToAction, sinAction, nullptr), cocos2d::DelayTime::create(duration), cocos2d::CallFunc::create(boundCallback), nullptr); sprites[i]->runAction(wholeAction); // sprites[i]->runAction(sinAction); } } cocos2d::Action* ToySpriteAnimator::actionWithEaseOption(cocos2d::ActionInterval* action, std::string easeOption) { cocos2d::Action* easedAction = action; if(easeOption != ""){ if(easeOption == "easeOut"){ easedAction = cocos2d::EaseOut::create(action, 1.2); } else if(easeOption == "easeIn"){ easedAction = cocos2d::EaseIn::create(action, 1.2); } else if(easeOption == "easeInOut"){ easedAction = cocos2d::EaseInOut::create(action, 1.2); } } return easedAction; } std::string ToySpriteAnimator::mapTagToRFAction(int tag) { auto animationTag = tag - RF_ANIMATION_TAG_BASE; switch(animationTag){ case 1: return "bounceAnimation"; case 2: return "floatAnimation"; case 3: return "windTugAnimation"; case 4: return "frameAnimation"; case 5: return "jumpAnimation"; case 6: return "scaleUpDownAnimation"; case 7: return "rotateForeverAnimation"; default: return "bounceAnimation"; } } void ToySpriteAnimator::restoreRFAction(cocos2d::Node* sprite, int actionTag) { auto animationTag = actionTag - RF_ANIMATION_TAG_BASE; AnimationUserData* userData = dynamic_cast(sprite->getUserObject()); if(animationTag == RF_ANIMATION_TAG_FLOAT_ANIMATION){ if(userData && userData->floatAnimationData){ float delay = userData->floatAnimationData->delay; std::vector> dxes; dxes.push_back(userData->floatAnimationData->dxRange); std::vector> dyes; dyes.push_back(userData->floatAnimationData->dyRange); float bezierTime = userData->floatAnimationData->bezierTime; ToySpriteAnimator::floatAnimation({sprite}, {delay}, dxes, dyes, bezierTime); } } else if (animationTag == RF_ANIMATION_TAG_BOUNCE_ANIMATION){ if(userData && userData->bounceAnimationData){ float delay = userData->bounceAnimationData->delay; float rotationAngle = userData->bounceAnimationData->rotationAngle; float rotationDuration = userData->bounceAnimationData->rotationDuration; float wholeDuration = userData->bounceAnimationData->wholeDuration; bool roundUp = userData->bounceAnimationData->roundUp; ToySpriteAnimator::bounceAnimation({sprite}, {delay}, {rotationDuration}, {rotationAngle}, {wholeDuration}, roundUp); } } } void ToySpriteAnimator::cleanUpAnimationData(cocos2d::Node* node) { if(node){ auto animData = dynamic_cast(node->getUserObject()); if(animData){ delete animData; } } }