这一篇我们来谈谈关于坐标系统中本地坐标与世界坐标的转换问题。
在上一篇中我们知道了标准的屏幕坐标系、本地坐标与世界坐标的区别,还了解了关于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里面的触摸事件该如何实现。