这一篇我们来谈谈关于坐标系统中本地坐标与世界坐标的转换问题。
在上一篇中我们知道了标准的屏幕坐标系、本地坐标与世界坐标的区别,还了解了关于cocos2dx的坐标系问题。
其实关于OpenGL的坐标,如果我们做2d编程,是可以暂时忽略Z轴坐标的。但是却需要记住的是渲染的深度问题,即Z_Older的值,这个值越大,其渲染出的图将会越在上面。关于这个值暂时记住就行。
在进入正题之前,我们需要知道什么是锚点?
锚点其实就是关于变换的参考点,比如旋转,平移缩放等。
锚点被规范化了,就像百分比一样,(0,0)意味着在节点的左下角,而(1,1)就在节点的右上角,你可以改变锚点的值在(0,0)到(1,1)范围内。
默认的锚点为(0.5,0.5),即中心点。
值得注意的是,如果这个节点是一个物理节点(physics body),它的锚点被固定在中间(in the middle),不可以改变。
我们来看一张图片:
如果我们把锚点设置为A点,那么,让它顺时针旋转90°之后,变成了如下图所示:
对每个Node节点都可以通过node->setAnthorPoint();来设置。
好了,下面进入正题吧~
Node对象给我们提供以下函数进行本地坐标的和世界坐标的转换:
Vec2 convertToNodeSpace(const Vec2& worldPoint) const ;//将世界坐标转换为本地坐标
Vec2 convertToWorldSpace(const Vec2& nodePoint) const;//将本地坐标转换为世界坐标
Vec2 convertToNodeSpaceAR(const Vec2& worldPoint) const;//不忽略参考点锚点的情况下,将世界坐标转换为本地坐标
Vec2 convertToWorldSpaceAR(const Vec2& nodePoint) const;//不忽略参考点锚点的情况下,将本地坐标转换为世界坐标
Vec2 convertTouchToNodeSpace(Touch * touch) const;//将世界坐标中的触摸点转换为本地坐标
Vec2 convertTouchToNodeSpaceAR(Touch * touch) const;//不忽略参考点锚点的情况下,将世界坐标中的触摸点转换为本地坐标
这些函数都会返回一个值,这个值便是转换后坐标点的值,即返回一个类型为Vec2的点。
这里我们就只讲一下前面四个函数的转换问题。
将世界坐标转换为本地坐标,这个会比较简单一点。我们先来看下下面的运行图:
我就不先贴代码出来,先来讲讲它们是如何转换的,表格是它们的相关信息:
属性 方块 |
锚点 |
位置 |
宽度 |
高度 |
Block1 |
(1,1) |
(300,300) |
200 |
200 |
Block2 |
(0,0) |
(0,0) |
100 |
100 |
我们把方块Block2以方块Block1为参考点从方块Block1为本地坐标中转换为世界坐标,转换的过程是:
第一种情况,在不考虑参考点锚点的前提下,转换后点的坐标 = 父节点的坐标 + 子节点在父节点的坐标
所以,转换之后的点的值为:(100,100)+(0,0) =(100,100)
实现代码如下:
Vec2 ConvertPoint = Block1->convertToNodeSpace(Block2->getPosition());
第二种情况,在考虑点锚点的前提下,转换后的点坐标 = 父节点的坐标 + 子节点的坐标 + 父节点锚点位置点*父节点实际大小
所以,转换之后的点的值为:(100,100)+ (0,0)+(1,1) * (200,200) = (300,300)
实现代码如下:
Vec2 ConvertPoint = Block1->convertToNodeSpaceAR(Block2->getPosition());
以上是本地坐标转换为世界坐标的实现。
现在来看看怎么由世界坐标转换为本地坐标,同样我我们先来看下运行图:
属性 方块 |
锚点 |
位置 |
宽度 |
高度 |
Block1 |
(1,1) |
(100,100) |
100 |
100 |
Block2 |
(0,0) |
(100,100) |
100 |
100 |
现在,我们可以以方块Block1为参考点把方块Block2转化为方块Block1的本地坐标。
思路也是和上面差不多,转换的过程如下:
第一种情况,不考虑参考点锚点的前提下,转换后的坐标 = 方块Block2的坐标 - 方块Block1的左下角点的坐标,
所以,转换后点的坐标 = (100,100)- (0,0) = (100,100)
实现代码如下:
Vec2 ConvertPoint = Block1->convertToNodeSpace(layer_block2->getPosition());
第二种情况,考虑参考点锚点的前提下,转换后的坐标 = 方块Block2的坐标 - 方块Block1的左下角坐标 - 锚点的位置点 * 方块Block1的大小,
所以,转换后点的坐标 = (100,100)- (0,0) - (1,1) * (100,100) = (0,0)
Vec2 ConvertPoint = Block1->convertToNodeSpaceAR(layer_block2->getPosition());
好了,现在把上面的所有代码都贴出来吧~
ConvertCoordinateDemo.h:
#pragma once #include"cocos2d.h" USING_NS_CC; class ConvertCoordinateDemo :public Layer{ public: virtual bool init(); static Scene *createScene(); CREATE_FUNC(ConvertCoordinateDemo); };ConvertCoordinateDemo.cpp:
#include"ConvertCoordinateDemo.h" Scene *ConvertCoordinateDemo::createScene() { Scene* scene = Scene::create(); ConvertCoordinateDemo *layer = ConvertCoordinateDemo::create(); scene->addChild(layer); return scene; } bool ConvertCoordinateDemo::init(){ if (!Layer::init()){ return false; } /********************************************************* 本地坐标转换为世界坐标 ************************************************************/ //方块一 LayerColor *layer_block1 = LayerColor::create(Color4B::RED, 100, 100); this->addChild(layer_block1); layer_block1->ignoreAnchorPointForPosition(false);//不忽略锚点 layer_block1->setAnchorPoint(Vec2(1,1)); layer_block1->setPosition(Vec2(100, 100)); auto mark1 = Label::createWithSystemFont("Block1", "", 30); mark1->setPosition(Vec2(50, 50)); layer_block1->addChild(mark1); //方块二 LayerColor *layer_block2 = LayerColor::create(Color4B::GREEN, 100, 100); this->addChild(layer_block2); layer_block2->ignoreAnchorPointForPosition(false);//层和场景都是忽略锚点的,默认为(0,0),这是设置不忽略锚点,即在中心点 layer_block2->setAnchorPoint(Vec2::ZERO); layer_block2->setPosition(Vec2(100, 100)); auto mark2 = Label::createWithSystemFont("Block2", "", 30); mark2->setPosition(Vec2(50, 50)); layer_block2->addChild(mark2); auto Block2_convertToNodeSpace = layer_block1->convertToNodeSpace(layer_block2->getPosition()); auto Block2_convertToNodeSpaceAR = layer_block1->convertToNodeSpaceAR(layer_block2->getPosition()); log("Block2_convertToNodeSpace:_x = %f,_y = %f", Block2_convertToNodeSpace.x, Block2_convertToNodeSpace.y); log("Block2_convertToNodeSpaceAR:_x = %f,_y = %f", Block2_convertToNodeSpaceAR.x, Block2_convertToNodeSpaceAR.y); /***************************************************************** 世界坐标转换为本地坐标 *******************************************************************/ //方块一 //LayerColor *layer_block1 = LayerColor::create(Color4B::RED, 200, 200); //this->addChild(layer_block1); //layer_block1->ignoreAnchorPointForPosition(false); //layer_block1->setAnchorPoint(Vec2(1,1)); //layer_block1->setPosition(Vec2(300, 300)); //auto mark1 = Label::createWithSystemFont("Block1", "", 50); //mark1->setPosition(Vec2(100, 120)); //layer_block1->addChild(mark1); //方块二 //LayerColor *layer_block2 = LayerColor::create(Color4B::GREEN, 100, 100); //layer_block1->addChild(layer_block2); //layer_block2->ignoreAnchorPointForPosition(false);//层和场景都是忽略锚点的,默认为(0,0),这是设置不忽略锚点,即在中心点 //layer_block2->setAnchorPoint(Vec2::ZERO); //layer_block2->setPosition(Vec2::ZERO); //auto mark2 = Label::createWithSystemFont("Block2", "", 30); //mark2->setPosition(Vec2(50, 50)); //layer_block2->addChild(mark2); //auto Block2_convertToWorldSpace = layer_block1->convertToWorldSpace(layer_block2->getPosition()); //auto Block2_convertToWorldSpaceAR = layer_block1->convertToWorldSpaceAR(layer_block2->getPosition()); //log("Block2_convertToWorldSpace:_x = %f,_y = %f", Block2_convertToWorldSpace.x, Block2_convertToWorldSpace.y); //log("Block2_convertToWorldSpaceAR:_x = %f,_y = %f", Block2_convertToWorldSpaceAR.x, Block2_convertToWorldSpaceAR.y); return true; }说明一下,这里的方块是用一个颜色层来创建,而层和场景默认是忽略锚点的,默认为(0,0),所以,为了能够重新设置层的锚点,我们先把层的设置为不忽略锚点,即调用ignoreAnchorPointForPosition()这个方法把它设置为false。其它的就不再多说了。希望能够对你有所帮助,如果有什么问题或是错误可以留下你的评论,我会很乐意为你解答的~
下一篇我会来谈谈关于cocos2dx里面的触摸事件该如何实现。