Drag to Pan and pinch to zoom on layer

Hi there,

I’m very new to cocos2dx, can some one point me some good example of drag to pan and pinch to zoom layer.
I tried many codes found in this forum and google, but none of theme are work for me, due to version of cocos2dx i’m using is the latest one.

I also tried to port codes writing in objective-c to cpp, it turns out that many functions do not work the same.

I decided to write my own, it nearly done but there is a jumping bug. I hope some one could help

maybe I should post my code here:

IsoController.h

#include "cocos2d.h"

class IsoController: public cocos2d::Layer {

    cocos2d::Point  _oneTouchStart;
    cocos2d::Point  _prevLayerPosition;

    int             _nTouches;
    float           _initialDistance;
    bool            _lock;

public:

    virtual bool init();
    virtual ~IsoController();
    CREATE_FUNC(IsoController);

    virtual void update(float delta);

    void ccTouchesBegan(cocos2d::Set *touches, cocos2d::Event *event);
    void ccTouchesMoved(cocos2d::Set *touches, cocos2d::Event *event);
    void ccTouchesEnded(cocos2d::Set *touches, cocos2d::Event *event);

};

IsoController.cpp

#include "IsoController.h"
USING_NS_CC;

bool IsoController::init() {

    if (!Layer::init()) {
        return false;
    }

    Size winSize = Director::getInstance()->getWinSize();

    this->setTouchEnabled(true);
    this->setAnchorPoint(Point(0.0f, 0.0f));
    this->setPosition(Point(winSize.width/2, winSize.height/2));

    _nTouches = 0;
    _oneTouchStart = Point(-1, -1);
    _prevLayerPosition = Point(-1, -1);
    _initialDistance = -1;
    _lock = false;

    Sprite *bg = Sprite::create("HelloWorld.png");
    this->addChild(bg);

    this->setContentSize(bg->getContentSize());

    return true;

}

IsoController::~IsoController() {

}

void IsoController::update(float delta) {

}

void IsoController::ccTouchesBegan(Set *touches, Event *event) {

    int n = touches->count();
    _nTouches += n;

}

void IsoController::ccTouchesMoved(Set *touches, Event *event) {

    if (_nTouches == 1 && !_lock) { //Pan

        Touch *touch = (Touch*)touches->anyObject();
        Point location = touch->getLocationInView();
        location = Director::getInstance()->convertToGL(location);

        if (_oneTouchStart.x < 0) {
            _oneTouchStart = location;
            _prevLayerPosition = this->getPosition();
        }else {
            this->setPosition(Point(_prevLayerPosition.x-(_oneTouchStart.x-location.x), _prevLayerPosition.y-(_oneTouchStart.y-location.y)));
        }

    }else if (_nTouches == 2) { //Zoom

        SetIterator it = touches->begin();
        for (int i=0; icount(); i++) {

            Touch *touch = (Touch*)(*it);
            Point location = touch->getLocationInView();
            location = Director::getInstance()->convertToGL(location);

            if (i == 0) {
                _oneTouchStart = location;
            }else {

                float x = (_oneTouchStart.x - location.x);
                float y = (_oneTouchStart.y - location.y);
                float z = sqrtf(x*x + y*y);

                if (_initialDistance < 0.0f) {
                    _initialDistance = z;

                    Point point = this->convertToNodeSpace(Point((_oneTouchStart.x+location.x)/2, (_oneTouchStart.y+location.y)/2));

                    Point t_newAnchor = Point(
                                              (point.x/(this->getContentSize().width)),
                                              (point.y/(this->getContentSize().height)
                                               ));

                    this->setAnchorPoint(t_newAnchor);

                    // I think, I should have some code to avoid camera jumping here

                }

                float zoom = this->getScale();
                zoom += (z-_initialDistance)*0.005f;

                if (zoom > 2.0f) {
                    zoom = 2.0f;
                }
                if (zoom < 0.5f) {
                    zoom = 0.5f;
                }

                this->setScale(zoom);

                _initialDistance = z;

            }
            it++;

            _lock = true;
        }

    }

}

void IsoController::ccTouchesEnded(Set *touches, Event *event) {

    int n = touches->count();
    _nTouches -= n;

    if (_nTouches < 0) {
        _nTouches = 0;
    }

    _oneTouchStart = Point(-1, -1);
    _initialDistance = -1.0f;

    if (_nTouches <= 0) {
        _lock = false;
    }

}

We modified a version of CCPanZoomLayer for our game, and updated it for the 3.2 release by using the event dispatcher and all touches events. We added a TMXTiledMap as a child so we could pan and zoom around our “map”. You may find some help or ideas looking at the code.

Original version for cocos2d-iPhone

Discussion regarding porting it.

Version ported to cocos2d-x

The jumping looks to occur because you’re changing the anchor point without modifying the position. I would guess you could determine the difference between the new anchor point and the old anchor point and move the position of the sprite by that amount before adjusting the scale.

For debugging purposes you can derive from LayerGradient instead of Layer and then call LayerGradient::initWithColor(Color4B(255,0,0,255), Color4B(0,0,255,255)) instead of Layer::init() in order to see a little better what is going on.

For a good example, check out cpp-tests, the Parallax node test. There are 3 different examples that may be useful.

sorry but i’m new cocos user
can you teach me “How to Drag Layerscreen with background”…
plzz help me

please look at cpp-tests for examples.

layerscreen=LayerColor::create(ccc4(0, 0, 0, 0), 1920,768);
layerscreen->setPosition(Vec2(0,0));
this->addChild(layerscreen);

//BackGround
Backgroud = Sprite::create(“lvl-bg.png”);
Backgroud->setPosition(Vec2(960,384));
layerscreen->addChild(Backgroud);

layerscreen->runAction(RepeatForever::create(Sequence::create(MoveTo::create(15, Vec2(-896,0)),MoveTo::create(15, Vec2(0,0)), NULL)));

layerscreen->setAnchorPoint(Point(0,0));

bool LevelScreen::onTouchBegan(Touch* touch, Event* event)
{
location = touch->getLocationInView();
location = Director::getInstance()->convertToGL(location);
location = layerscreen->convertToNodeSpace(location);

layerscreen->stopAllActions();

Began_point=location.x;

return true;
}
void LevelScreen::onTouchMoved(Touch* touch, Event* event)
{
location = touch->getLocationInView();
location = Director::getInstance()->convertToGL(location);
location = this->convertToNodeSpace(location);

location = layerscreen->convertToNodeSpace(location);
// level_point[temp]->setPosition(location);

if(_oneTouchStart.x<0)
{
_oneTouchStart=location;
_prevLayerPosition=layerscreen->getPosition();
}
else if(_prevLayerPosition.x>=1024)
{
}
else
{
layerscreen->setPositionX(_prevLayerPosition.x-(_oneTouchStart.x-location.x));
}

}

void LevelScreen::onTouchEnded(Touch* touch, Event* event)
{
location = touch->getLocationInView();
location = Director::getInstance()->convertToGL(location);
location = layerscreen->convertToNodeSpace(location);

_oneTouchStart=Point(-1,-1);
_initialDisstance=-1.0f;

layerscreen->runAction(RepeatForever::create(Sequence::create(MoveTo::create(l_time, Vec2(-896,0)),MoveTo::create(15, Vec2(0,0)), NULL)));

CCLOG(“X=%3.0f y=%3.0f”, location.x,location.y);
temp++;
// CCLOG(“Vec2(PosX+(%3.0f), PosY+(%3.0f))”, -(visibleSize.width / 2 - location.x), -(visibleSize.height / 2 - location.y));
}