// // ToySimpleActionParser.cpp // SteveMaggieCpp // // Created by Katarzyna Kalinowska-Górska on 31.05.2017. // // #include #include "ToySimpleActionParser.h" #include "ToyJSONParseUtils.h" #include "ToySoundsRepo.h" #include "ToySoundUtils.h" //#include "ToyDragAndDropHandler.h" #include "ToySpriteAnimator.h" #include "ToySceneWithUtils.h" #include "ToyValueStorage.h" //#include "UserDefaultsKeys.h" #include "ToyMathUtils.h" class DynamicObjectMapper { public: ToyScenarioObject* createObjectFromClassName(std::string className, const rapidjson::Value& objectData, ActionParseDelegate* parseDelegate) { ToyScenarioObject* object = NULL; /*else if(className == "DragAndDropHandler"){ const auto& params = objectData["parameters"].GetArray(); // ToyDragAndDropHandler::ToyDragAndDropHandler(std::vector objectsToDrag, cocos2d::Node* destinationObject, std::vector wrongDraggedObjects, std::vector wrongDestinationObjects) object = new ToyDragAndDropHandler(); } */ return object; } }; // main parse function cocos2d::Action* ToySimpleActionParser::parseJSONAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { cocos2d::Action* parsedAction = NULL; // log("ToySimpleActionParser: parsing action of type "+jsonActionObject.actionType); if(ToyJSONParseUtils::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* ToySimpleActionParser::parseWaitAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { if(ToyJSONParseUtils::hasMemberFloat(jsonActionObject, "seconds")){ float seconds = jsonActionObject["seconds"].GetFloat(); if(notifyDelegateWhenFinished){ auto storedValueKey = ToyValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getToyValueStorageContainerName()); 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(*ToyValueStorage::getInstance().getStoredValue(p2StoredValueKey, p2ParseDelegate->getToyValueStorageContainerName())); ToyValueStorage::getInstance().removeStoredValue(p2StoredValueKey, p2ParseDelegate->getToyValueStorageContainerName()); // if the callback is unscheduled, this will not be called. However, when the scene changes, the ToyValueStorage 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* ToySimpleActionParser::parseCreateObjectAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ToyValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getToyValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate){ auto storedJsonActionObject = ToyValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); if(ToyActionParser::getInstance().checkLateCondition(*storedJsonActionObject, pParseDelegate)){ if(ToyJSONParseUtils::hasMemberString(*storedJsonActionObject, "objectClass") && ToyJSONParseUtils::hasMemberString(*storedJsonActionObject, "objectName")){ DynamicObjectMapper mapper; auto newObject = mapper.createObjectFromClassName((*storedJsonActionObject)["objectClass"].GetString(), *storedJsonActionObject, pParseDelegate); pParseDelegate->addNewObject((*storedJsonActionObject)["objectName"].GetString(), newObject); } } ToyValueStorage::getInstance().removeStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); }; 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* ToySimpleActionParser::parseSetPropertyAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ToyValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getToyValueStorageContainerName()); std::function callback = [&](std::string pStoredValueKey, ActionParseDelegate* pActionParseDelegate, bool pNotifyDelegate){ auto storedJsonActionObject = ToyValueStorage::getInstance().getStoredValue(pStoredValueKey, pActionParseDelegate->getToyValueStorageContainerName()); if(ToyActionParser::getInstance().checkLateCondition(*storedJsonActionObject, pActionParseDelegate)){ auto objects = ToyActionParser::getInstance().prepareObjectsForAction(*storedJsonActionObject, pActionParseDelegate); for(auto object : objects){ object->setProperty((*storedJsonActionObject)["propertyName"].GetString(), (*storedJsonActionObject)["value"], pActionParseDelegate); } } ToyValueStorage::getInstance().removeStoredValue(pStoredValueKey, pActionParseDelegate->getToyValueStorageContainerName()); }; 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* ToySimpleActionParser::parseCallFunctionAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto key = ToyValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getToyValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate){ auto restoredValue = ToyValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); if(ToyActionParser::getInstance().checkLateCondition(*restoredValue, pParseDelegate)){ auto objects = ToyActionParser::getInstance().prepareObjectsForAction(*restoredValue, pParseDelegate); const rapidjson::Value* params = NULL; if(ToyJSONParseUtils::hasMemberArray(*restoredValue, "parameters")){ params = &((*restoredValue)["parameters"]); } for(auto object : objects){ object->callFunctionByName((*restoredValue)["functionName"].GetString(), params, pParseDelegate); } } ToyValueStorage::getInstance().removeStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); }; return this->finalizeParseActionWithActionFunction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished, std::bind(actionFunction, key, parseDelegate)); } /* "actionType" = "playSound" "sound" [string] "useAlternativePath" [boolean] "loop" [boolean] "keepPreviousSounds" [boolean] */ cocos2d::Action* ToySimpleActionParser::parsePlaySoundAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storageKey = ToyValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getToyValueStorageContainerName()); auto actionFunction = [&](std::string pStorageKey, ActionParseDelegate* pParseDelegate){ auto storedJsonActionObject = ToyValueStorage::getInstance().getStoredValue(pStorageKey, pParseDelegate->getToyValueStorageContainerName()); if(ToyActionParser::getInstance().checkLateCondition(*storedJsonActionObject, pParseDelegate)){ if(!ToyJSONParseUtils::hasMemberString(*storedJsonActionObject, "sound")){ return; } std::string sound = (*storedJsonActionObject)["sound"].GetString(); auto soundPath = ToyJSONParseUtils::checkMemberBool(*storedJsonActionObject, "useAlternativePath", true) ? pParseDelegate->getAlternativeSoundsPath() +sound : pParseDelegate->getDefaultSoundsPath() + sound; // auto loop = ToyJSONParseUtils::hasMemberBool(*storedJsonActionObject, "loop") && (*storedJsonActionObject)["loop"].GetBool() == true ? true : false; if(!ToyJSONParseUtils::hasMemberBool(*storedJsonActionObject, "keepPreviousSounds") || ToyJSONParseUtils::checkMemberBool(*storedJsonActionObject, "keepPreviousSounds", false)){ // CocosDenshion::SimpleAudioEngine::getInstance()->stopAllEffects(); ToySoundsRepo::stopAllSounds(); } bool cancelSameSound = ToyJSONParseUtils::checkMemberBool(*storedJsonActionObject, "cancelSameSound", true); if(cancelSameSound){ auto soundId = pParseDelegate->removeStoredSoundId(soundPath); if(soundId != -1){ ToySoundsRepo::stopSoundById(soundId); // CocosDenshion::SimpleAudioEngine::getInstance()->stopEffect(soundId); } } unsigned int newSoundId = ToySoundsRepo::playSound(soundPath.c_str()); //TODO loop //CocosDenshion::SimpleAudioEngine::getInstance()->playEffect(soundPath.c_str(), loop); if(cancelSameSound){ pParseDelegate->storeSoundId(soundPath, newSoundId); } } ToyValueStorage::getInstance().removeStoredValue(pStorageKey, pParseDelegate->getToyValueStorageContainerName()); }; return this->finalizeParseActionWithActionFunction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished, std::bind(actionFunction, storageKey, parseDelegate)); } /* "actionType" = "playRandomSound" "sounds" [array of strings] "useAlternativePath" [boolean] "keepPreviousSounds" [boolean] */ cocos2d::Action* ToySimpleActionParser::parsePlayRandomSoundAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ToyValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getToyValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate){ auto storedActionObject = ToyValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); if(ToyActionParser::getInstance().checkLateCondition(*storedActionObject, pParseDelegate)){ auto soundFolder = ToyJSONParseUtils::checkMemberBool(*storedActionObject, "useAlternativePath", true) ? pParseDelegate->getAlternativeSoundsPath() : pParseDelegate->getDefaultSoundsPath(); auto stopEffects = !ToyJSONParseUtils::hasMemberBool(*storedActionObject, "keepPreviousSounds") || ToyJSONParseUtils::checkMemberBool(*storedActionObject, "keepPreviousSounds", false) ? true : false; if(ToyJSONParseUtils::hasMemberArray(*storedActionObject, "sounds")){ std::vector sounds; for(const auto& sound : (*storedActionObject)["sounds"].GetArray()){ sounds.push_back(sound.GetString()); } ToySoundUtils::playRandomSound(soundFolder, sounds, stopEffects); } } ToyValueStorage::getInstance().removeStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); }; return this->finalizeParseActionWithActionFunction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished, std::bind(actionFunction, storedValueKey, parseDelegate)); } /* "actionType" = "reorderInParent" "objectName" [string] "newDepth" [number] */ cocos2d::Action* ToySimpleActionParser::parseReorderInParentAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ToyValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getToyValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate){ auto storedActionObject = ToyValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); if(ToyActionParser::getInstance().checkLateCondition(*storedActionObject, pParseDelegate)){ if(ToyJSONParseUtils::hasMemberString(*storedActionObject, "objectName") && ToyJSONParseUtils::hasMemberInt(*storedActionObject, "newDepth")){ auto object = pParseDelegate->getObjectByName((*storedActionObject)["objectName"].GetString()); auto objectNode = dynamic_cast(object); if(objectNode){ objectNode->getParent()->reorderChild(objectNode, (*storedActionObject)["newDepth"].GetInt()); } } } ToyValueStorage::getInstance().removeStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); }; 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* ToySimpleActionParser::parseAnimateObjectsAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) //todo put all into the acton function for late parse { auto objects = ToyActionParser::getInstance().prepareObjectsForAction(jsonActionObject, parseDelegate); if(ToyJSONParseUtils::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() && ToyActionParser::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 = ToyValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getToyValueStorageContainerName()); auto actionFunction = [&](std::vector pNodes, std::string pStorageKey, ActionParseDelegate* pParseDelegate){ auto storedJsonObject = ToyValueStorage::getInstance().getStoredValue(pStorageKey, pParseDelegate->getToyValueStorageContainerName()); if(ToyActionParser::getInstance().checkLateCondition(*storedJsonObject, pParseDelegate)){ std::string animationName = (*storedJsonObject)["animationName"].GetString(); const rapidjson::Value* params = nullptr; if(ToyJSONParseUtils::hasMemberArray(*storedJsonObject, "parameters")){ params = &((*storedJsonObject)["parameters"]); } ToySpriteAnimator::runAnimationForName(animationName, pNodes, params); } ToyValueStorage::getInstance().removeStoredValue(pStorageKey, pParseDelegate->getToyValueStorageContainerName()); }; 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* ToySimpleActionParser::parseAnimateObjectByAnimationIdAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ToyValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getToyValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate){ auto storedJsonActionObject = ToyValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); auto objects = ToyActionParser::getInstance().prepareObjectsForAction(*storedJsonActionObject, pParseDelegate); auto animationObject = objects[0]->getAnimationById((*storedJsonActionObject)["animationId"].GetString()); //TODO sprobowac wywalic poza lambde if(ToyActionParser::getInstance().checkLateCondition(*storedJsonActionObject, pParseDelegate)){ std::string animationName = (*animationObject)["animationName"].GetString(); const rapidjson::Value* params = NULL; if(ToyJSONParseUtils::hasMemberArray((*animationObject), "parameters")){ params = &((*animationObject)["parameters"]); } ToySpriteAnimator::runAnimationForName(animationName, {dynamic_cast(objects[0])}, params); } ToyValueStorage::getInstance().removeStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); }; auto boundActionFunction = std::bind(actionFunction, storedValueKey, parseDelegate); return this->finalizeParseActionWithActionFunction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished, boundActionFunction); } /* "actionType" = "stopAnimations" "objectName" [string] | "objectNames" [array of strings] */ cocos2d::Action* ToySimpleActionParser::parseStopAnimationsAction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished) { auto storedValueKey = ToyValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getToyValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate){ auto storedJsonActionObject = ToyValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); if(ToyActionParser::getInstance().checkLateCondition(*storedJsonActionObject, pParseDelegate)){ auto objects = ToyActionParser::getInstance().prepareObjectsForAction(*storedJsonActionObject, pParseDelegate); for(int i = 0; i < objects.size(); ++i){ dynamic_cast(objects[i])->stopAllActions(); } } ToyValueStorage::getInstance().removeStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); }; return this->finalizeParseActionWithActionFunction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished, std::bind(actionFunction, storedValueKey, parseDelegate)); } cocos2d::Action* ToySimpleActionParser::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* ToySimpleActionParser::finalizeParseActionWithActionFunction(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished, std::function preparedActionFunction) { if(ToyJSONParseUtils::checkMemberBool(jsonActionObject, "instantAction", true)){ parseDelegate->runInstantly(preparedActionFunction); return NULL; } else { return ToyActionParser::getInstance().embedFunctionInAction(preparedActionFunction, jsonActionObject, parseDelegate, notifyDelegateWhenFinished); } } cocos2d::Action* ToySimpleActionParser::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 = ToyValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getToyValueStorageContainerName()); auto actionFunction = [&](std::string pStoredValueKey, ActionParseDelegate* pParseDelegate){ auto actionJson = ToyValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); if(ToyJSONParseUtils::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 = ToyMathUtils::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 = ToyJSONParseUtils::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 = ToyMathUtils::getRandomElement(availableObjects); auto object1 = dynamic_cast(parseDelegate->getObjectByName(mainObjectName)); auto object2 = dynamic_cast(parseDelegate->getObjectByName(objectToSwapWith)); auto tempPos = object1->getPosition(); auto tempZOrder = object1->getLocalZOrder(); object1->setPosition(object2->getPosition()); object1->setLocalZOrder(object2->getLocalZOrder()); object2->setPosition(tempPos); object2->setLocalZOrder(tempZOrder); usedObjects.push_back(mainObjectName); usedObjects.push_back(objectToSwapWith); // printf("swapping %s with %s\n", mainObjectName.c_str(), objectToSwapWith.c_str()); } } ToyValueStorage::getInstance().removeStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName()); }; return this->finalizeParseActionWithActionFunction(jsonActionObject, parseDelegate, notifyDelegateWhenFinished, std::bind(actionFunction, storedValueKey, parseDelegate)); }