// // ParentScene.cpp // SteveMaggieCpp // // Created by Katarzyna Kalinowska-Górska on 16.05.2017. // // #include #include "ParentScene.h" #include "LayoutParser.h" #include "SimpleButton.h" #include "TwoStateButton.h" #include "MathUtils.h" #include "StringUtils.h" #include "ResourceUtilities.h" #include "MiscUtils.h" #include "TOSAcceptPopupView.h" #include "LevelPickerLayer.h" #include "SoundsRepo.h" #include "HelloWorldScene.h" ParentScene* ParentScene::create(std::string layoutFilePath, std::string scenarioFilePath) { ParentScene * scene = new (std::nothrow) ParentScene(); if(scene && scene->initWithConfigurationFiles(layoutFilePath, scenarioFilePath)) { scene->autorelease(); return scene; } CC_SAFE_DELETE(scene); return nullptr; } bool ParentScene::initWithConfigurationFiles(std::string layoutFilePath, std::string scenarioFilePath) { if(!SceneWithUtils::init()) { return false; } _layoutFilePath = layoutFilePath; _scenarioFilePath = scenarioFilePath; _loadFromAssets = false; _layers.clear(); _objects.clear(); _alwaysSkipDemo = false; _layoutLoaded = false; // _scenarioHandler = new ScenarioHandler(this); // _scenarioObjects.insert({"scenarioHandler", _scenarioHandler}); _userTaskInteractionStarted = false; _currentTask = ""; _rightObjectTouchedAlready = false; //TODO these should probably be in the WorksheetScene _isHandlingTouches = false; this->clearTouchHandlers(); this->resetLastUserTouchTimes(); return true; } void ParentScene::reloadLayoutClean() { this->removeAllChildren(); _layers.clear(); _objects.clear(); _scenarioObjects.clear(); // _scenarioObjects.insert({"scenarioHandler", _scenarioHandler}); _userTaskInteractionStarted = false; _currentTask = ""; _rightObjectTouchedAlready = false; //TODO these should probably be in the WorksheetScene _isHandlingTouches = false; this->clearTouchHandlers(); this->resetLastUserTouchTimes(); this->loadLayout(true); } void ParentScene::loadLayout(bool forceLoad) { if(!this->_layoutLoaded || forceLoad){ _layoutLoaded = false; if (_loadFromAssets && cocos2d::FileUtils::getInstance()->isFileExist(this->_layoutFilePath)) { auto& layoutParser = LayoutParser::getInstance(); layoutParser.loadLayoutFromJSONFile(this->_layoutFilePath, this); this->_layoutLoaded = true; } else if(!_loadFromAssets){ auto& layoutParser = LayoutParser::getInstance(); layoutParser.loadLayoutFromDownloadedJSONFile(this->_layoutFilePath, this); this->_layoutLoaded = true; } } } void ParentScene::loadScenario(bool skipDemoActions) { // auto fileUtils = cocos2d::FileUtils::getInstance(); // if (fileUtils->isFileExist(this->_scenarioFilePath)) { // std::string jsonString = fileUtils->getStringFromFile(this->_scenarioFilePath); // _scenarioHandler->loadScenarioFromJSONString(jsonString, skipDemoActions); // } } void ParentScene::setLoadFromAssets(bool loadFromAssets) { _loadFromAssets = loadFromAssets; } // overrides void ParentScene::onEnter() { this->configureTouchHandlers(); this->configureTransitionListeners(); SceneWithUtils::onEnter(); // auto playing = this->playBackgroundMusic(true); // this->adjustBgMusicButton(playing); } void ParentScene::onExit() { SceneWithUtils::onExit(); // if(_scenarioHandler){ // _scenarioHandler->end(); //// delete _scenarioHandler; //TODO do it somewhere when the scene gets dealloced // } // this->stopBackgroundMusic(false); } void ParentScene::configureTransitionListeners() //TODO check if it works. remove somewhere later the vent listeners? leaks? { _eventDispatcher->addCustomEventListener("game_on_hide", CC_CALLBACK_1(ParentScene::onGameHide, this)); _eventDispatcher->addCustomEventListener("game_on_show", CC_CALLBACK_1(ParentScene::onGameShow, this)); } void ParentScene::onGameHide(cocos2d::EventCustom* event) { // _scenarioHandler->pauseScenario(); } void ParentScene::onGameShow(cocos2d::EventCustom* event) { // _scenarioHandler->resumeScenario(); } // object config & handlers ScenarioObject* ParentScene::getObjectByName(std::string objectName) { if(_objects.find(objectName) == _objects.end()){ if(_scenarioObjects.find(objectName) == _scenarioObjects.end()){ return NULL; } return _scenarioObjects.at(objectName); } return dynamic_cast(_objects.at(objectName)); } void ParentScene::addNewObject(std::string objectName, ScenarioObject* newObject) { _scenarioObjects.insert({objectName, newObject}); } void ParentScene::setupBackgroundMusic(std::string backgroundMusicPath) { _backgroundMusicFilePath = backgroundMusicPath; } bool ParentScene::touchHandlerForWidget(std::string objectName, cocos2d::ui::Widget::TouchEventType touchEventType) { if(objectName == "backButton" && touchEventType == cocos2d::ui::Widget::TouchEventType::ENDED){ // _scenarioHandler->pauseScenario(); // _scenarioHandler->stopAllActions(); SoundsRepo::stopAllSounds(); cocos2d::Director::getInstance()->popScene(); _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 ParentScene::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 ParentScene::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 ParentScene::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 ParentScene::disableFastForwardButton() { this->disableButton("fastForwardButton"); } void ParentScene::enableFastForwardButton() { this->enableButton("fastForwardButton"); } // touch handlers void ParentScene::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 ParentScene::filterTouchHandlers() { for(auto pair : _touchHandlersToRemove){ this->removeTouchHandler(pair.first, pair.second); } _touchHandlersToRemove.clear(); } void ParentScene::clearTouchHandlers() { _touchBeganHandlers.clear(); _touchMovedHandlers.clear(); _touchEndedHandlers.clear(); } void ParentScene::addTouchHandler(std::string key, TouchHandlerFunction touchHandler, TouchHandlerType touchType) { auto handlersArray = this->pickTouchHandlersContainer(touchType); if(handlersArray){ handlersArray->insert({key, touchHandler}); } } void ParentScene::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* ParentScene::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 ParentScene::getLastScreenTouchTime() { if(_lastUserTouchEndedTime != -1 && _lastUserTouchMovedTime != -1){ return MAX(_lastUserTouchEndedTime, _lastUserTouchMovedTime); } else { return _lastUserTouchMovedTime; // if moved is null, ended must be null as well } } void ParentScene::resetLastUserTouchTimes() { _lastUserTouchEndedTime = -1; _lastUserTouchMovedTime = -1; } void ParentScene::setAlwaysSkipDemo(bool alwaysSkipDemo) { _alwaysSkipDemo = alwaysSkipDemo; } // layout parse delegate void ParentScene::addLayer(cocos2d::Layer* layer) { _layers.push_back(layer); } void ParentScene::addObject(std::string objectName, cocos2d::Node* object) { _objects.insert({objectName, object}); } void ParentScene::addScenarioObject(std::string objectName, ScenarioObject* object) { _scenarioObjects.insert({objectName, object}); } // ScenarioObject void ParentScene::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) { // _scenarioHandler->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 ParentScene::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 ParentScene::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 = StringUtils::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 ParentScene::addNewNodeToObjectLayer(cocos2d::Node* newNode){ if(_layers.size() > 0){ _layers[_layers.size()-1]->addChild(newNode); } } void ParentScene::showTOSAcceptPopup(std::function onAccept){ if(MiscUtils::wasTOSAccepted()){ // gameState->tosAcceptMenuShown = false; onAccept(); } else { // gameState->tosAcceptMenuShown = true; auto tosPopup = TOSAcceptPopupView::create(std::bind([&](std::functionf){ MiscUtils::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, TOSAcceptPopupView* n){ if(keyCode == cocos2d::EventKeyboard::KeyCode::KEY_BACK){ if(MiscUtils::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 ParentScene::showLevelPickerLayer(std::function onLayerDismissed, std::function onLevelChanged) { isShowingLevelPicker = true; auto levelPickerLayer = LevelPickerLayer::create(getBoundingBox().size.width, getBoundingBox().size.height); addTouchBlockingLayer(levelPickerLayer); levelPickerLayer->setLocalZOrder(400); levelPickerLayer->addOnGoPressedCallback(onLayerDismissed); levelPickerLayer->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 (MiscUtils::isNodeVisible(n)) { cocos2d::Director::getInstance()->end(); //auto scene = HelloWorld::createScene(); //cocos2d::Director::getInstance()->replaceScene(scene); } } }, std::placeholders::_1, std::placeholders::_2, levelPickerLayer); _eventDispatcher->addEventListenerWithSceneGraphPriority(keyboardListener, levelPickerLayer); #endif } void ParentScene::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 MiscUtils::isNodeVisible(n); }, std::placeholders::_1, std::placeholders::_2, layer); _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, layer); } void ParentScene::repeatPickLevelPrompt(){ static int DelaySecs = 15; runAction(cocos2d::Sequence::create(cocos2d::DelayTime::create(DelaySecs), cocos2d::CallFunc::create([&](){ if(isShowingLevelPicker){ SoundsRepo::playSound(SoundsRepo::pickLevelSound().filePath); repeatPickLevelPrompt(); } }), nullptr)); }