// // MapAdventureObjectSlide.cpp // WattsenglishFoodApp // // Created by Katarzyna Kalinowska-Górska on 21/03/2020. // #include "AniMapUtils.h" #include "MapAdventureObjectRotatingEnd.h" #include "AniScalingUtils.h" #include "AniGeometryUtils.h" #include "AniMiscUtils.h" MapAdventureObjectRotatingEnd::MapAdventureObjectRotatingEnd(const rapidjson::Value& p_mapObjectData, IMapImageObject* p_mapImageObject, IMapImageObject* p_hintMapImageObject) : IMapAdventureObject(p_mapObjectData) { m_objectClassName = "MapAdventureObjectRotatingEnd"; auto scale = 1/cocos2d::Director::getInstance()->getContentScaleFactor(); m_mapImageObjects.insert({p_mapImageObject->objectName, p_mapImageObject}); m_occupiedTilesLying = AniJSONParseUtilsMap::parseTileDataArray(p_mapObjectData["occupiedPointsLying"]); m_occupiedTilesReady = AniJSONParseUtilsMap::parseTileDataArray(p_mapObjectData["occupiedPointsReady"]); m_entryTilesLying = AniJSONParseUtilsMap::parseTileDataArray(p_mapObjectData["entryPointsLying"]); m_entryTilesReady = AniJSONParseUtilsMap::parseTileDataArray(p_mapObjectData["entryPointsReady"]); m_tempBlockedTiles = AniJSONParseUtilsMap::parseTileDataArray(p_mapObjectData["tempBlockedTiles"]); m_wasAlwaysReady = m_isReady = p_mapObjectData["isReady"].GetBool(); m_rotationPivotPoint = AniJSONParseUtils::getPoint(p_mapObjectData["rotationPivotPoint"])*scale; m_readyRotationDegrees = p_mapObjectData["readyRotationDegrees"].GetInt(); m_blinkPictureFilePath = p_mapObjectData.HasMember("blinkPictureFilePath") ? p_mapObjectData["blinkPictureFilePath"].GetString() : ""; m_originalPictureFilePath = p_mapObjectData.HasMember("originalPictureFilePath") ? p_mapObjectData["originalPictureFilePath"].GetString() : ""; m_mergesWithMapWhenReady = p_mapObjectData.HasMember("mergesWithMapWhenReady") ? p_mapObjectData["mergesWithMapWhenReady"].GetBool() : false; if(p_hintMapImageObject != nullptr){ m_hintMapImageObject = p_hintMapImageObject; m_hintMapImageObject->setOpacity(0); } auto originalAnchorPoint = p_mapImageObject->getAnchorPoint(); p_mapImageObject->setAnchorPoint(cocos2d::Point(m_rotationPivotPoint.x / p_mapImageObject->getBoundingBox().size.width, m_rotationPivotPoint.y / p_mapImageObject->getBoundingBox().size.height)); // when we change the anchor point, we also need to adjust the postion so the sprite stays at the same spot auto anchorPointChange = p_mapImageObject->getAnchorPoint() - originalAnchorPoint; p_mapImageObject->setPositionX(p_mapImageObject->getPositionX() + anchorPointChange.x*p_mapImageObject->getBoundingBox().size.width); p_mapImageObject->setPositionY(p_mapImageObject->getPositionY() + anchorPointChange.y*p_mapImageObject->getBoundingBox().size.height); if(m_isReady){ p_mapImageObject->setRotation(m_readyRotationDegrees); p_mapImageObject->setMergeWithBackground(m_mergesWithMapWhenReady); } else { p_mapImageObject->setRotation(p_mapObjectData["entryRotationDegrees"].GetInt()); } m_originalRotation = p_mapImageObject->getRotation(); } std::vector MapAdventureObjectRotatingEnd::getEntryTiles() const { if(m_isReady){ return m_entryTilesReady; } else { return m_entryTilesLying; } } std::vector MapAdventureObjectRotatingEnd::getOccupiedTiles() const { return m_isReady ? m_occupiedTilesReady : m_occupiedTilesLying; } void MapAdventureObjectRotatingEnd::rotate(cocos2d::Point p_touchPointOnMap){ if(!m_isReady){ auto rotateAngleDegrees = evalNewRotation(p_touchPointOnMap); if(evalReady(rotateAngleDegrees)){ getMapImageObject()->setRotation(m_readyRotationDegrees); m_isReady = true; performOnRotationComplete(); if(m_mergesWithMapWhenReady){ getMapImageObject()->setMergeWithBackground(true); } if(m_hintMapImageObject != nullptr){ m_hintMapImageObject->setOpacity(0); } if(m_delegate != nullptr){ m_delegate->onOccupiedTilesDataChanged(this); m_delegate->onBlockedTilesDataChanged(this, m_tempBlockedTiles, std::vector()); } } else { getMapImageObject()->setRotation(rotateAngleDegrees); } } } float MapAdventureObjectRotatingEnd::evalNewRotation(cocos2d::Point p_touchPointOnMap){ auto rotationPivotPointInMapCoords = getMapImageObject()->getPosition(); //the anchor point is already set as m_rotationPivotPoint auto rotateVec = p_touchPointOnMap - rotationPivotPointInMapCoords; auto rotateAngle = -atan2(rotateVec.y, rotateVec.x); auto fix = 0.f; if(getMapImageObject()->getAnchorPoint().x > 0.5){ fix = 180; } auto rotateAngleDegrees = rotateAngle*180.0/3.14 + fix; return ensureValidRotation(rotateAngleDegrees, getMapImageObject()->getRotation()); } bool MapAdventureObjectRotatingEnd::evalReady(float p_newRotationDegrees){ static float eps = 4.f; return abs(p_newRotationDegrees - m_readyRotationDegrees) <= eps; } bool MapAdventureObjectRotatingEnd::evalReady(cocos2d::Point p_touchPointOnMap){ auto newRotation = evalNewRotation(p_touchPointOnMap); return evalReady(newRotation); } void MapAdventureObjectRotatingEnd::resetRotation(){ getMapImageObject()->setRotation(m_originalRotation); } //todo make somehow generic? //todo force to blink upon interacting? instead of doing it in the character controller? static int MAOREBlinkActionTag = 10; //temp //TODO better blinking void MapAdventureObjectRotatingEnd::startBlinking(){ if(m_blinkPictureFilePath != "" && m_originalPictureFilePath != ""){ auto animation = cocos2d::Animation::create(); animation->addSpriteFrameWithFile(m_blinkPictureFilePath); animation->addSpriteFrameWithFile(m_originalPictureFilePath); animation->setDelayPerUnit(0.5); auto blinkAction = cocos2d::RepeatForever::create(cocos2d::Animate::create(animation)); blinkAction->setTag(MAOREBlinkActionTag); getMapImageObject()->runAction(blinkAction); } if(m_hintMapImageObject != nullptr){ m_hintMapImageObject->runAction(cocos2d::FadeIn::create(AniMiscUtils::StandardAnimationTime)); } } void MapAdventureObjectRotatingEnd::stopBlinking(){ getMapImageObject()->stopActionByTag(MAOREBlinkActionTag); getMapImageObject()->setTexture(m_originalPictureFilePath); if(m_hintMapImageObject != nullptr){ m_hintMapImageObject->runAction(cocos2d::FadeOut::create(AniMiscUtils::StandardAnimationTime)); } } // ensure rotation is between original rotation and target rotation float MapAdventureObjectRotatingEnd::ensureValidRotation(float rotation, float prevRotation){ if(!m_onlyAllowRightDirection){ return rotation; } if(abs(rotation - prevRotation) > 300){ return prevRotation; } // we want to eliminate the 0-359 "jump" auto newRotation = rotation; if(m_readyRotationDegrees > m_originalRotation){ newRotation = MIN(newRotation, m_readyRotationDegrees); newRotation = MAX(newRotation, m_originalRotation); } else { newRotation = MAX(newRotation, m_readyRotationDegrees); newRotation = MIN(newRotation, m_originalRotation); } return newRotation; } void MapAdventureObjectRotatingEnd::reset(){ if(!m_wasAlwaysReady){ stopBlinking(); resetRotation(); m_isReady = false; getMapImageObject()->setMergeWithBackground(false); if(m_delegate != nullptr){ m_delegate->onOccupiedTilesDataChanged(this); m_delegate->onBlockedTilesDataChanged(this, std::vector(), m_tempBlockedTiles); } } }