Skip to content

Instantly share code, notes, and snippets.

@toughrogrammer
Last active January 3, 2016 23:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save toughrogrammer/8535614 to your computer and use it in GitHub Desktop.
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!
#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;
}
// 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
@toughrogrammer
Copy link
Author

@toughrogrammer
Copy link
Author

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