Last active
January 3, 2016 23:29
-
-
Save toughrogrammer/8535614 to your computer and use it in GitHub Desktop.
GrowingDever's PanZoomLayer :pIf it is useful to you, improve this and share please!
This file contains hidden or 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
#include "PanZoomLayer.h" | |
PanZoomLayer::PanZoomLayer() | |
{ | |
} | |
PanZoomLayer::~PanZoomLayer() | |
{ | |
} | |
PanZoomLayer* PanZoomLayer::create() | |
{ | |
PanZoomLayer *pRet = new PanZoomLayer; | |
if( pRet && pRet->init() ) | |
{ | |
pRet->autorelease(); | |
return pRet; | |
} | |
CC_SAFE_DELETE( pRet ); | |
return NULL; | |
} | |
bool PanZoomLayer::init() | |
{ | |
if( CCLayerColor::initWithColor( ccc4( 255, 0, 0, 0 ) ) == false ) | |
return false; | |
_touches = CCArray::create(); | |
_touches->retain(); | |
_accelerationFactor = 0.0f; | |
_productFactor = 55.0f; | |
_maxScale = 2.5f; | |
_minScale = 1.0f; | |
_isHolding = false; | |
return true; | |
} | |
void PanZoomLayer::onEnter() | |
{ | |
CCLayer::onEnter(); | |
CCDirector::sharedDirector()->getScheduler()->scheduleUpdateForTarget(this, 0, false); | |
this->setTouchEnabled( true ); | |
} | |
void PanZoomLayer::onExit() | |
{ | |
CCDirector::sharedDirector()->getScheduler()->unscheduleAllForTarget( this ); | |
CCLayer::onExit(); | |
_touches->removeAllObjects(); | |
CC_SAFE_RELEASE_NULL( _touches ); | |
} | |
void PanZoomLayer::update( float dt ) | |
{ | |
CCLayer::update( dt ); | |
if( _touches->count() == 1 ) | |
{ | |
_accelerationFactor *= 40 * dt * 0.95f; | |
} | |
else if( _touches->count() == 0 ) | |
{ | |
_accelerationFactor = fabs( _accelerationFactor - 0 ); | |
if( _accelerationFactor < FLT_EPSILON ) | |
return; | |
if( _accelerationFactor < 0.004f ) | |
{ | |
_accelerationFactor = 0; | |
} | |
else | |
{ | |
double d = dt * 60; | |
if( d > 0.99 ) | |
d = 0.99; | |
double i = (0 - _accelerationFactor) * 0.025 * d; | |
_accelerationFactor = ( _accelerationFactor + i ) * d; | |
CCPoint adder = _deltaSum; | |
adder.x *= this->getContentSize().width; | |
adder.y *= this->getContentSize().height; | |
this->setPosition( this->getPosition() + adder * 2.5 * _accelerationFactor ); | |
} | |
} | |
} | |
void PanZoomLayer::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent) | |
{ | |
if( _isHolding ) return; | |
CCTouch *pTouch; | |
CCSetIterator setIter; | |
int cnt = 0; | |
for (setIter = pTouches->begin(); setIter != pTouches->end(); ++setIter) | |
{ | |
pTouch = (CCTouch *)(*setIter); | |
_touches->addObject(pTouch); | |
} | |
_deltaSum = ccp( 0, 0 ); | |
_accelerationFactor = 0; | |
CCTime::gettimeofdayCocos2d( &_timeStamp, NULL ); | |
} | |
void PanZoomLayer::ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent) | |
{ | |
if( _isHolding ) return; | |
if( _touches->count() == 1 ) | |
{ | |
CCTouch *touch = (CCTouch*)_touches->objectAtIndex( 0 ); | |
CCPoint curTouchPosition = CCDirector::sharedDirector()->convertToGL( touch->getLocationInView() ); | |
CCPoint prevTouchPosition = CCDirector::sharedDirector()->convertToGL( touch->getPreviousLocationInView() ); | |
CCPoint deltaPosition = curTouchPosition - prevTouchPosition; | |
this->setPosition( this->getPosition() + deltaPosition ); | |
float prevAngle = CC_RADIANS_TO_DEGREES( _prevDeltaPoint.getAngle() ); | |
float angle = CC_RADIANS_TO_DEGREES( deltaPosition.getAngle() ); | |
if( fabs( prevAngle - angle ) <= 30 ) | |
{ | |
_deltaSum = ccp( 0, 0 ); | |
} | |
_prevDeltaPoint = deltaPosition; | |
_deltaSum.x = _deltaSum.x + deltaPosition.x / this->getContentSize().width; | |
_deltaSum.y = _deltaSum.y + deltaPosition.y / this->getContentSize().height; | |
_accelerationFactor += _deltaSum.getLength() * 4.0; | |
} | |
else if( _touches->count() >= 2 ) | |
{ | |
// Get the two first touches | |
CCTouch *touch1 = (CCTouch*)_touches->objectAtIndex(0); | |
CCTouch *touch2 = (CCTouch*)_touches->objectAtIndex(1); | |
// Get current and previous positions of the touches | |
CCPoint curPosTouch1 = CCDirector::sharedDirector()->convertToGL(touch1->getLocationInView()); | |
CCPoint curPosTouch2 = CCDirector::sharedDirector()->convertToGL(touch2->getLocationInView()); | |
CCPoint prevPosTouch1 = CCDirector::sharedDirector()->convertToGL(touch1->getPreviousLocationInView()); | |
CCPoint prevPosTouch2 = CCDirector::sharedDirector()->convertToGL(touch2->getPreviousLocationInView()); | |
// Calculate current and previous positions of the layer relative the anchor point | |
CCPoint curPosLayer = ccpMidpoint(curPosTouch1, curPosTouch2); | |
CCPoint prevPosLayer = ccpMidpoint(prevPosTouch1, prevPosTouch2); | |
// Calculate new scale | |
float prevScale = this->getScale(); | |
float curScale = this->getScale() * ccpDistance(curPosTouch1, curPosTouch2) / ccpDistance(prevPosTouch1, prevPosTouch2); | |
this->setScale( curScale ); | |
if( this->getScale() != prevScale ) | |
{ | |
CCPoint realCurPosLayer = this->convertToNodeSpaceAR(curPosLayer); | |
float deltaX = (realCurPosLayer.x) * (this->getScale() - prevScale); | |
float deltaY = (realCurPosLayer.y) * (this->getScale() - prevScale); | |
this->setPosition(ccp(this->getPosition().x - deltaX, this->getPosition().y - deltaY)); | |
} | |
// If current and previous position of the multitouch's center aren't equal -> change position of the layer | |
if (!prevPosLayer.equals(curPosLayer)) | |
{ | |
this->setPosition(ccp(this->getPosition().x + curPosLayer.x - prevPosLayer.x, | |
this->getPosition().y + curPosLayer.y - prevPosLayer.y)); | |
} | |
} | |
} | |
void PanZoomLayer::ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent) | |
{ | |
if( _isHolding ) return; | |
CCTouch *pTouch; | |
CCSetIterator setIter; | |
for (setIter = pTouches->begin(); setIter != pTouches->end(); ++setIter) | |
{ | |
pTouch = (CCTouch *)(*setIter); | |
_touches->removeObject(pTouch); | |
} | |
} | |
void PanZoomLayer::setPosition( CCPoint position ) | |
{ | |
CCNode::setPosition( position ); | |
if( _panBoundsRect.equals( CCRectZero ) == false ) | |
{ | |
CCRect boundBox = this->boundingBox(); | |
boundBox.origin = boundBox.origin * -1; | |
boundBox.size = boundBox.size / this->getScale(); | |
CCRect panBoundsRect; | |
panBoundsRect.origin = _panBoundsRect.origin * this->getScale(); | |
panBoundsRect.size = _panBoundsRect.size * this->getScale(); | |
// OpenGL coordinate system | |
float left = boundBox.origin.x; | |
float right = boundBox.origin.x + this->getContentSize().width; | |
float top = boundBox.origin.y + this->getContentSize().height; | |
float bottom = boundBox.origin.y; | |
float min_x = panBoundsRect.getMinX(); | |
float max_x = panBoundsRect.getMaxX(); | |
float min_y = panBoundsRect.getMinY(); | |
float max_y = panBoundsRect.getMaxY(); | |
float arLeft = min_x; | |
float arRight = max_x - this->getContentSize().width; | |
float arTop = max_y - this->getContentSize().height; | |
float arBottom = min_y; | |
if( left < min_x ) | |
{ | |
CCNode::setPosition( -arLeft, this->getPosition().y ); | |
} | |
if( right > max_x ) | |
{ | |
CCNode::setPosition( -arRight, this->getPosition().y ); | |
} | |
if( top > max_y ) | |
{ | |
CCNode::setPosition( this->getPosition().x, -arTop ); | |
} | |
if( bottom < min_y ) | |
{ | |
CCNode::setPosition( this->getPosition().x, -arBottom ); | |
} | |
} | |
} | |
void PanZoomLayer::setScale( float scale ) | |
{ | |
CCLayer::setScale( MIN( MAX( scale, _minScale ), _maxScale ) ); | |
this->setPosition( this->getPosition() ); | |
} | |
void PanZoomLayer::SetPanBoundsRect( CCRect rect ) | |
{ | |
_panBoundsRect = rect; | |
} | |
void PanZoomLayer::SetMaxScale( float maxScale ) | |
{ | |
_maxScale = maxScale; | |
} | |
float PanZoomLayer::GetMaxScale() | |
{ | |
return _maxScale; | |
} | |
void PanZoomLayer::SetMinScale( float minScale ) | |
{ | |
_minScale = minScale; | |
} | |
float PanZoomLayer::GetMinScale() | |
{ | |
return _minScale; | |
} | |
void PanZoomLayer::Holding() | |
{ | |
_isHolding = true; | |
} | |
void PanZoomLayer::UnHolding() | |
{ | |
_isHolding = false; | |
} | |
void PanZoomLayer::SetProductFactor( float v ) | |
{ | |
_productFactor = v; | |
} |
This file contains hidden or 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
// Created By GrowingDever 21th January 2014 | |
#ifndef _PAN_ZOOM_LAYER_H_ | |
#define _PAN_ZOOM_LAYER_H_ | |
#include "cocos2d.h" | |
using namespace cocos2d; | |
class PanZoomLayer : public CCLayerColor | |
{ | |
private: | |
CCArray *_touches; | |
CCPoint _beganTouchPoint; | |
CCPoint _endedTouchPoint; | |
CCPoint _deltaSum; | |
CCPoint _prevDeltaPoint; | |
double _accelerationFactor; | |
cc_timeval _timeStamp; | |
CCRect _panBoundsRect; | |
float _maxScale; | |
float _minScale; | |
float _productFactor; | |
bool _isHolding; | |
public: | |
PanZoomLayer(); | |
virtual ~PanZoomLayer(); | |
static PanZoomLayer* create(); | |
virtual bool init(); | |
virtual void onEnter(); | |
virtual void onExit(); | |
virtual void update( float dt ); | |
virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent); | |
virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent); | |
virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent); | |
virtual void setPosition( CCPoint position ); | |
virtual void setScale( float scale ); | |
void SetPanBoundsRect( CCRect rect ); | |
void SetMaxScale( float maxScale ); | |
float GetMaxScale(); | |
void SetMinScale( float minScale ); | |
float GetMinScale(); | |
void Holding(); | |
void UnHolding(); | |
void SetProductFactor( float v ); | |
}; | |
#endif |
27th January 2014, updating about pan bound. There was some error.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here is usage
http://growingdever.tistory.com/191