无论是搞2d还是3d开发,最需要搞清楚的就是坐标系。网上很多讲解坐标系的文章,要么写得很模糊,要么纯粹是转载,此文章是在参考了各位大神的博客之后,根据自己的理解写的,在后面也分析了几个例子。菜鸟入门,不喜勿喷!
部分转载自:http://blog.163.com/zjf_to/blog/static/201429061201292193855498/
Cocos2d-x在CCNode中提供了一下四个坐标转换函数:
CCPoint convertToNodeSpace(constCCPoint& worldPoint);
CCPoint convertToWorldSpace(constCCPoint& nodePoint);
CCPoint convertToNodeSpaceAR(constCCPoint& worldPoint);
CCPoint convertToWorldSpaceAR(constCCPoint& nodePoint);
在理解这个之前,先了解一下世界坐标和本地坐标:
1、 GL坐标系:
Cocos2D以OpenglES为图形库,所以它使用OpenglES坐标系。GL坐标系原点在屏幕左下角,x轴向右,y轴向上。
2、 屏幕坐标系:
苹果的Quarze2D使用的是不同的坐标系统,原点在屏幕左上角,x轴向右,y轴向下。ios的屏幕触摸事件CCTouch传入的位置信息使用的是该坐标系。因此在cocos2d中对触摸事件做出响应前需要首先把触摸点转化到GL坐标系。可以使用CCDirector的convertToGL来完成这一转化。
3、 世界坐标系:
也叫做绝对坐标系,cocos2d中的元素是有父子关系的层级结构,我们通过CCNode的position设定元素的位置使用的是相对与其父节点的本地坐标系而非世界坐标系。最后在绘制屏幕的时候cocos2d会把这些元素的本地坐标映射成世界坐标系坐标。世界坐标系和GL坐标系一致,原点在屏幕左下角。
4、 本地坐标系:
本地坐标系也叫做物体坐标系,是和特定物体相关联的坐标系。每个物体都有它们独立的坐标系,当物体移动或改变方向时,和该物体关联的坐标系将随之移动或改变方向。比如用cocos2d-x创建了个矩形colorLayer:CCRect(10,10,100,100),这是的本地坐标系为以(10,10)为坐标原点,x轴向右,y轴向上。如果创建了一个CCSprite,锚点为(0.5,0.5),位置为(100,100),size为(40,40),这时的本地坐标系为以(80,80)为坐标原点,x轴向右,y轴向上。总之,本地坐标系原点为node的左下角坐标。
接下来,详细解析一下上述的四个函数:
1、 convertToNodeSpace:
调用CCPoint point =node1->convertToNodeSpace(node2->getPosition());
将node2的坐标转化成相对于node1的本地坐标。
如上图所示:node1的锚点为(0,0),所以node1的坐标为(20,40),node2的锚点为(1,1),所以node2的坐标为(-5, -20)。转换的时候,以node1(20,40)原点建立坐标系,此时node2(-5,-20)相对于新坐标系,转换之后就是(-25,-60)。
2、 convertToWorldSpace:
调用CCPoint point =node1->convertToWorldSpace(node2->getPosition());
将node2的坐标转化成相对于node1的世界坐标。
如上图所示:node1(20,40),node2(-5,-20)。以node1(20,40)为原点建立世界坐标系,此时node2(-5,-20)在新的世界坐标系中需往左(x轴)偏移5个单位,往下(y轴)偏移20个单位。所以node2(-5,-20)相对于node1世界坐标系为(-5,-20),而相对于原来的世界坐标系(0,0),其坐标则为(20-5,40-20),即(15,20)。
3、 convertToNodeSpaceAR:
上面的两个是忽略锚点的,所以讲坐标系原点设置在左下角。convertToNodeSpaceAR就是把node1的坐标系原点设置在锚点的位置,node1的锚点是(0,0),所以转化之后的坐标系位置和上面的convertToNodeSpace一样,结果也是一样的。
4、 convertToWorldSpaceAR:
跟convertToNodeSpaceAR同理。
测试:
CCSprite *sprite1 = CCSprite::create("HelloWorld.png",CCRect(0, 0, 40, 40));//从HelloWorld.png截取40x40的矩形区域
sprite1->setPosition(ccp(20,40));
sprite1->setAnchorPoint(ccp(0,0));
this->addChild(sprite1);
CCSprite *sprite2 = CCSprite::create("HelloWorld.png",CCRect(0, 0, 40, 40));
sprite2->setPosition(ccp(-5,-20));
sprite2->setAnchorPoint(ccp(1,1));
this->addChild(sprite2);
CCPoint point1 = sprite1->convertToNodeSpace(sprite2->getPosition());
CCPoint point2 =sprite1->convertToNodeSpaceAR(sprite2->getPosition());
CCPoint point3 =sprite1->convertToWorldSpace(sprite2->getPosition());
CCPoint point4 =sprite1->convertToWorldSpaceAR(sprite2->getPosition());
CCLog("position = (%f,%f)",point1.x,point1.y);
CCLog("position = (%f,%f)",point2.x,point2.y);
CCLog("position = (%f,%f)",point3.x,point3.y);
CCLog("position = (%f,%f)",point4.x,point4.y);
结果:
position = (-25.000000,-60.000000)
position = (-25.000000,-60.000000)
position = (15.000000,20.000000)
position = (15.000000,20.000000)
测试:
CCPoint point1 =sprite2->convertToNodeSpace(sprite1->getPosition());
CCPoint point2 =sprite2->convertToNodeSpaceAR(sprite1->getPosition());
CCPoint point3 = sprite2->convertToWorldSpace(sprite1->getPosition());
CCPoint point4 =sprite2->convertToWorldSpaceAR(sprite1->getPosition());
结果:
position = (65.000000,100.000000)
position = (25.000000,60.000000)
position = (-25.000000,-20.000000)
position = (15.000000,20.000000)
这里由于sprite2的锚点为(1,1),所以convertToNodeSpace和convertToNodeSpaceAR结果不一样。
解析:
sprite1坐标(20,40),sprite2坐标(-5,-20)。
convertToNodeSpace:以sprite2左下角建立节点坐标系,原点(-5-40,-20-40)即(-45,-60),node1(20,40)相对于(-45,-60),转换之后为(45+20,60+40)即(65,100)。
convertToNodeSpaceAR:以sprite2锚点的位置建立节点坐标系,原点(-5,-20),node1(20,40)相对于(-5,-20),转换之后为(5+20,20+40)即(25,60)。
convertToWorldSpace:以sprite2左下角建立世界坐标系,原点(-5-40,-20-40)即(-45,-60),node1(20,40)相对于(-45,-60),转换之后为(-45+20,-60+40)即(-25,-20)。
convertToWorldSpaceAR:以sprite2锚点的位置建立世界坐标系,原点(-5,-20),node1(20,40)相对于(-5,-20),转换之后为(-5+20,-20+40)即(15,20)。