-
-
Save stevetranby/32bf3f27b389e5497750b33edeb8c8cc to your computer and use it in GitHub Desktop.
Camera Management
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// CameraManager.h | |
// | |
// Created by Steve Tranby on 4/21/13. | |
// Copyright (c) 2013 Steve Tranby. All rights reserved. | |
// | |
// License: MIT | |
// | |
#pragma once | |
#include "extensions/STLayerPanZoom.h" | |
typedef std::function<void()> popCallback; | |
class CameraManager | |
{ | |
// Singleton Stuff | |
public: | |
static CameraManager* get(); | |
private: | |
CameraManager() = default; | |
~CameraManager() = default; | |
CameraManager(const CameraManager&) = delete; | |
CameraManager& operator=(const CameraManager&) = delete; | |
CameraManager(CameraManager&&) = delete; | |
CameraManager& operator=(CameraManager&&) = delete; | |
public: | |
void update(float dt); | |
void setupWithPanZoomLayer(STLayerPanZoom* layer); | |
void resetManager(); | |
/// Get's world coordinate of the camera's center point | |
cocos2d::Vec2 worldToScreen(const cocos2d::Vec2& worldCoord, float atScale); | |
cocos2d::Vec2 screenToWorld(const cocos2d::Vec2& screenCoord, float atScale); | |
cocos2d::Vec2 currentWorldCoord(); | |
void pushState(); | |
bool popStateWithAction(const popCallback& callback); | |
bool popState(); | |
bool isMoving(); | |
/// reposition camera's center to a given world coord | |
/// defaults: newScale = 0, dur = 0, delay = 0 | |
void setViewpointCenter(const cocos2d::Vec2& newWorldCoord, bool animated, float newScale = 0, float dur = 0, float delay = 0, const popCallback& callback = [](){}); | |
/// reposition camera's center to a given world coord | |
/// defaults: no animation (instant move), no change to zoom, dur = 0 | |
void moveTo(const cocos2d::Vec2& position, bool animated = false, float newScale = 0, float dur = 0); | |
/// move camera's center by a given amount in world coord units | |
/// defaults: no animation (instant move), no change to zoom, dur = 0 | |
void moveBy(const cocos2d::Vec2& position, bool animated = false, float newScale = 0, float dur = 0); | |
void scaleBy(float scaleFactor); | |
void setInputDisabled(bool disabled); | |
private: | |
//cocos2d::ValueVector | |
struct CameraState { | |
cocos2d::Vec2 worldCoord; | |
float scale; | |
}; | |
std::vector<CameraState> stateStack; | |
STLayerPanZoom* panZoomLayer; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// CameraManager.cpp | |
// | |
// Created by Steve Tranby on 4/21/13. | |
// Copyright (c) 2013 Steve Tranby. All rights reserved. | |
// | |
// License: MIT | |
// | |
#include "stdafx.h" | |
#include "managers/CameraManager.h" | |
USING_NS_CC; | |
CameraManager* CameraManager::get() | |
{ | |
static CameraManager instance; | |
return &instance; | |
} | |
void CameraManager::setInputDisabled(bool disabled) { | |
panZoomLayer->setInputDisabled(disabled); | |
} | |
void CameraManager::setupWithPanZoomLayer(STLayerPanZoom* layer) | |
{ | |
panZoomLayer = layer; | |
} | |
void CameraManager::resetManager() | |
{ | |
dinfo("Resetting CM Manager!!"); | |
//setPanZoomLayer(nullptr); | |
panZoomLayer = nullptr; | |
stateStack.clear(); | |
} | |
/////////////////////////////////////////// | |
// MARK: - | |
void CameraManager::pushState() | |
{ | |
if(! panZoomLayer) { return; } | |
panZoomLayer->setInputDisabled(true); | |
CameraState state; | |
state.worldCoord = currentWorldCoord(); | |
state.scale = panZoomLayer->getScaleX(); | |
stateStack.push_back(state); | |
dlog("pushstate: %s, scaleTo=%f", CStrFromPoint(state.worldCoord), state.scale); | |
} | |
bool CameraManager::popStateWithAction(const popCallback& callback) | |
{ | |
if(! panZoomLayer) { return false; } | |
if(stateStack.empty()) { return false; } | |
panZoomLayer->stopAllActions(); | |
// return camera to top state (pos,zoom) | |
auto state = stateStack.back(); | |
float duration = 0.4f; | |
dlog("popstate: %s, scaleTo=%f, callback = %p", CStrFromPoint(state.worldCoord), state.scale, &callback); | |
setViewpointCenter(state.worldCoord, true, state.scale, duration, 0.f, callback); | |
stateStack.pop_back(); | |
panZoomLayer->setInputDisabled(false); | |
panZoomLayer->resetTouches(); | |
return true; | |
} | |
bool CameraManager::popState() | |
{ | |
return popStateWithAction(nullptr); | |
} | |
// MARK: - | |
Vec2 CameraManager::worldToScreen(const cocos2d::Vec2& worldCoord, float atScale) | |
{ | |
auto ws = Director::getInstance()->getWinSize(); | |
Vec2 screenCenter { ws.width * .5f, ws.height * .5f }; | |
Vec2 newOrigin = worldCoord * atScale; | |
Vec2 screenCoord = screenCenter - newOrigin; | |
dinfo2("screenCoored: %s", CStrFromPoint(screenCoord)); | |
//return { truncf(screenCoord.x), truncf(screenCoord.y) }; | |
return { screenCoord.x, screenCoord.y }; | |
} | |
Vec2 CameraManager::screenToWorld(const cocos2d::Vec2& screenCoord, float atScale) | |
{ | |
auto wsHalf = Director::getInstance()->getWinSize() * .5f; | |
Vec2 screenCenter { wsHalf.width, wsHalf.height }; | |
Vec2 worldOrigin = screenCenter - screenCoord; | |
Vec2 worldCoord = worldOrigin * 1.f / atScale; | |
return worldCoord; | |
} | |
Vec2 CameraManager::currentWorldCoord() | |
{ | |
if(! panZoomLayer) { return Vec2::ZERO; } | |
Vec2 p = panZoomLayer->getPosition(); | |
float s = panZoomLayer->getScaleX(); | |
// TODO: add to dlog macros header | |
// #define dlogVec2(x) dlog(#x ": %s", CStrFromPoint(x)) | |
// dlogVec2(p); | |
// dlogFloat(s); | |
return screenToWorld(p, s); | |
} | |
// MARK: - | |
bool CameraManager::isMoving() | |
{ | |
if(! panZoomLayer) { return false; } | |
auto action = panZoomLayer->getActionByTag(kTagActionCameraMoving); | |
if(action && ! action->isDone()) { | |
return true; | |
} | |
return false; | |
} | |
// MARK: - | |
//void CameraManager::setViewpointCenter(const Vec2& newWorldCoord, bool animated, float newScale /* = 0 */, float dur /* = 0 */, float delay /* = 0 */, FiniteTimeAction* callback /* = nullptr */) | |
void CameraManager::setViewpointCenter(const Vec2& newWorldCoord, bool animated, float newScale /* = 0 */, float dur /* = 0 */, float delay /* = 0 */, const std::function<void()>& callback) | |
{ | |
if(! panZoomLayer) { return; } | |
if(newScale == 0) { | |
newScale = panZoomLayer->getScaleX(); | |
} | |
// TODO: @profile @performance | |
float minScale = panZoomLayer->minScale(); | |
float maxScale = panZoomLayer->maxScale(); | |
newScale = clampf(newScale, minScale, maxScale);// .25f * SCALE_LARGE, 2.f * SCALE_LARGE); | |
// just find where panZoom should be if centering at new scale | |
Vec2 newPos = worldToScreen(newWorldCoord, newScale); | |
if(animated) | |
{ | |
float easeRate = 1.5f; | |
dinfo2("panZoomLayer position by action => %s, scale: %f, easerate: %f\n\n", CStrFromPoint(newPos), newScale, easeRate); | |
panZoomLayer->runCameraAction(delay, dur, newPos, newScale, easeRate, callback); | |
} | |
else | |
{ | |
panZoomLayer->setPosition(newPos); | |
panZoomLayer->setScale(newScale); | |
dinfo2("newWorldCoord: %s, newPos: %s, newScale: %f\n\n", | |
CStrFromPoint(newWorldCoord), | |
CStrFromPoint(newPos), | |
newScale); | |
} | |
} | |
// MARK: Move To - | |
void CameraManager::moveTo(const Vec2& position, bool animated /* = false */, float newScale /* = 0 */, float dur /* = 0 */) | |
{ | |
if(! panZoomLayer) { return; } | |
if (newScale == 0) { newScale = panZoomLayer->getScaleX(); } | |
setViewpointCenter(position, animated, newScale, dur); | |
} | |
// MARK: Move By - | |
// position - ?? world coord ?? offset from current camera "center of screen" world coord | |
void CameraManager::moveBy(const Vec2& position, bool animated /* = false */, float newScale /* = 0 */, float dur /* = 0 */) | |
{ | |
//dinfo("enter: moveby p = %s", CStrFromPoint(position)); | |
if(! panZoomLayer) { return; } | |
if(position.isZero() && newScale == 0) { return; } | |
Vec2 oldWorldCoord = currentWorldCoord(); | |
Vec2 newWorldCoord = oldWorldCoord + position; | |
if (animated && dur == 0) { | |
dur = 0.5f; | |
} | |
if (newScale == 0) { | |
newScale = panZoomLayer->getScaleX(); | |
} | |
setViewpointCenter(newWorldCoord, animated, newScale, dur); | |
} | |
void CameraManager::scaleBy(float scaleFactor) | |
{ | |
if(! panZoomLayer) { return; } | |
float newScale = panZoomLayer->getScaleX(); | |
newScale *= scaleFactor; | |
moveBy(Vec2::ZERO, false, newScale, 0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment