cocos2dx学习之路----第七篇(坐标系统中本地坐标与世界坐标的转换详解)

这一篇我们来谈谈关于坐标系统中本地坐标与世界坐标的转换问题。

在上一篇中我们知道了标准的屏幕坐标系、本地坐标与世界坐标的区别,还了解了关于cocos2dx的坐标系问题。

其实关于OpenGL的坐标,如果我们做2d编程,是可以暂时忽略Z轴坐标的。但是却需要记住的是渲染的深度问题,即Z_Older的值,这个值越大,其渲染出的图将会越在上面。关于这个值暂时记住就行。

在进入正题之前,我们需要知道什么是锚点?

锚点其实就是关于变换的参考点,比如旋转,平移缩放等。

锚点被规范化了,就像百分比一样,(0,0)意味着在节点的左下角,而(1,1)就在节点的右上角,你可以改变锚点的值在(0,0)到(1,1)范围内。

默认的锚点为(0.5,0.5),即中心点。

值得注意的是,如果这个节点是一个物理节点(physics body),它的锚点被固定在中间(in the middle),不可以改变。

我们来看一张图片:

cocos2dx学习之路----第七篇(坐标系统中本地坐标与世界坐标的转换详解)_第1张图片

如果我们把锚点设置为A点,那么,让它顺时针旋转90°之后,变成了如下图所示:

cocos2dx学习之路----第七篇(坐标系统中本地坐标与世界坐标的转换详解)_第2张图片

对每个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的点。

这里我们就只讲一下前面四个函数的转换问题。

将世界坐标转换为本地坐标,这个会比较简单一点。我们先来看下下面的运行图:

cocos2dx学习之路----第七篇(坐标系统中本地坐标与世界坐标的转换详解)_第3张图片

我就不先贴代码出来,先来讲讲它们是如何转换的,表格是它们的相关信息:

        属性

方块

锚点

位置

宽度

高度

Block1

(1,1)

(300,300)

200

200

Block2

(0,0)

(0,0)

100

100

需要说明的是,方块Block2是Block1的子节点。

我们把方块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());

 
  

以上是本地坐标转换为世界坐标的实现。

现在来看看怎么由世界坐标转换为本地坐标,同样我我们先来看下运行图:

cocos2dx学习之路----第七篇(坐标系统中本地坐标与世界坐标的转换详解)_第4张图片

            属性

方块

  锚点

     位置

 宽度             

 高度   

Block1

(1,1)

  (100,100)

100

100

Block2

(0,0)

  (100,100)

100

100

这两个方块都通过this->addChild()添加上去,所以和上面不同,它们的位置可以看作世界坐标。

现在,我们可以以方块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里面的触摸事件该如何实现。




你可能感兴趣的:(cocos2dx学习之路,cocos2dx学习之路)