# cocos2d-x(5):坐标系(coordinate)学习

544人阅读 评论(0)

Cocos2d-x坐标系和OpenGL坐标系相同，都是起源于笛卡尔坐标系。

## 笛卡尔坐标系

### 屏幕坐标系和Cocos2d坐标系

iOS, Android, Windows Phone等在开发应用时使用的是标准屏幕坐标系，原点为屏幕左上角，x向右，y向下。

Cocos2d坐标系和OpenGL坐标系一样，原点为屏幕左下角，x向右，y向上。

## 锚点（Anchor Point）

• Anchor Point的两个参数都在0~1之间。它们表示的并不是像素点，而是乘数因子。(0.5, 0.5)表示Anchor Point位于节点长度乘0.5和宽度乘0.5的地方，即节点的中心

• 在Cocos2d-x中Layer的Anchor Point为默认值(0, 0)，其他Node的默认值为(0.5, 0.5)。

auto red = LayerColor::create(Color4B(255, 100, 100, 128), visibleSize.width/2, visibleSize.height/2);

auto green = LayerColor::create(Color4B(100, 255, 100, 128), visibleSize.width/4, visibleSize.height/4);

red->addChild(green);

this->addChild(red, 0);


注：因为Layer比较特殊，它默认忽略锚点，所以要调用ignoreAnchorPointForPosition()接口来改变锚点，关于ignoreAnchorPointForPosition()接口的使用说明，我们将在后面详细讲解。

auto red = LayerColor::create(Color4B(255, 100, 100, 128), visibleSize.width/2, visibleSize.height/2);
red->ignoreAnchorPointForPosition(false);
red->setAnchorPoint(Point(0.5, 0.5));
red->setPosition(Point(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

auto green = LayerColor::create(Color4B(100, 255, 100, 128), visibleSize.width/4, visibleSize.height/4);
green->ignoreAnchorPointForPosition(false);
green->setAnchorPoint(Point(1, 1));
red->addChild(green);

this->addChild(red, 0);


## 忽略锚点(Ignore Anchor Point)

Ignore Anchor Point全称是ignoreAnchorPointForPosition，作用是将锚点固定在一个地方。

auto red = LayerColor::create(Color4B(255, 100, 100, 128), visibleSize.width/2, visibleSize.height/2);
red->ignoreAnchorPointForPosition(true);
red->setPosition(Point(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

auto green = LayerColor::create(Color4B(100, 255, 100, 128), visibleSize.width/4, visibleSize.height/4);
green->ignoreAnchorPointForPosition(true);

red->addChild(green);

this->addChild(red, 0);


## VertexZ，PositionZ和zOrder

• VerextZ是OpenGL坐标系中的Z值
• PositionZ是Cocos2d-x坐标系中Z值
• zOrder是Cocos2d-x本地坐标系中Z值

Sets the 'z' coordinate in the position. It is the OpenGL Z vertex value.


    auto red = LayerColor::create(Color4B(255, 100, 100, 255), visibleSize.width/2, visibleSize.height/2);
red->ignoreAnchorPointForPosition(false);
red->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2));

auto green = LayerColor::create(Color4B(100, 255, 100, 255), visibleSize.width/4, visibleSize.height/4);
green->ignoreAnchorPointForPosition(false);
green->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2 - 100));
red->setPositionZ(1);
green->setPositionZ(0);
this->addChild(red, 0);
this->addChild(green, 1);


## 触摸点（Touch position)

    virtual bool onTouchBegan(Touch *touch, Event * event);
virtual void onTouchEnded(Touch *touch, Event * event);
virtual void onTouchCancelled(Touch *touch, Event * event);
virtual void onTouchMoved(Touch *touch, Event * event);


Touch position是屏幕坐标系中的点，OpenGL position是Cocos2d-x用到的OpenGL坐标系上的点坐标。通常我们在开发中会使用两个接口getLocation()getLocationInView()来进行相应坐标转换工作。

    // 把世界坐标转换到当前节点的本地坐标系中
Point convertToNodeSpace(const Point& worldPoint) const;

// 把基于当前节点的本地坐标系下的坐标转换到世界坐标系中
Point convertToWorldSpace(const Point& nodePoint) const;

// 基于Anchor Point把基于当前节点的本地坐标系下的坐标转换到世界坐标系中
Point convertToNodeSpaceAR(const Point& worldPoint) const;

// 基于Anchor Point把世界坐标转换到当前节点的本地坐标系中
Point convertToWorldSpaceAR(const Point& nodePoint) const;


    auto *sprite1 = Sprite::create("HelloWorld.png");
sprite1->setPosition(ccp(20,40));
sprite1->setAnchorPoint(ccp(0,0));
this->addChild(sprite1);  //此时添加到的是世界坐标系，也就是OpenGL坐标系

