// // AniAdventureScene.cpp // SteveMaggieCpp // // Created by Katarzyna Kalinowska-Górska on 18.06.2017. // // #include #include "AniAdventureScene.h" #include "AniAlertUtils.h" #include "MapAdventureObjectPickupItem.h" #include "AniDefaultMapControlCoordinator.h" #include "AniTouchRecognizerMapControl.h" #include "AniSoundsRepo.h" #include "AniMathUtils.h" #include "BasicGardenMapAdventureObjectMapper.h" #include "AniPlainLabel.h" #include "AniEndScene.h" #include "AniGeometryUtils.h" #include "AniSimpleButton.h" #include "AniTwoStateButton.h" AniAdventureScene* AniAdventureScene::create(int pGameId, std::string layoutFilePath, std::function gameConfigParser) { AniAdventureScene * scene = new (std::nothrow) AniAdventureScene(); if(scene && scene->initWithConfiguration(pGameId, layoutFilePath, gameConfigParser)) { scene->autorelease(); return scene; } CC_SAFE_DELETE(scene); return nullptr; } bool AniAdventureScene::initWithConfiguration(int pGameId,std::string layoutFilePath, std::function gameConfigParse){ if(!AniSubGameScene::initWithConfiguration(layoutFilePath)){ return false; } gameConfigParse(gameConfig); clearGameState(); return true; } AniAdventureScene::~AniAdventureScene() { } //!!! MAKE IT RESISTANT TO REENTERING - home button etc void AniAdventureScene::onEnter() { AniSubGameScene::onEnter(); initAfterLayoutLoad(); spawnSteveAndStartGame(); cocos2d::Device::setKeepScreenOn(true); } void AniAdventureScene::prepareBgMusicButton(){ auto bgMusicButton = dynamic_cast(_objects["backgroundMusicButton"]); bgMusicButton->setActive(AniMiscUtils::shouldBgMusicPlay()); bgMusicButton->setVisible(false); bgMusicButton->setOpacity(0); bgMusicButton->removeFromParent(); addChild(bgMusicButton); bgMusicButton->setLocalZOrder(240); } void AniAdventureScene::shuffleObjectsIfRequired(){ std::vector excludedItems; if(!tutorialComplete()){ excludedItems.push_back(tut_firstItemToFind()); } if(m_gardenMapController != nullptr){ auto level = AniMiscUtils::lastLevel(); if(level == AniMiscUtils::Level::TEEN){ m_gardenMapController->shuffleAllPickupMapAdventureObjects(excludedItems); } else if(level == AniMiscUtils::Level::ADULT){ m_gardenMapController->distributeAllPickupMapAdventureObjectsRandomly(excludedItems); } if(!tutorialComplete()){ m_gardenMapController->deactivateAllObjects(); m_gardenMapController->hideAllObjects(excludedItems); } } } void AniAdventureScene::stopAnimatingStars(){ for(auto it = m_stars.begin(); it != m_stars.end(); ++it){ auto starSprite = (*it)->getAssociatedMapImageObjects().begin()->second; starSprite->stopAllActions(); } } void AniAdventureScene::animateStars(){ for(auto it = m_stars.begin(); it != m_stars.end(); ++it){ auto starSprite = (*it)->getAssociatedMapImageObjects().begin()->second; auto moveVec = cocos2d::Vec2(0, starSprite->getBoundingBox().size.height); // auto delay = MathUtils::getRandom(0, 0.3f); starSprite->runAction(cocos2d::RepeatForever::create(cocos2d::Sequence::create(cocos2d::EaseInOut::create(cocos2d::MoveBy::create(0.6f, moveVec), 1.2), cocos2d::EaseInOut::create(cocos2d::MoveBy::create(0.6f, -moveVec), 1.2), nullptr))); } } // //void AniAdventureScene::setRandomizeSpawnTile(bool randomize) //{ // //} void AniAdventureScene::initAfterLayoutLoad(){ auto steveButton = dynamic_cast(_objects["steveButton"]); steveButton->setEnabled(false); AniMiscUtils::hideView(steveButton, false); prepareBgMusicButton(); disableButton("replayButton"); if(AniMiscUtils::lastLevel() != AniMiscUtils::Level::CHILD){ m_progressSliderNode = static_cast(_objects["timeSlider"]); m_progressSliderNode->setContentSize(m_progressSliderNode->getParent()->getContentSize()); if(!tutorialComplete()){ m_progressSliderNode->getParent()->setVisible(false); } } if(!tutorialComplete()){ _objects["pauseButton"]->setVisible(false); } _mapLayer = dynamic_cast(_objects["mapLayer"]); if(_mapLayer){ _mapLayer->setAniMapLayerDelegate(this); _mapLayer->setup(this); if(tutorialComplete()){ _mapLayer->setChooseRandomSpawnTile(true); } else { _mapLayer->setSpawnTile(6, 9); //todo maybe an external json file with all the tutorial data ? } shuffleObjectsIfRequired(); } } void AniAdventureScene::spawnSteveAndStartGame(){ gameState->currentLevel = (int)AniMiscUtils::lastLevel(); _mapLayer->spawnCharacters(); } void AniAdventureScene::startGame(bool playIntro){ gameState->playState = PlayState::PRE_PLAYING; m_mainMapControl->setEnabled(false); if(playIntro){ // SoundsRepo::turnDownMusic(); runAction(cocos2d::Sequence::create(cocos2d::CallFunc::create([&](){ AniSoundsRepo::playSound(AniSoundsRepo::MAP_GAME_SOUND_INTRO); //TODO FIXED TIME BAD BAD BAD sounds.info todo m_characterController->steveLookAround(); }), cocos2d::DelayTime::create(9), cocos2d::CallFunc::create([&](){ disableFastForwardButton(); startGame(false); // SoundsRepo::turnUpMusic(); }), nullptr)); } else { // presentEndScene(5); // return; m_characterController->steveReadyForAdventure(); m_mainMapControl->setEnabled(true); auto level = AniMiscUtils::lastLevel(); gameState->playState = PlayState::PLAYING; nextItem(); if(level != AniMiscUtils::Level::CHILD){ startTimer(); } _mapLayer->scheduleUpdate(); _mapLayer->installMapControl(m_mainMapControl); scheduleOnce([&](float){ // cocos2d::log("music loaded: %d\n", SoundsRepo::musicPreloaded); if(AniMiscUtils::shouldBgMusicPlay() && !AniSoundsRepo::isMusicPlaying()){ playBackgroundMusic(false); } }, 1,"playMusic"); } } void AniAdventureScene::startTutorial(){ m_tutorialRunning = true; m_characterController->getCharacter()->setTimeToGetBored(__INT_MAX__); _mapLayer->installMapControl(m_tutorialMapControl); m_tutorialMapControl->startTutorial(); } void AniAdventureScene::pauseGame(){ _mapLayer->unscheduleUpdate(); _mapLayer->pause(); m_steve->pause(); AniSoundsRepo::pauseAllSounds(); pause(); if(m_progressSliderNode != nullptr){ m_progressSliderNode->pause(); } } void AniAdventureScene::resumeGame(){ if(gameState->playState == AniSubGameScene::PlayState::PLAYING) { auto currentSoundPath = currentItem().soundRequest; AniSoundsRepo::playSound(currentSoundPath); } _mapLayer->scheduleUpdate(); _mapLayer->resume(); m_steve->resume(); resume(); AniSoundsRepo::resumeAllSounds(); if(m_progressSliderNode != nullptr){ m_progressSliderNode->resume(); } } void AniAdventureScene::hideSettingsMenuWithLevelReset(){ auto newLevel = (int)(AniMiscUtils::lastLevel()); if(newLevel != gameState->currentLevel){ stopAllActions(); unscheduleAllCallbacks(); resume(); scheduleOnce([&](float){ resetGame(); }, 0.24f, "lvlReset"); } else { m_replayingTutorial = false; m_shouldDisplayHintForLogLadder = false; hideSettingsMenu(true); resumeGame(); } } void AniAdventureScene::hideSettingsMenuWithTutorialReset(){ m_replayingTutorial = true; m_shouldDisplayHintForLogLadder = true; hideSettingsMenu(true); resetGame(); } void AniAdventureScene::clearGameState(){ AniMapUtils::getInstance().clearMap(); gameState->playState = AniSubGameScene::PlayState::INIT; gameState->currentLevel = (int)AniMiscUtils::lastLevel(); advGameState.score = 0; m_stars.clear(); advGameState.alreadyCollectedWrongObjects.clear(); advGameState.itemsOrder.clear(); auto itemsCount = gameConfig.items.size(); for(int i = 0; i < itemsCount; ++i){ advGameState.itemsOrder.push_back(i); } AniMathUtils::shuffleArray(advGameState.itemsOrder); if(!tutorialComplete()){ //a bit unelegant.. but won't happen a lot and the arrays are very small. int firstItemIndex = 0; for(int i = 0; i < gameConfig.items.size(); ++i){ if(gameConfig.items[i].mapAdvObjectName == tut_firstItemToFind()){ firstItemIndex = i; break; } } if(!(advGameState.itemsOrder[0] == firstItemIndex)){ int indexForTheOtherItem = 0; for(int i = 1; i < advGameState.itemsOrder.size(); ++i){ if(advGameState.itemsOrder[i] == firstItemIndex){ advGameState.itemsOrder[i] = advGameState.itemsOrder[0]; advGameState.itemsOrder[0] = firstItemIndex; break; } } } } advGameState.currentItem = -1; if(m_characterController != nullptr){ m_characterController->enableCharacter(); m_characterController->setDefaultCharacterPosture(); } stopTimer(); auto scoreLabel = dynamic_cast(_objects["scoreLabel"]); if(scoreLabel){ scoreLabel->setString("0"); } if(m_progressSliderNode != nullptr){ m_progressSliderNode->setProgress(0); } if(m_gardenMapController != nullptr){ m_gardenMapController->reset(); } shuffleObjectsIfRequired(); } void AniAdventureScene::resetGame(){ gameCreator.preloadGameResources([&](std::vector){ auto scene = dynamic_cast(gameCreator.createGameScene()); if(m_replayingTutorial){ scene->markShouldReplayTutorial(); } cocos2d::Director::getInstance()->replaceScene(scene); }); // cocos2d::Director::getInstance()->replaceScene(GameStaticCreator::createGameScene()); // todo: mapLayer setup must not be called twice. old map controller remains and blocked tiles remain -> when we switch from medium level to baby level, we'll get blocked tiles // stopAllActions(); // clearGameState(); // _layoutFilePath = layoutFileForCurrentLevel(); // reloadLayoutClean(); // initAfterLayoutLoad(); // spawnSteveAndStartGame(); } void AniAdventureScene::nextItem(){ if(advGameState.currentItem == advGameState.itemsOrder.size() - 1){ gameWon(); AniMiscUtils::hideView(_objects["pauseButton"], true); stopTimer(); stopAllActions(); unscheduleAllCallbacks(); m_characterController->disableSteveHappy(); // SoundsRepo::turnDownMusic(); AniSoundsRepo::playSound(AniSoundsRepo::MAP_GAME_SOUND_ALL_DONE); scheduleOnce(CC_SCHEDULE_SELECTOR(AniAdventureScene::presentEndScene), 7.6f); } else { if(m_stars.empty()){ m_stars = m_gardenMapController->generatePickupObjectsRandomly(5, "star", "graphics/star.png", true); for(auto it = m_stars.begin(); it != m_stars.end(); ++it){ auto imageObject = (*it)->getAssociatedMapImageObjects().begin()->second; imageObject->setAlwaysOnTop(true); imageObject->setLocalZOrder(m_gardenMapController->getMaxObjectDepth() + 8); //TODO steve falling has +10, de-magic!!!! } animateStars(); m_characterController->adjustCharacterDepth(); } else { stopAnimatingStars(); m_gardenMapController->distributeConcretePickupMapAdventureObjectsRandomly(m_stars); animateStars(); } advGameState.alreadyCollectedWrongObjects.clear(); m_gardenMapController->activateConcreteObjects(m_stars); m_gardenMapController->showConcreteObjects(m_stars); ++advGameState.currentItem; auto item = currentItem(); auto currentSoundPath = item.soundRequest; // SoundsRepo::turnDownMusic(); AniSoundsRepo::playSound(currentSoundPath); gameState->playState = PlayState::PLAYING; } } // timer void AniAdventureScene::startTimer(){ if(m_progressSliderNode != nullptr){ advGameState.currentTimeSeconds = gameConfig.levelConfigs[(int)AniMiscUtils::lastLevel()].levelTime; m_progressSliderNode->startTimeAnimation(advGameState.currentTimeSeconds); this->schedule(CC_SCHEDULE_SELECTOR(AniAdventureScene::onSecondElapsed), 1, CC_REPEAT_FOREVER, 0); } } void AniAdventureScene::onSecondElapsed(float dt){ --advGameState.currentTimeSeconds; if(advGameState.currentTimeSeconds <= 0){ stopTimer(); gameLost(); AniSoundsRepo::playSound(currentItem().soundTooLate); } } void AniAdventureScene::stopTimer(){ if(m_progressSliderNode){ m_progressSliderNode->stopTimeAnimation(); } unschedule(CC_SCHEDULE_SELECTOR(AniAdventureScene::onSecondElapsed)); } void AniAdventureScene::gameLost(){ AniSubGameScene::gameLost(); AniMiscUtils::hideView(_objects["pauseButton"], true); m_characterController->disableSteveDisappointed(); _mapLayer->stopAllActions(); _mapLayer->unscheduleUpdate(); _mapLayer->unscheduleAllCallbacks(); // TODO maybe all the controllers?? maybe override these methods and send them down to all the controllers, like in the update method? stopAllActions(); unscheduleAllCallbacks(); AniSoundsRepo::stopAllSounds(); scheduleOnce(CC_SCHEDULE_SELECTOR(AniAdventureScene::presentEndScene), 7.4f); } void AniAdventureScene::increaseScore(int by, bool animated){ advGameState.score += by; //TODO WHY IS _OBJECTS[SCORELABEL] NULL?!?!?! set brkpoint in autorelease auto children = _objects["starCollector"]->getChildren(); for(int i =0; i < children.size(); ++i){ auto l = dynamic_cast(children.at(i)); if(l){ l->setString(std::to_string(advGameState.score)); } } // dynamic_cast(_objects["scoreLabel"])->setString(std::to_string(advGameState.score)); } void AniAdventureScene::decreaseScore(int by, bool animated){ advGameState.score = std::max(advGameState.score - by, 0); // dynamic_cast(_objects["scoreLabel"])->setString(std::to_string(advGameState.score)); auto children = _objects["starCollector"]->getChildren(); for(int i =0; i < children.size(); ++i){ auto l = dynamic_cast(children.at(i)); if(l){ l->setString(std::to_string(advGameState.score)); } } } bool AniAdventureScene::onFastForwardButtonClicked() { if(m_tutorialRunning){ AniAlertUtils::showTwoButtonDialog(1000, "Do you want to skip the tutorial?", "Yep, I already know my way around.", "No, let's complete it!", [this](){ m_tutorialMapControl->forceFinishTutorial(); }); } else { disableButton("fastForwardButton"); stopAllActions(); AniSoundsRepo::stopAllSounds(); unscheduleAllCallbacks(); shouldPlayIntro = false; if(!_mapLayer->fastForwardCharacterFall()){ startGame(false); } } return true; // m_characterController->getCharacter()->stopAllActions(); // return SubGameScene::onFastForwardButtonClicked(); } static constexpr char* TUTORIAL_COMPLETE_KEY {"TUTORIAL_COMPLETE_KEY"}; static constexpr char* LOG_LADDER_TUTORIAL_COMPLETE_KEY {"LOG_LADDER_TUTORIAL_COMPLETE_KEY"}; bool AniAdventureScene::tutorialComplete(){ return !m_replayingTutorial && cocos2d::UserDefault::getInstance()->getBoolForKey(TUTORIAL_COMPLETE_KEY, false); } void AniAdventureScene::saveTutorialComplete(){ cocos2d::UserDefault::getInstance()->setBoolForKey(TUTORIAL_COMPLETE_KEY, true); cocos2d::UserDefault::getInstance()->flush(); } bool AniAdventureScene::logLadderTutorialComplete(){ // return false; return !m_replayingTutorial && cocos2d::UserDefault::getInstance()->getBoolForKey(LOG_LADDER_TUTORIAL_COMPLETE_KEY, false); } void AniAdventureScene::saveLogLadderTutorialComplete(){ cocos2d::UserDefault::getInstance()->setBoolForKey(LOG_LADDER_TUTORIAL_COMPLETE_KEY, true); cocos2d::UserDefault::getInstance()->flush(); } // // map layer delegate // virtual initializers IMapControl* AniAdventureScene::initAllocMapControl() { if(tutorialComplete()){ m_mainMapControl = new AniTouchRecognizerMapControl(); m_mainMapControl->setEnabled(false); return m_mainMapControl; } else { m_tutorialMapControl = new AniTutorialMapControl(this, this); return m_tutorialMapControl; } } IMapControlCoordinator* AniAdventureScene::initAllocMapControlCoordinator(){ return new AniDefaultMapControlCoordinator(); } IMapAdventureObjectMapper* AniAdventureScene::initAllocAdventureObjectMapper() { return new BasicGardenMapAdventureObjectMapper(); } std::vector AniAdventureScene::createAutoreleasedMapCharacters(){ m_steve = AniSteveCharacter::create(this); m_steve->setTimeToGetBored(__INT_MAX__); return std::vector{ m_steve }; } // controller at [i] corresponds to a character at [i] std::vector AniAdventureScene::initAllocMapCharacterControllers(){ m_characterController = new AniBasicSteveMapCharacterController(); m_characterController->setDelegate(this); return std::vector{ m_characterController }; } IMapController* AniAdventureScene::initAllocMapController(cocos2d::TMXTiledMap* p_map, IMapAdventureObjectMapper* p_mapper){ m_gardenMapController = new AniGardenMapController(p_map, p_mapper); m_gardenMapController->setOnZoomModeEnteredCallback([&](){ if(!m_tutorialRunning){ showZoomButton(); } }); return m_gardenMapController; } void AniAdventureScene::showZoomButton(){ cancelMovingHintFinger(); auto button = dynamic_cast(_objects["steveButton"]); button->setEnabled(true); AniMiscUtils::showView(button, true); auto basket = _objects["starCollector"]; AniMiscUtils::hideView(basket, true); // automatically revert if it's only a little - probably by mistake if(!m_tutorialRunning){ scheduleOnce([&](float){ if(_mapLayer->getScale() > 0.9f){ cancelZoomMode(); } }, 1, "autoCancelZoomMode"); // display hint finger scheduleOnce([&](float){ if(m_finger == nullptr){ m_finger = cocos2d::Sprite::create("graphics/tutorials/graphics/finger_one.png"); m_finger->setAnchorPoint(cocos2d::Vec2(0.25, 0.9)); addChild(m_finger); } else { m_finger->stopAllActions(); } AniMiscUtils::showView(m_finger, false); m_finger->setRotation(20); auto buttonBB = _objects["steveButton"]->getBoundingBox(); m_finger->setPosition(cocos2d::Vec2(buttonBB.getMidX(), buttonBB.getMidY())); m_finger->runAction(cocos2d::RepeatForever::create(cocos2d::Blink::create(10, 10))); }, 5, "cancelZoomModeHint"); } } void AniAdventureScene::onMapAdventureObjectEvent(IMapAdventureObject* p_object, IMapAdventureObjectEvent* event) { // if(event->eventType == IMapAdventureObjectEventTypeItemPickedUp){ // printf("item picked up!!! %s \n", p_object->getObjectName().c_str()); // } } void AniAdventureScene::onCharacterFinishedIntroFalling(IMapCharacter* character) { if(gameState->playState == PlayState::INIT){ //fast forward button might have triggered game start while steve was falling if(tutorialComplete()){ startGame(shouldPlayIntro); //TODO handle intro or not intro? } else { startTutorial(); } } } // character controller delegate bool AniAdventureScene::isRightPickUpItem(MapAdventureObjectPickupItem* item){ // return true; return item->getObjectName() == currentItem().mapAdvObjectName; } bool AniAdventureScene::isBonusPickUpItem(MapAdventureObjectPickupItem* item){ return std::find(m_stars.begin(), m_stars.end(), item) != m_stars.end(); } bool AniAdventureScene::shouldApproachItem(IMapAdventureObject* item, AniMapUtils::TileData touchedTile){ auto pickupItem = dynamic_cast(item); if(pickupItem == nullptr){ //always approach other adv objects return true; } if( isRightPickUpItem(pickupItem) || isBonusPickUpItem(pickupItem)){ return true; // always approach right and bonus pickup items } else { // if wrong item, put more restriction on collecting and ignore if it was the last object if (std::find(advGameState.alreadyCollectedWrongObjects.begin(), advGameState.alreadyCollectedWrongObjects.end(), item->getObjectName()) != advGameState.alreadyCollectedWrongObjects.end()){ return false; } auto tiles = pickupItem->getOccupiedTilesRestrictedByIntersectionPercent(0.5f); //TODO de-magic, naming convention wrong, they are not percent return std::find(tiles.begin(), tiles.end(), touchedTile) != tiles.end(); } return true; } void AniAdventureScene::onRightItemPickedUp(MapAdventureObjectPickupItem* item){ gameState->playState = PlayState::CHANGING_LEVEL; auto scoreBonus = 3; // increaseScore(scoreBonus); AniSoundsRepo::playSound(currentItem().soundConf); AniSoundsRepo::playSound(AniSoundsRepo::rightItemEffectSound().filePath, false); auto sprite = item->getAssociatedMapImageObjects().begin()->second; auto itemPositionToWorld = sprite->getParent()->convertToWorldSpace(sprite->getPosition()); multipleStarAnimation(itemPositionToWorld, scoreBonus); // TODO need this sound's duration! runAction(cocos2d::Sequence::create(cocos2d::DelayTime::create(5.5), cocos2d::CallFunc::create([&](){ nextItem(); }), NULL)); } void AniAdventureScene::onWrongItemPickUpTry(MapAdventureObjectPickupItem* item){ if (std::find(advGameState.alreadyCollectedWrongObjects.begin(), advGameState.alreadyCollectedWrongObjects.end(), item->getObjectName()) == advGameState.alreadyCollectedWrongObjects.end()){ basketShakeAnimation(); decreaseScore(1); advGameState.alreadyCollectedWrongObjects.push_back(item->getObjectName()); } static float AngryDuration = 2.f; m_steve->getAngry(AngryDuration); AniSoundsRepo::playSound(currentItem().soundNo, true); AniSoundsRepo::playSound(AniSoundsRepo::wrongItemEffectSound().filePath, false); } void AniAdventureScene::onBonusItemPickUp(MapAdventureObjectPickupItem* item){ AniSoundsRepo::playSound(AniSoundsRepo::rightItemEffectSound().filePath, false); auto starSprite = item->getAssociatedMapImageObjects().begin()->second; auto itemPositionToWorld = starSprite->getParent()->convertToWorldSpace(starSprite->getPosition()); //GeometryUtils::getBoundingBoxToWorld(item->getAssociatedMapImageObjects().begin()->second); item->pickUp(); m_gardenMapController->hideObject(item); m_steve->flickerColours(); starAnimation(itemPositionToWorld); } void AniAdventureScene::onApproachedRotatingItem(MapAdventureObjectRotatingEnd* object){ if(m_shouldDisplayHintForLogLadder || !logLadderTutorialComplete()){ scheduleOnce([&, object](float){ auto bb1 = AniGeometryUtils::getBoundingBoxToWorld(object->getMapImageObject()); auto bb2 = AniGeometryUtils::getBoundingBoxToWorld(object->getHintMapImageObject()); auto point1 = cocos2d::Point(bb1.getMidX(), bb1.getMidY()); auto point2 = cocos2d::Point(bb2.getMidX(), bb2.getMidY()); displayMovingHintFinger(point1, point2); }, 0.6f, "displayMovingHintFinger"); //todo unscheduling this in cancelFinger is not semantically correct } auto movableObjectBB = object->getMapImageObject()->getBoundingBox(); auto hintObjectBB = object->getHintMapImageObject()->getBoundingBox(); m_gardenMapController->revealTilesInRadius(cocos2d::Point(movableObjectBB.getMidX(), movableObjectBB.getMidY()), movableObjectBB.size.width/2, movableObjectBB.size.height/2); m_gardenMapController->revealTilesInRadius(cocos2d::Point(hintObjectBB.getMidX(), hintObjectBB.getMidY()), hintObjectBB.size.width/2, hintObjectBB.size.height/2); } void AniAdventureScene::onFinishedRotatingItem(MapAdventureObjectRotatingEnd* object){ cancelMovingHintFinger(); m_shouldDisplayHintForLogLadder = false; saveLogLadderTutorialComplete(); } void AniAdventureScene::onCancelledRotatingItem(MapAdventureObjectRotatingEnd* object){ cancelMovingHintFinger(); } void AniAdventureScene::multipleStarAnimation(cocos2d::Vec2 startPosition, int count){ if(count < 1){ return; } auto delayBetweenStars = 0.3f; schedule([&, startPosition](float){ starAnimation(startPosition); }, delayBetweenStars, count-1, 0, "starAnimationSchedule"); } void AniAdventureScene::starAnimation(cocos2d::Vec2 startPosition){ auto newStarSprite = cocos2d::Sprite::create("graphics/star.png"); addChild(newStarSprite); newStarSprite->setPosition(startPosition); auto scaleUpDuration = 0.6f; auto midScreen = cocos2d::Director::getInstance()->getWinSize()/2; auto scaleUpRotateAnimation = cocos2d::EaseBounceOut::create(cocos2d::Spawn::create(cocos2d::MoveTo::create(scaleUpDuration, midScreen), cocos2d::ScaleTo::create(scaleUpDuration, 5), cocos2d::RotateBy::create(scaleUpDuration, 1000), nullptr)); // auto delayAction = cocos2d::DelayTime::create(0.2f); auto jumpToBasketDuration = 0.3f; auto basket = _objects["starCollector"]; auto hopIntoBasketAnimation = cocos2d::Spawn::create(cocos2d::ScaleTo::create(scaleUpDuration, 1), cocos2d::JumpTo::create(jumpToBasketDuration, basket->getPosition(), -midScreen.height/2, 1), nullptr); auto disappearAction = cocos2d::CallFunc::create([&, newStarSprite](){ newStarSprite->removeFromParent(); increaseScore(1); }); newStarSprite->runAction(cocos2d::Sequence::create(scaleUpRotateAnimation, /*delayAction,*/ hopIntoBasketAnimation, disappearAction, nullptr)); } void AniAdventureScene::basketShakeAnimation(){ auto basket = _objects["starCollector"]; auto singleRotateDuration = 0.1f; auto singleRotateAngle = 25; auto shakeAction = cocos2d::Repeat::create(cocos2d::Sequence::create(cocos2d::RotateTo::create(singleRotateDuration, singleRotateAngle), cocos2d::RotateTo::create(singleRotateDuration, -singleRotateAngle), NULL) , 4); basket->runAction(cocos2d::Sequence::create(shakeAction, cocos2d::CallFunc::create([basket](){ basket->setRotation(0); }), NULL)); } std::string AniAdventureScene::soundFilePathBored(IMapCharacter* p_mapCharacter){ return currentItem().soundRequest; } // TutorialDataSource std::string AniAdventureScene::soundPathForPhaseMove(AniTutorialMapControl* p_mapControl, int& soundDurationSecs){ return AniSoundsRepo::gameTutorialSound(0).filePath; } cocos2d::Point AniAdventureScene::mapPointForMoveSteveFinger(AniTutorialMapControl* p_mapControl){ return AniMapUtils::getInstance().getTileMiddlePosition(m_gardenMapController->getMap(), 10, 8); } std::vector AniAdventureScene::mapTilesForMoveSteveEnd(AniTutorialMapControl* p_mapControl){ return { AniMapUtils::TileData(9, 8), AniMapUtils::TileData(10, 8), AniMapUtils::TileData(11, 8), AniMapUtils::TileData(12, 8), AniMapUtils::TileData(13, 8) }; } cocos2d::Vec2 AniAdventureScene::cancelZoomButtonPosition(AniTutorialMapControl* p_mapControl){ showZoomButton(); auto buttonBB = _objects["steveButton"]->getBoundingBox(); return cocos2d::Vec2(buttonBB.getMidX(), buttonBB.getMidY()); } std::string AniAdventureScene::soundPathForPhaseTapObject(AniTutorialMapControl* p_mapControl, int& soundDurationSecs){ return AniSoundsRepo::gameTutorialSound(1).filePath; } cocos2d::Point AniAdventureScene::mapPointForTapObjectFinger(AniTutorialMapControl* p_mapControl){ return AniMapUtils::getInstance().getTileMiddlePosition(m_gardenMapController->getMap(), 13, 8); } std::string AniAdventureScene::soundPathForPhaseJumpUp(AniTutorialMapControl* p_mapControl, int& soundDurationSecs){ return AniSoundsRepo::gameTutorialSound(2).filePath; } std::string AniAdventureScene::soundPathForPhaseJumpDown(AniTutorialMapControl* p_mapControl, int& soundDurationSecs){ return AniSoundsRepo::gameTutorialSound(3).filePath; } std::string AniAdventureScene::soundPathForPhaseJumpLeft(AniTutorialMapControl* p_mapControl, int& soundDurationSecs){ return AniSoundsRepo::gameTutorialSound(4).filePath; } std::string AniAdventureScene::soundPathForPhaseJumpRight(AniTutorialMapControl* p_mapControl, int& soundDurationSecs){ return AniSoundsRepo::gameTutorialSound(5).filePath; } std::string AniAdventureScene::soundPathForPhaseTickle(AniTutorialMapControl* p_mapControl, int& soundDurationSecs){ return AniSoundsRepo::gameTutorialSound(6).filePath; } std::string AniAdventureScene::soundPathForPhaseMoveMap(AniTutorialMapControl* p_mapControl, int& soundDurationSecs){ return AniSoundsRepo::gameTutorialSound(7).filePath; } std::string AniAdventureScene::soundPathForPhaseTapToFinishMovingMap(AniTutorialMapControl* p_mapControl, int& soundDurationSecs){ return AniSoundsRepo::gameTutorialSound(8).filePath; } std::string AniAdventureScene::soundPathForTutorialFinished(AniTutorialMapControl* p_mapControl, int& soundDurationSecs){ soundDurationSecs = 5; return AniSoundsRepo::gameTutorialSound(9).filePath; } // TutorialDelegate void AniAdventureScene::tutorialFinished(AniTutorialMapControl* p_mapControl){ m_tutorialRunning = false; m_replayingTutorial = false; saveTutorialComplete(); m_tutorialMapControl = nullptr; //map layer will dealloc the previous map control // m_characterController->getCharacter()->setTimeToGetBored(40); _mapLayer->reallocMapControl(); m_gardenMapController->activateAllObjects(); m_gardenMapController->showAllObjects(); if(AniMiscUtils::lastLevel() != AniMiscUtils::Level::CHILD){ AniMiscUtils::showView(m_progressSliderNode->getParent(), true); } AniMiscUtils::showView(_objects["pauseButton"], true); startGame(true); } bool AniAdventureScene::touchHandlerForWidget(std::string objectName, cocos2d::ui::Widget::TouchEventType touchEventType){ if(objectName == "settingsButton" && touchEventType == cocos2d::ui::Widget::TouchEventType::ENDED){ if(!gameState->settingsMenuShown && !gameState->resumeLayerShown){ pauseGame(); showSettingsMenu(); } else { if(m_settingsMenu->isShowingParentalGate()){ m_settingsMenu->hideParentalGate(); } else { m_settingsMenu->hideParentalGate(); // in case showing parental gate is in progress... resumeGame(); hideSettingsMenu(); } } return true; } else if(objectName == "steveButton" && touchEventType == cocos2d::ui::Widget::TouchEventType::ENDED){ cancelZoomMode(); return true; } else if(objectName == "backgroundMusicButton" && touchEventType == cocos2d::ui::Widget::TouchEventType::ENDED){ auto bgMusicButton = dynamic_cast(_objects[objectName]); if(AniMiscUtils::shouldBgMusicPlay()){ AniMiscUtils::saveBgMusicPlaying(false); stopBackgroundMusic(false); if(bgMusicButton->isActive()){ bgMusicButton->setActive(false); } } else { AniMiscUtils::saveBgMusicPlaying(true); playBackgroundMusic(false); if(!bgMusicButton->isActive()){ bgMusicButton->setActive(true); } } return true; } return AniSubGameScene::touchHandlerForWidget(objectName, touchEventType); } void AniAdventureScene::showSettingsMenu(bool animated){ AniSubGameScene::showSettingsMenu(animated); AniMiscUtils::showView(_objects["backgroundMusicButton"], animated); disableButton("pauseButton"); } void AniAdventureScene::hideSettingsMenu(bool animated){ AniSubGameScene::hideSettingsMenu(animated); AniMiscUtils::hideView(_objects["backgroundMusicButton"], animated); enableButton("pauseButton"); } //void AniAdventureScene::displayMovingHintFinger(cocos2d::Point fromPoint, cocos2d::Point toPoint, float delay){ // scheduleOnce([&, fromPoint, toPoint](float){ // displayMovingHintFinger(fromPoint, toPoint); // }, delay, "displayMovingHintFinger"); //} void AniAdventureScene::displayMovingHintFinger(cocos2d::Point fromPoint, cocos2d::Point toPoint){ if(m_finger == nullptr){ m_finger = cocos2d::Sprite::create("graphics/tutorials/graphics/finger_one.png"); addChild(m_finger); m_finger->setAnchorPoint(cocos2d::Vec2(0.25, 0.9)); } else { m_finger->stopAllActions(); m_finger->setOpacity(255); m_finger->setVisible(true); } m_finger->setRotation(0); m_finger->setPosition(fromPoint); auto moveAction = cocos2d::Sequence::create(cocos2d::FadeIn::create(AniMiscUtils::StandardAnimationTime), cocos2d::EaseInOut::create( cocos2d::MoveTo::create(0.3f, toPoint), 1.2), cocos2d::DelayTime::create(0.2f), cocos2d::FadeOut::create(AniMiscUtils::StandardAnimationTime), cocos2d::CallFunc::create([&, fromPoint](){ m_finger->setPosition(fromPoint); }), cocos2d::FadeIn::create(AniMiscUtils::StandardAnimationTime), nullptr); m_finger->runAction(cocos2d::RepeatForever::create(moveAction)); } void AniAdventureScene::cancelMovingHintFinger(){ unschedule("displayMovingHintFinger"); if(m_finger != nullptr){ m_finger->stopAllActions(); AniMiscUtils::hideView(m_finger, true); } } void AniAdventureScene::cancelZoomMode(){ auto button = dynamic_cast(_objects["steveButton"]); button->setEnabled(false); AniMiscUtils::hideView(button, true); auto basket = _objects["starCollector"]; AniMiscUtils::showView(basket, true); unschedule("cancelZoomModeHint"); unschedule("autoCancelZoomMode"); if(m_finger != nullptr){ m_finger->stopAllActions(); AniMiscUtils::hideView(m_finger, true); } m_gardenMapController->cancelZoomMode(); auto rotatingObject = m_characterController->currentlyInteractedWithObject(); if(rotatingObject != nullptr){ onApproachedRotatingItem(rotatingObject); //todo here we also should have a separat function. we should not call this function. it might contain functionality other than blinking the finger } } void AniAdventureScene::presentEndScene(float t){ AniSoundsRepo::playSound(AniSoundsRepo::scoreSound().filePath); auto endScene = AniEndScene::create("graphics/end_scene/scene_layout.scl", advGameState.score); cocos2d::Director::getInstance()->replaceScene(cocos2d::TransitionFade::create(0.4f, endScene)); }