// // SimpleActionParser.cpp // SteveMaggieCpp // // Created by Katarzyna Kalinowska-Górska on 31.05.2017. // // #include #include "SimpleActionParser.h" #include "JSONParseUtils.h" #include "SoundsRepo.h" #include "SoundUtils.h" //#include "DragAndDropHandler.h" #include "SpriteAnimator.h" #include "SceneWithUtils.h" #include "ValueStorage.h" //#include "UserDefaultsKeys.h" #include "MathUtils.h" class DynamicObjectMapper { public: ScenarioObject* createObjectFromClassName(std::string className, const rapidjson::Value& objectData, ActionParseDelegate* parseDelegate) { ScenarioObject* object = NULL; /*else if(className == "DragAndDropHandler"){ const auto& params = objectData["parameters"].GetArray(); // DragAndDropHandler::DragAndDropHandler(std::vector objectsToDrag, cocos2d::Node* destinationObject, std::vector wrongDraggedObjects, std::vector wrongDestinationObjects) object = new DragAndDropHandler(); } */ return object; } }; // main parse function cocos2d::Action* SimpleActionParser::parseJSONAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { cocos2d::Action* parsedAction = NULL; // log("SimpleActionParser: parsing action of type "+jsonActionObject.actionType); if(JSONParseUtils::hasMemberString(jsonActionObject, "actionType")){ std::string actionType = jsonActionObject["actionType"].GetString(); if(actionType == "wait"){ parsedAction = this->parseWaitAction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } else if(actionType == "createObject"){ parsedAction = this->parseCreateObjectAction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } else if(actionType == "setProperty"){ parsedAction = this->parseSetPropertyAction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } else if(actionType == "callFunction"){ parsedAction = this->parseCallFunctionAction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } else if(actionType == "playSound"){ parsedAction = this->parsePlaySoundAction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } else if(actionType == "playRandomSound"){ parsedAction = this->parsePlayRandomSoundAction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } else if(actionType == "reorderInParent"){ parsedAction = this->parseReorderInParentAction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } else if(actionType == "animateObjects"){ parsedAction = this->parseAnimateObjectsAction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } else if(actionType == "animateObjectByAnimationId"){ parsedAction = this->parseAnimateObjectByAnimationIdAction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } else if(actionType == "stopAnimations"){ parsedAction = this->parseStopAnimationsAction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } else if(actionType == "dismissCurrentDialog"){ parsedAction = this->parseDismissCurrentDialogAction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } else if(actionType == "randomSwitchItemPositions"){ parsedAction = this->parseRandomObjectSwapAction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } } return parsedAction; } // functions for parsing differenct actions /* common properties: "actionType" "condition" */ /* "actionType" = "wait" "seconds" [float] */ cocos2d::Action* SimpleActionParser::parseWaitAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { if(JSONParseUtils::hasMemberFloat(jsonActionObject, "seconds")){ float seconds = jsonActionObject["seconds"].GetFloat(); if(notifyDelegateWhenFinished){ auto storedValueKey = ValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getValueStorageContainerName()); auto actionFunction = [](float pSeconds, std::string pStoredValueKey, ActionParseDelegate* pParseDelegate){ static int keyModifier = 0; static int modulus = 100; static std::string keyBase = "waitAction"; std::string key = keyBase + std::to_string((++keyModifier)%modulus); pParseDelegate->scheduleOnce(std::bind([](float, std::string p2StoredValueKey, ActionParseDelegate* p2ParseDelegate){ p2ParseDelegate->actionFinished(*ValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getValueStorageContainerName())); ValueStorage::getInstance().removeStoredValue(p2StoredValueKey, p2ParseDelegate->getValueStorageContainerName()); // if the callback is unscheduled, this will not be called. However, when the scene changes, the ValueStorage is always cleared. }, std::placeholders::_1, pStoredValueKey, pParseDelegate), pSeconds, key); }; return cocos2d::CallFunc::create(std::bind(actionFunction, seconds, storedValueKey, parseDelegate)); } return cocos2d::DelayTime::create(seconds); } return nullptr; } /* "actionType" = "createObject" "objectClass" [string] "objectName" [string] "parameters" [array of arbitrary things for the constructor or nothing; see parseParameters()] */ cocos2d::Action* SimpleActionParser::parseCreateObjectAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate){ auto storedJsonActionObject = ValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); if(ActionParser::getInstance().checkLateCondition(*storedJsonActionObject, pParseDelegate)){ if(JSONParseUtils::hasMemberString(*storedJsonActionObject, "objectClass") && JSONParseUtils::hasMemberString(*storedJsonActionObject, "objectName")){ DynamicObjectMapper mapper; auto newObject = mapper.createObjectFromClassName((*storedJsonActionObject)["objectClass"].GetString(), *storedJsonActionObject, pParseDelegate); pParseDelegate->addNewObject((*storedJsonActionObject)["objectName"].GetString(), newObject); } } ValueStorage::getInstance().removeStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); }; return this->finalizeParseActionWithActionFunction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished, std::bind(actionFunction, storedValueKey, parseDelegate)); } /* "actionType" = "setProperty" "objectName" [string] | "objectNames" [array of strings] | nothing "propertyName" [string] "value" [anything] */ cocos2d::Action* SimpleActionParser::parseSetPropertyAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getValueStorageContainerName()); std::function callback = [&](std::string pStoredValueKey, ActionParseDelegate* pActionParseDelegate, bool pNotifyDelegate){ auto storedJsonActionObject = ValueStorage::getInstance().getStoredValue(pStoredValueKey, pActionParseDelegate->getValueStorageContainerName()); if(ActionParser::getInstance().checkLateCondition(*storedJsonActionObject, pActionParseDelegate)){ auto objects = ActionParser::getInstance().prepareObjectsForAction(*storedJsonActionObject, pActionParseDelegate); for(auto object : objects){ object->setProperty((*storedJsonActionObject)["propertyName"].GetString(), (*storedJsonActionObject)["value"], pActionParseDelegate); } } ValueStorage::getInstance().removeStoredValue(pStoredValueKey, pActionParseDelegate->getValueStorageContainerName()); }; auto actionFunction = std::bind(callback, storedValueKey, parseDelegate, notifyDelegateWhenFinished); return this->finalizeParseActionWithActionFunction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished, actionFunction); } /* "actionType" = "callFunction" "objectName" [string] | "objectNames" [array of strings] | nothing "functionName" [string] "parameters" [array of arbitrary things or nothing; see parseParameters()] */ cocos2d::Action* SimpleActionParser::parseCallFunctionAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto key = ValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate){ auto restoredValue = ValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); if(ActionParser::getInstance().checkLateCondition(*restoredValue, pParseDelegate)){ auto objects = ActionParser::getInstance().prepareObjectsForAction(*restoredValue, pParseDelegate); const rapidjson::Value* params = NULL; if(JSONParseUtils::hasMemberArray(*restoredValue, "parameters")){ params = &((*restoredValue)["parameters"]); } for(auto object : objects){ object->callFunctionByName((*restoredValue)["functionName"].GetString(), params, pParseDelegate); } } ValueStorage::getInstance().removeStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); }; return this->finalizeParseActionWithActionFunction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished, std::bind(actionFunction, key, parseDelegate)); } /* "actionType" = "playSound" "sound" [string] "useAlternativePath" [boolean] "loop" [boolean] "keepPreviousSounds" [boolean] */ cocos2d::Action* SimpleActionParser::parsePlaySoundAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storageKey = ValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getValueStorageContainerName()); auto actionFunction = [&](std::string pStorageKey, ActionParseDelegate* pParseDelegate){ auto storedJsonActionObject = ValueStorage::getInstance().getStoredValue(pStorageKey, pParseDelegate->getValueStorageContainerName()); if(ActionParser::getInstance().checkLateCondition(*storedJsonActionObject, pParseDelegate)){ if(!JSONParseUtils::hasMemberString(*storedJsonActionObject, "sound")){ return; } std::string sound = (*storedJsonActionObject)["sound"].GetString(); auto soundPath = JSONParseUtils::checkMemberBool(*storedJsonActionObject, "useAlternativePath", true) ? pParseDelegate->getAlternativeSoundsPath() +sound : pParseDelegate->getDefaultSoundsPath() + sound; // auto loop = JSONParseUtils::hasMemberBool(*storedJsonActionObject, "loop") && (*storedJsonActionObject)["loop"].GetBool() == true ? true : false; if(!JSONParseUtils::hasMemberBool(*storedJsonActionObject, "keepPreviousSounds") || JSONParseUtils::checkMemberBool(*storedJsonActionObject, "keepPreviousSounds", false)){ // CocosDenshion::SimpleAudioEngine::getInstance()->stopAllEffects(); SoundsRepo::stopAllSounds(); } bool cancelSameSound = JSONParseUtils::checkMemberBool(*storedJsonActionObject, "cancelSameSound", true); if(cancelSameSound){ auto soundId = pParseDelegate->removeStoredSoundId(soundPath); if(soundId != -1){ SoundsRepo::stopSoundById(soundId); // CocosDenshion::SimpleAudioEngine::getInstance()->stopEffect(soundId); } } unsigned int newSoundId = SoundsRepo::playSound(soundPath.c_str()); //TODO loop //CocosDenshion::SimpleAudioEngine::getInstance()->playEffect(soundPath.c_str(), loop); if(cancelSameSound){ pParseDelegate->storeSoundId(soundPath, newSoundId); } } ValueStorage::getInstance().removeStoredValue(pStorageKey, pParseDelegate->getValueStorageContainerName()); }; return this->finalizeParseActionWithActionFunction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished, std::bind(actionFunction, storageKey, parseDelegate)); } /* "actionType" = "playRandomSound" "sounds" [array of strings] "useAlternativePath" [boolean] "keepPreviousSounds" [boolean] */ cocos2d::Action* SimpleActionParser::parsePlayRandomSoundAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate){ auto storedActionObject = ValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); if(ActionParser::getInstance().checkLateCondition(*storedActionObject, pParseDelegate)){ auto soundFolder = JSONParseUtils::checkMemberBool(*storedActionObject, "useAlternativePath", true) ? pParseDelegate->getAlternativeSoundsPath() : pParseDelegate->getDefaultSoundsPath(); auto stopEffects = !JSONParseUtils::hasMemberBool(*storedActionObject, "keepPreviousSounds") || JSONParseUtils::checkMemberBool(*storedActionObject, "keepPreviousSounds", false) ? true : false; if(JSONParseUtils::hasMemberArray(*storedActionObject, "sounds")){ std::vector sounds; for(const auto& sound : (*storedActionObject)["sounds"].GetArray()){ sounds.push_back(sound.GetString()); } SoundUtils::playRandomSound(soundFolder, sounds, stopEffects); } } ValueStorage::getInstance().removeStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); }; return this->finalizeParseActionWithActionFunction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished, std::bind(actionFunction, storedValueKey, parseDelegate)); } /* "actionType" = "reorderInParent" "objectName" [string] "newDepth" [number] */ cocos2d::Action* SimpleActionParser::parseReorderInParentAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate){ auto storedActionObject = ValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); if(ActionParser::getInstance().checkLateCondition(*storedActionObject, pParseDelegate)){ if(JSONParseUtils::hasMemberString(*storedActionObject, "objectName") && JSONParseUtils::hasMemberInt(*storedActionObject, "newDepth")){ auto object = pParseDelegate->getObjectByName((*storedActionObject)["objectName"].GetString()); auto objectNode = dynamic_cast(object); if(objectNode){ objectNode->getParent()->reorderChild(objectNode, (*storedActionObject)["newDepth"].GetInt()); } } } ValueStorage::getInstance().removeStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); }; return this->finalizeParseActionWithActionFunction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished, std::bind(actionFunction, storedValueKey, parseDelegate)); } /* "actionType" = "animateObjects" "objectName" [string] | "objectNames" [array of strings] "animationName" [string] "parameters" [array of arbitrary things or nothing; see parseParameters()] "animationConditions" [array of conditions for different sprites in the array] */ cocos2d::Action* SimpleActionParser::parseAnimateObjectsAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) //todo put all into the acton function for late parse { auto objects = ActionParser::getInstance().prepareObjectsForAction(jsonActionObject, parseDelegate); if(JSONParseUtils::hasMemberArray(jsonActionObject, "animationConditions")){ const auto& conditionsArray = jsonActionObject["animationConditions"].GetArray(); if(conditionsArray.Size() >= objects.size()){ for(int i = (int)objects.size()-1; i >= 0; --i){ if(conditionsArray[i].IsString() && ActionParser::getInstance().checkCondition(conditionsArray[i].GetString(), parseDelegate) == false){ objects.erase(objects.begin() + i, objects.begin() + i + 1); } } } } std::vector nodes; for(auto object : objects){ auto objAsNode = dynamic_cast(object); nodes.push_back(objAsNode); } auto storageKey = ValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getValueStorageContainerName()); auto actionFunction = [&](std::vector pNodes, std::string pStorageKey, ActionParseDelegate* pParseDelegate){ auto storedJsonObject = ValueStorage::getInstance().getStoredValue(pStorageKey, pParseDelegate->getValueStorageContainerName()); if(ActionParser::getInstance().checkLateCondition(*storedJsonObject, pParseDelegate)){ std::string animationName = (*storedJsonObject)["animationName"].GetString(); const rapidjson::Value* params = nullptr; if(JSONParseUtils::hasMemberArray(*storedJsonObject, "parameters")){ params = &((*storedJsonObject)["parameters"]); } SpriteAnimator::runAnimationForName(animationName, pNodes, params); } ValueStorage::getInstance().removeStoredValue(pStorageKey, pParseDelegate->getValueStorageContainerName()); }; return this->finalizeParseActionWithActionFunction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished, std::bind(actionFunction, nodes, storageKey, parseDelegate)); } /* "actionType" = "animateObjectByAnimationId" "objectName" [string] "animationId" [string] The object should have the animation with given "animationId" specified in its "animations" field in the layout file. */ cocos2d::Action* SimpleActionParser::parseAnimateObjectByAnimationIdAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate){ auto storedJsonActionObject = ValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); auto objects = ActionParser::getInstance().prepareObjectsForAction(*storedJsonActionObject, pParseDelegate); auto animationObject = objects[0]->getAnimationById((*storedJsonActionObject)["animationId"].GetString()); //TODO sprobowac wywalic poza lambde if(ActionParser::getInstance().checkLateCondition(*storedJsonActionObject, pParseDelegate)){ std::string animationName = (*animationObject)["animationName"].GetString(); const rapidjson::Value* params = NULL; if(JSONParseUtils::hasMemberArray((*animationObject), "parameters")){ params = &((*animationObject)["parameters"]); } SpriteAnimator::runAnimationForName(animationName, {dynamic_cast(objects[0])}, params); } ValueStorage::getInstance().removeStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); }; auto boundActionFunction = std::bind(actionFunction, storedValueKey, parseDelegate); return this->finalizeParseActionWithActionFunction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished, boundActionFunction); } /* "actionType" = "stopAnimations" "objectName" [string] | "objectNames" [array of strings] */ cocos2d::Action* SimpleActionParser::parseStopAnimationsAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate){ auto storedJsonActionObject = ValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); if(ActionParser::getInstance().checkLateCondition(*storedJsonActionObject, pParseDelegate)){ auto objects = ActionParser::getInstance().prepareObjectsForAction(*storedJsonActionObject, pParseDelegate); for(int i = 0; i < objects.size(); ++i){ dynamic_cast(objects[i])->stopAllActions(); } } ValueStorage::getInstance().removeStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); }; return this->finalizeParseActionWithActionFunction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished, std::bind(actionFunction, storedValueKey, parseDelegate)); } cocos2d::Action* SimpleActionParser::parseDismissCurrentDialogAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { return cocos2d::CallFunc::create([](){ auto currentScene = dynamic_cast(cocos2d::Director::getInstance()->getRunningScene()); currentScene->dismissCurrentDialog(); }); } cocos2d::Action* SimpleActionParser::finalizeParseActionWithActionFunction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished, std::function preparedActionFunction) { if(JSONParseUtils::checkMemberBool(jsonActionObject, "instantAction", true)){ parseDelegate->runInstantly(preparedActionFunction); return NULL; } else { return ActionParser::getInstance().embedFunctionInAction(preparedActionFunction, jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } } cocos2d::Action* SimpleActionParser::parseRandomObjectSwapAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished){ // "objectGroups" : // [ // {"t_doll1" : ["t_robot2", "t_robot4", "t_bear1", "t_bear3", "t_bear4", "blueBoat", "ballSpots", "ballStripy"]}, // {"t_doll2" : ["t_robot2", "t_robot4", "t_bear1", "t_bear3", "t_bear4", "blueBoat", "ballSpots", "ballStripy"]}, // {"t_doll3" : ["t_bear1", "t_bear3", "dinoRed", "dinoGreen"]}, // {"t_auto3" : ["t_bear2", "lego3"]}, // {"t_doll4" : ["t_robot2", "t_robot4", "t_bear1", "t_bear3", "t_bear4", "blueBoat", "ballSpots", "ballStripy", "t_auto1", "t_auto4", "t_train1", "t_train2", "t_train3", "t_train4", "t_bear2"]}, // {"t_auto1" : ["t_train1", "t_train2", "t_train3", "t_train4", "t_doll4", "t_bear2", "ballStripy"]}, // {"t_auto2" : ["dinoRed", "dinoGreen", "lego3", "blueBoat", "t_bear2", "t_bear4"]}, // {"t_auto4" : ["t_train1", "t_train2", "t_train3", "t_train4", "t_doll4", "t_bear2", "ballStripy"]}, // {"t_train1" : ["t_auto1", "t_auto4", "t_doll4", "t_bear2", "ballStripy"]}, // {"t_train2" : ["t_auto1", "t_auto4", "t_doll4", "t_bear2", "ballStripy"]}, // {"t_train3" : ["t_auto1", "t_auto4", "t_doll4", "t_bear2", "ballStripy"]}, // {"t_train4" : ["t_auto1", "t_auto4", "t_doll4", "t_bear2", "ballStripy"]}, // {"t_bear1" : ["t_robot2", "t_robot4", "t_doll1", "t_doll2", "t_doll4", "blueBoat", "ballSpots", "ballStripy", "t_doll3", "dinoRed", "dinoGreen"]}, // {"t_bear2" : ["dinoRed", "dinoGreen", "lego3", "blueBoat", "t_auto2", "t_auto3", "t_train1", "t_train2", "t_train3", "t_train4", "t_doll4", "ballStripy"]}, // {"t_bear3" : ["t_robot2", "t_robot4", "t_doll1", "t_doll2", "t_doll4", "blueBoat", "ballSpots", "ballStripy", "t_doll3", "dinoRed", "dinoGreen"]}, // {"t_bear4" : ["dinoRed", "dinoGreen", "lego3", "blueBoat", "t_auto2", "t_robot2", "t_robot4", "t_doll1", "t_doll2", "t_doll4", "ballSpots", "ballStripy"]} // ] //TODO add probability of swap, maybe different for different levels auto storedValueKey = ValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate){ auto actionJson = ValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); if(JSONParseUtils::hasMemberArray(*actionJson, "objectGroups")){ auto objectGroups = (*actionJson)["objectGroups"].GetArray(); auto swapProbability = (*actionJson)["swapProbability"].GetFloat(); // std::map> objectMap; std::vector usedObjects; //keep info which objects are already swapped, not to swap them again for(int i = 0; i < objectGroups.Size(); ++i){ // first throw dice to see if we should swap at all auto randomFloat = MathUtils::getRandom(0, 1); if(randomFloat > swapProbability){ continue; } std::string mainObjectName = objectGroups[i].MemberBegin()->name.GetString(); if(std::find(usedObjects.begin(), usedObjects.end(), mainObjectName) != usedObjects.end()) { // printf("already swapped %s! skipping\n", mainObjectName.c_str()); continue; // object already swapped, move on } auto availableObjects = JSONParseUtils::parseStringArray(objectGroups[i].MemberBegin()->value); for(int i = (int)availableObjects.size()-1; i >= 0; --i){ if(std::find(usedObjects.begin(), usedObjects.end(), availableObjects[i]) != usedObjects.end()){ availableObjects.erase(availableObjects.begin()+i); } } if(availableObjects.size() == 0){ // printf("nothing to swap %s with! skipping\n", mainObjectName.c_str()); continue; //nothing to swap with } auto objectToSwapWith = MathUtils::getRandomElement(availableObjects); auto object1 = dynamic_cast(parseDelegate->getObjectByName(mainObjectName)); auto object2 = dynamic_cast(parseDelegate->getObjectByName(objectToSwapWith)); auto tempPos = object1->getPosition(); auto tempZOrder = object1->getZOrder(); object1->setPosition(object2->getPosition()); object1->setZOrder(object2->getZOrder()); object2->setPosition(tempPos); object2->setZOrder(tempZOrder); usedObjects.push_back(mainObjectName); usedObjects.push_back(objectToSwapWith); // printf("swapping %s with %s\n", mainObjectName.c_str(), objectToSwapWith.c_str()); } } ValueStorage::getInstance().removeStoredValue(pStoredValueKey, pParseDelegate->getValueStorageContainerName()); }; return this->finalizeParseActionWithActionFunction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished, std::bind(actionFunction, storedValueKey, parseDelegate)); }