auto *sprite2 = Sprite::create("HelloWorld.png");
sprite2->setPosition(ccp(-5,-20));
sprite2->setAnchorPoint(ccp(1,1));
this->addChild(sprite2); //此时添加到的是世界坐标系，也就是OpenGL坐标系

//将 sprite2 这个节点的坐标ccp(-5,-20) 转换为 sprite1节点 下的本地(节点)坐标系统的 位置坐标
Point point1 = sprite1->convertToNodeSpace(sprite2->getPosition());

//将 sprite2 这个节点的坐标ccp(-5,-20) 转换为 sprite1节点 下的世界坐标系统的 位置坐标
Point point2 = sprite1->convertToWorldSpace(sprite2->getPosition());

log("position = (%f,%f)",point1.x,point1.y);
log("position = (%f,%f)",point2.x,point2.y);

运行结果：

Cocos2d: position = (-25.000000,-60.000000)
Cocos2d: position = (15.000000,20.000000)


bool Cood::init()
{
CCLayer::init();
/*
GL坐标体系：左下角为原点
UI坐标体系：左上角为原点

世界坐标体系：是窗口的坐标体系，它是GL坐标体系，原点在窗口的左下角
节点坐标体系：是Node的坐标体系，它也是GL坐标体系，和世界坐标体系不同的是，它的原点是节点的左下角

当一个节点调用setPosition时，使用的参数是它的父节点（渲染树）的坐标体系

CCLayer默认大小和窗口一样，所以它的坐标体系和世界坐标体系重合
CCScene默认大小和窗口一样，所以它的坐标体系和世界坐标体系重合

总结：
UI坐标和世界坐标之间的转换
CCDirector::sharedDirector()->convertToUI();
CCDirector::sharedDirector()->convertToGL();

世界坐标和节点坐标之间的转换
CCNode::convertToNodeSpace(CCPoint ptInWorld);
CCNode::convertToWorldSpace(CCPoint ptInNode);

按照锚点为原点来进行转换的方法
CCNode::convertToNodeSpaceAR(CCPoint ptInWorld); 这个函数返回的node坐标，是以锚点为原点
CCNode::convertToWorldSpaceAR(CCPoint ptInNode);

用touch作为参数转换
CCNode::convertTouchToNodeSpace，直接将触摸转换成节点坐标系的坐标
*/
CCSize winSize = CCDirector::sharedDirector()->getWinSize();

CCLayerColor* layerColor = CCLayerColor::create(ccc4(255, 0, 0, 255), winSize.width / 2, winSize.height / 2);
addChild(layerColor);  //相当于窗口大小

CCSprite* sprite = CCSprite::create("CloseNormal.png");
_sprite = sprite;
layerColor->addChild(sprite);
//sprite->setAnchorPoint(CCPoint(0,0));
//sprite->setPosition(ccp(100, 100));

layerColor->setPosition(ccp(100, 100));

CCPoint ptSpriteInWorld = layerColor->convertToWorldSpace(sprite->getPosition());
CCLog("ptSpriteInWorld.x = %f, ptSpriteInWorld.y=%f", ptSpriteInWorld.x, ptSpriteInWorld.y);

// convertToWorldSpaceAR 是以锚点作为原点来转换的结果
CCPoint ptSpriteInWorldByAnchor = layerColor->convertToWorldSpaceAR(sprite->getPosition());

// 加一个触摸处理，来演示UI坐标和GL坐标的转换
setTouchEnabled(true);
setTouchMode(kCCTouchesOneByOne);
return true;
}

bool Cood::ccTouchBegan(CCTouch* touch, CCEvent*)
{
//
CCPoint ptInUI = touch->getLocationInView();
//UI->GL
CCPoint ptInGL = touch->getLocation();
CCPoint ptUIConvert = CCDirector::sharedDirector()->convertToGL(ptInUI);

// and than ptUIConvert == ptInGL
CCLog("ptInUI(%f, %f)", ptInUI.x, ptInUI.y);
CCLog("ptInGL(%f, %f), ptConvert(%f, %f)", ptInGL.x, ptInGL.y, ptUIConvert.x, ptUIConvert.y);

// 判断是否点中了精灵
// 获取精灵的矩形，获取触摸点，判断戳点是不是在矩形内
CCRect rc = _sprite->boundingBox();
//CCPoint touchPoint = touch->getLocation();

// _sprite->getParent()->convertToNodeSpace(touchPoint) 将touch转换成精灵的父节点的坐标体系内的坐标点
//if (rc.containsPoint(_sprite->getParent()->convertToNodeSpace(touchPoint)))
if (rc.containsPoint(_sprite->getParent()->convertTouchToNodeSpace(touch)))
{
CCLog("Oh i am touched");
}
return true;
}


个人资料
等级：
访问量： 20万+
积分： 3292
排名： 1万+
最新评论