// // AniParentScene.cpp // SteveMaggieCpp // // Created by Katarzyna Kalinowska-Górska on 16.05.2017. // // #include #include "AniParentScene.h" #include "AniLayoutParser.h" #include "AniSimpleButton.h" #include "AniTwoStateButton.h" #include "AniMathUtils.h" #include "AniStringUtils.h" #include "AniResourceUtilities.h" #include "AniMiscUtils.h" #include "AniTOSAcceptPopupView.h" #include "AniLevelPickerLayer.h" #include "AniSoundsRepo.h" #include "HelloWorldScene.h" AniParentScene* AniParentScene::create(std::string layoutFilePath, std::string scenarioFilePath) { AniParentScene * scene = new (std::nothrow) AniParentScene(); if(scene && scene->initWithConfigurationFiles(layoutFilePath, scenarioFilePath)) { scene->autorelease(); return scene; } CC_SAFE_DELETE(scene); return nullptr; } bool AniParentScene::initWithConfigurationFiles(std::string layoutFilePath, std::string scenarioFilePath) { if(!AniSceneWithUtils::init()) { return false; } _layoutFilePath = layoutFilePath; _scenarioFilePath = scenarioFilePath; _loadFromAssets = false; _layers.clear(); _objects.clear(); _alwaysSkipDemo = false; _layoutLoaded = false; // _AniScenarioHandler = new AniScenarioHandler(this); // _AniScenarioObjects.insert({"AniScenarioHandler", _AniScenarioHandler}); _userTaskInteractionStarted = false; _currentTask = ""; _rightObjectTouchedAlready = false; //TODO these should probably be in the WorksheetScene _isHandlingTouches = false; this->clearTouchHandlers(); this->resetLastUserTouchTimes(); return true; } void AniParentScene::reloadLayoutClean() { this->removeAllChildren(); _layers.clear(); _objects.clear(); _AniScenarioObjects.clear(); // _AniScenarioObjects.insert({"AniScenarioHandler", _AniScenarioHandler}); _userTaskInteractionStarted = false; _currentTask = ""; _rightObjectTouchedAlready = false; //TODO these should probably be in the WorksheetScene _isHandlingTouches = false; this->clearTouchHandlers(); this->resetLastUserTouchTimes(); this->loadLayout(true); } void AniParentScene::loadLayout(bool forceLoad) { if(!this->_layoutLoaded || forceLoad){ _layoutLoaded = false; if (_loadFromAssets && cocos2d::FileUtils::getInstance()->isFileExist(this->_layoutFilePath)) { auto& AniLayoutParser = AniLayoutParser::getInstance(); AniLayoutParser.loadLayoutFromJSONFile(this->_layoutFilePath, this); this->_layoutLoaded = true; } else if(!_loadFromAssets){ auto& AniLayoutParser = AniLayoutParser::getInstance(); AniLayoutParser.loadLayoutFromDownloadedJSONFile(this->_layoutFilePath, this); this->_layoutLoaded = true; } } } void AniParentScene::loadScenario(bool skipDemoActions) { // auto fileUtils = cocos2d::FileUtils::getInstance(); // if (fileUtils->isFileExist(this->_scenarioFilePath)) { // std::string jsonString = fileUtils->getStringFromFile(this->_scenarioFilePath); // _AniScenarioHandler->loadScenarioFromJSONString(jsonString, skipDemoActions); // } } void AniParentScene::setLoadFromAssets(bool loadFromAssets) { _loadFromAssets = loadFromAssets; } // overrides void AniParentScene::onEnter() { this->configureTouchHandlers(); this->configureTransitionListeners(); AniSceneWithUtils::onEnter(); // auto playing = this->playBackgroundMusic(true); // this->adjustBgMusicButton(playing); } void AniParentScene::onExit() { AniSceneWithUtils::onExit(); // if(_AniScenarioHandler){ // _AniScenarioHandler->end(); //// delete _AniScenarioHandler; //TODO do it somewhere when the scene gets dealloced // } // this->stopBackgroundMusic(false); } void AniParentScene::configureTransitionListeners() //TODO check if it works. remove somewhere later the vent listeners? leaks? { _eventDispatcher->addCustomEventListener("game_on_hide", CC_CALLBACK_1(AniParentScene::onGameHide, this)); _eventDispatcher->addCustomEventListener("game_on_show", CC_CALLBACK_1(AniParentScene::onGameShow, this)); } void AniParentScene::onGameHide(cocos2d::EventCustom* event) { // _AniScenarioHandler->pauseScenario(); } void AniParentScene::onGameShow(cocos2d::EventCustom* event) { // _AniScenarioHandler->resumeScenario(); } // object config & handlers AniScenarioObject* AniParentScene::getObjectByName(std::string objectName) { if(_objects.find(objectName) == _objects.end()){ if(_AniScenarioObjects.find(objectName) == _AniScenarioObjects.end()){ return NULL; } return _AniScenarioObjects.at(objectName); } return dynamic_cast(_objects.at(objectName)); } void AniParentScene::addNewObject(std::string objectName, AniScenarioObject* newObject) { _AniScenarioObjects.insert({objectName, newObject}); } void AniParentScene::setupBackgroundMusic(std::string backgroundMusicPath) { _backgroundMusicFilePath = backgroundMusicPath; } bool AniParentScene::touchHandlerForWidget(std::string objectName, cocos2d::ui::Widget::TouchEventType touchEventType) { if(objectName == "backButton" && touchEventType == cocos2d::ui::Widget::TouchEventType::ENDED){ // _AniScenarioHandler->pauseScenario(); // _AniScenarioHandler->stopAllActions(); AniSoundsRepo::stopAllSounds(); cocos2d::Director::getInstance()->end(); _sceneDismissCallback(); return true; } /*else if(objectName == "backgroundMusicButton" && touchEventType == cocos2d::ui::Widget::TouchEventType::ENDED){ // auto bgMusicButton = dynamic_cast(_objects[objectName]); // if(this->isBackgroundMusicPlaying()){ // this->stopBackgroundMusic(true); // // if(bgMusicButton->isActive()){ // bgMusicButton->setActive(false); // } // // } else { // this->playBackgroundMusic(false); // // if(!bgMusicButton->isActive()){ // bgMusicButton->setActive(true); // } // } }*/ return false; } void AniParentScene::adjustBgMusicButton(bool bgMusicPlaying) { if(_objects.find("backgroundMusicButton") != _objects.end()){ auto bgMusicButton = dynamic_cast(_objects["backgroundMusicButton"]); if(bgMusicPlaying){ if(!bgMusicButton->isActive()){ bgMusicButton->setActive(true); } } else { if(bgMusicButton->isActive()){ bgMusicButton->setActive(false); } } } } void AniParentScene::disableButton(const std::string& buttonName) { auto object = this->getObjectByName(buttonName); auto button = dynamic_cast(object); if(button){ button->setEnabled(false); if(button->getOpacity() != 0){ button->setOpacity(128); for(auto child : button->getChildren()){ child->setOpacity(128); } } } } void AniParentScene::enableButton(const std::string& buttonName) { auto object = this->getObjectByName(buttonName); auto button = dynamic_cast(object); if(button){ button->setEnabled(true); button->setOpacity(255); for(auto child : button->getChildren()){ child->setOpacity(255); } } } // fast forward button convenience void AniParentScene::disableFastForwardButton() { this->disableButton("fastForwardButton"); } void AniParentScene::enableFastForwardButton() { this->enableButton("fastForwardButton"); } // touch handlers void AniParentScene::configureTouchHandlers() { auto touchListener = cocos2d::EventListenerTouchOneByOne::create(); touchListener->onTouchBegan = [&](cocos2d::Touch* touch, cocos2d::Event* event) -> bool{ _isHandlingTouches = true; for(auto handler : _touchBeganHandlers){ handler.second(touch, event); } _isHandlingTouches = false; this->filterTouchHandlers(); return true; }; touchListener->onTouchMoved = [&](cocos2d::Touch* touch, cocos2d::Event* event){ _isHandlingTouches = true; _lastUserTouchMovedTime = cocos2d::utils::getTimeInMilliseconds(); for(auto handler : _touchMovedHandlers){ handler.second(touch, event); } _isHandlingTouches = false; this->filterTouchHandlers(); }; touchListener->onTouchEnded = [&](cocos2d::Touch* touch, cocos2d::Event* event){ _isHandlingTouches = true; _lastUserTouchEndedTime = cocos2d::utils::getTimeInMilliseconds(); for(auto handler : _touchEndedHandlers){ handler.second(touch, event); } _isHandlingTouches = false; this->filterTouchHandlers(); }; _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this); } void AniParentScene::filterTouchHandlers() { for(auto pair : _touchHandlersToRemove){ this->removeTouchHandler(pair.first, pair.second); } _touchHandlersToRemove.clear(); } void AniParentScene::clearTouchHandlers() { _touchBeganHandlers.clear(); _touchMovedHandlers.clear(); _touchEndedHandlers.clear(); } void AniParentScene::addTouchHandler(std::string key, TouchHandlerFunction touchHandler, TouchHandlerType touchType) { auto handlersArray = this->pickTouchHandlersContainer(touchType); if(handlersArray){ handlersArray->insert({key, touchHandler}); } } void AniParentScene::removeTouchHandler(std::string touchHandlerKey, TouchHandlerType touchHandlerType) { if(!_isHandlingTouches){ auto handlersArray = this->pickTouchHandlersContainer(touchHandlerType); if(handlersArray){ handlersArray->erase(touchHandlerKey); } } else { _touchHandlersToRemove.insert({touchHandlerKey, touchHandlerType}); } } std::map* AniParentScene::pickTouchHandlersContainer(TouchHandlerType touchHandlerType) { std::map* handlersArray = NULL; switch(touchHandlerType){ case TouchHandlerType::TOUCHES_BEGAN: handlersArray = &_touchBeganHandlers; break; case TouchHandlerType::TOUCHES_MOVED: handlersArray = &_touchMovedHandlers; break; case TouchHandlerType::TOUCHES_ENDED: handlersArray = &_touchEndedHandlers; break; default: break; } return handlersArray; } long long AniParentScene::getLastScreenTouchTime() { if(_lastUserTouchEndedTime != -1 && _lastUserTouchMovedTime != -1){ return MAX(_lastUserTouchEndedTime, _lastUserTouchMovedTime); } else { return _lastUserTouchMovedTime; // if moved is null, ended must be null as well } } void AniParentScene::resetLastUserTouchTimes() { _lastUserTouchEndedTime = -1; _lastUserTouchMovedTime = -1; } void AniParentScene::setAlwaysSkipDemo(bool alwaysSkipDemo) { _alwaysSkipDemo = alwaysSkipDemo; } // layout parse delegate void AniParentScene::addLayer(cocos2d::Layer* layer) { _layers.push_back(layer); } void AniParentScene::addObject(std::string objectName, cocos2d::Node* object) { _objects.insert({objectName, object}); } void AniParentScene::addAniScenarioObject(std::string objectName, AniScenarioObject* object) { _AniScenarioObjects.insert({objectName, object}); } // AniScenarioObject void AniParentScene::setProperty(std::string propertyName, const rapidjson::Value& newValue, ActionParseDelegate* parseDelegate) { static std::string demoState = "demoState"; static std::string userTaskInteractionStarted = "userTaskInteractionStarted"; static std::string currentTask = "currentTask"; static std::string rightObjectTouchedAlready = "rightObjectTouchedAlready"; if (propertyName == demoState) { // _AniScenarioHandler->setProperty(propertyName, newValue, parseDelegate); } else if(propertyName == userTaskInteractionStarted){ _userTaskInteractionStarted = newValue.GetBool(); } else if(propertyName.find(userTaskInteractionStarted) == 0){ std::string additionalName = propertyName.substr(userTaskInteractionStarted.size()); _userTaskInteractionStartedMap[additionalName] = newValue.GetBool(); } else if(propertyName == currentTask){ _currentTask = newValue.GetString(); } else if(propertyName == rightObjectTouchedAlready){ _rightObjectTouchedAlready = newValue.GetBool(); } } void AniParentScene::callFunctionByName(std::string methodName, const rapidjson::Value* arguments, ActionParseDelegate* parseDelegate, std::function callback) { if(methodName == "disableFastForwardButton"){ this->disableFastForwardButton(); } else if(methodName == "clearTouchHandlers"){ this->clearTouchHandlers(); } } std::string AniParentScene::getPropertyAsString(std::string propertyName) { static std::string userTaskInteractionStarted = "userTaskInteractionStarted"; if(propertyName == userTaskInteractionStarted){ return _userTaskInteractionStarted ? "true" : "false"; } else if(propertyName.find(userTaskInteractionStarted) != std::string::npos){ auto tokens = AniStringUtils::splitString(propertyName, userTaskInteractionStarted); if(tokens.size() > 0){ auto key = tokens[tokens.size()-1]; if(_userTaskInteractionStartedMap.find(key) != _userTaskInteractionStartedMap.end()){ return _userTaskInteractionStartedMap.at(key) ? "true" : "false"; } } } else if(propertyName == "rightObjectTouchedAlready"){ return _rightObjectTouchedAlready ? "true" : "false"; } return "NULL"; } void AniParentScene::addNewNodeToObjectLayer(cocos2d::Node* newNode){ if(_layers.size() > 0){ _layers[_layers.size()-1]->addChild(newNode); } } void AniParentScene::showTOSAcceptPopup(std::function onAccept){ if(AniMiscUtils::wasTOSAccepted()){ // gameState->tosAcceptMenuShown = false; onAccept(); } else { // gameState->tosAcceptMenuShown = true; auto tosPopup = AniTOSAcceptPopupView::create(std::bind([&](std::functionf){ AniMiscUtils::saveTOSAccepted(); // gameState->tosAcceptMenuShown = false; f();}, onAccept)); addTouchBlockingLayer(tosPopup); tosPopup->setLocalZOrder(500); #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) auto keyboardListener = cocos2d::EventListenerKeyboard::create(); keyboardListener->onKeyReleased = std::bind([&](cocos2d::EventKeyboard::KeyCode keyCode, cocos2d::Event* event, AniTOSAcceptPopupView* n){ if(keyCode == cocos2d::EventKeyboard::KeyCode::KEY_BACK){ if(AniMiscUtils::isNodeVisible(n)){ if (n->isShowingParentalGate()) { n->hideParentalGate(); } else { cocos2d::Director::getInstance()->end(); //auto scene = HelloWorld::createScene(); //cocos2d::Director::getInstance()->replaceScene(scene); } } } }, std::placeholders::_1, std::placeholders::_2, tosPopup); _eventDispatcher->addEventListenerWithSceneGraphPriority(keyboardListener, tosPopup); #endif } } void AniParentScene::showAniLevelPickerLayer(std::function onLayerDismissed, std::function onLevelChanged) { isShowingLevelPicker = true; auto AniLevelPickerLayer = AniLevelPickerLayer::create(getBoundingBox().size.width, getBoundingBox().size.height); addTouchBlockingLayer(AniLevelPickerLayer); AniLevelPickerLayer->setLocalZOrder(400); AniLevelPickerLayer->addOnGoPressedCallback(onLayerDismissed); AniLevelPickerLayer->setOnLevelChangedCallback(onLevelChanged); #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) auto keyboardListener = cocos2d::EventListenerKeyboard::create(); keyboardListener->onKeyReleased = std::bind( [&](cocos2d::EventKeyboard::KeyCode keyCode, cocos2d::Event *event, cocos2d::Node *n) { if (keyCode == cocos2d::EventKeyboard::KeyCode::KEY_BACK) { if (AniMiscUtils::isNodeVisible(n)) { cocos2d::Director::getInstance()->end(); // auto scene = HelloWorld::createScene(); // cocos2d::Director::getInstance()->replaceScene(scene); } } }, std::placeholders::_1, std::placeholders::_2, AniLevelPickerLayer); _eventDispatcher->addEventListenerWithSceneGraphPriority(keyboardListener, AniLevelPickerLayer); #endif } void AniParentScene::addTouchBlockingLayer(cocos2d::Node* layer){ addChild(layer); auto touchListener = cocos2d::EventListenerTouchOneByOne::create(); touchListener->setSwallowTouches(true); touchListener->onTouchBegan = std::bind([&](cocos2d::Touch* touch, cocos2d::Event* event, cocos2d::Node* n){ return AniMiscUtils::isNodeVisible(n); }, std::placeholders::_1, std::placeholders::_2, layer); _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, layer); } void AniParentScene::repeatPickLevelPrompt(){ static int DelaySecs = 15; runAction(cocos2d::Sequence::create(cocos2d::DelayTime::create(DelaySecs), cocos2d::CallFunc::create([&](){ if(isShowingLevelPicker){ AniSoundsRepo::playSound(AniSoundsRepo::pickLevelSound().filePath); repeatPickLevelPrompt(); } }), nullptr)); }