坐标系详解
Cocos2d-x坐标系和OpenGL坐标系相同,都是起源于笛卡尔坐标系。原点为屏幕左下角,x向右,y向上。
世界坐标系(World Coordinate) VS 本地坐标系(Node Local)
世界坐标系也叫做绝对坐标系,本地坐标系也叫相对坐标系,是和节点相关联的坐标系。每个节点都有独立的坐标系,当节点移动或改变方向时,和该节点关联的坐标系将随之移动或改变方向。我们通过Node的setPosition设定元素的位置使用的是相对与其父节点的本地坐标系而非世界坐标系。最后在绘制屏幕的时候cocos2d会把这些元素的本地坐标映射成世界坐标系坐标。
锚点(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)。
- 因为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);
gnore Anchor Point全称是ignoreAnchorPointForPosition,开启锚点自由定位的方法。
- 如果设置其值为true,则图片资源的Anchor Pont固定为左下角,否则即为所设置的位置。
- 如果设置其值为false,则可以通过setAnchorPoint重新设置锚点的位置。
VertexZ,PositionZ和zOrder
- VerextZ是OpenGL坐标系中的Z值
- PositionZ是Cocos2d-x坐标系中Z值
- zOrder是Cocos2d-x本地坐标系中Z值
在实际开发中我们只需关注zOrder,可以通过setPositionZ
接口来设置PositionZ。
- PositionZ是全局渲染顺序即在根节点上的渲染顺序。
- zOrder则是局部渲染顺序,即该节点在其父节点上的渲染顺序,与Node的层级有关。
实例代码:
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);
虽然green的zOrder大于red的zOder,但是因为red的PositionZ较大,所以red还是在green上面显示。
触摸点(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,我们在设计游戏逻辑时需要用到触摸点在Cocos2d坐标系中的位置,就需要将touch的坐标转换成OpenGL坐标系中的点坐标。
Touch position是屏幕坐标系中的点,OpenGL position是Cocos2d-x用到的OpenGL坐标系上的点坐标。通常我们在开发中会使用两个接口getLocation()
和getLocationInView()
来进行相应坐标转换工作。
此外,关于世界坐标系和本地坐标系的相互转换,在Node中定义了以下四个常用的坐标变换的相关方法。
// 把世界坐标转换到当前节点的本地坐标系中 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)
其中:Point point1 = sprite1->convertToNodeSpace(sprite2->getPosition());
相当于sprite2 这个节点添加到了sprite1这个节点上(实际并没有),sprite2在世界坐标系中位置不变的,以sprite1作为假象父节点,来算出sprite2锚点相对于sprite1的本地坐标。
其中:Point point2 = sprite1->convertToWorldSpace(sprite2->getPosition());
相当于sprite2 这个节点添加到了sprite1这个节点上(实际并没有),把sprite2目前的世界坐标作为相当于sprite1的本地坐标值后,这个时候sprite2的实际位置将会发生变化,算出sprite2变化后的世界坐标。