为你解说cocos2d 坐标转换一些内容
在Cocos2D开发中,坐标转换是一项常见且重要的操作。通常,我们会遇到以下两种坐标转换情况:
常见坐标转换场景
1. 从当前坐标点获取世界坐标点(屏幕坐标点,OpenGL的坐标系)
若要实现此转换,可直接使用 nodeParent->convertToWorldSpace(node->getPosition())。需要注意的是,这里必须由需要转换坐标对象的父类调用 convertToWorldSpace 方法,其参数为对象相对于父类的坐标点,该方法返回的是屏幕坐标点。
2. 从当前坐标点获取相对于某个 CCNode 的坐标点
这种情况下,可使用 node2->convertToNodeSpace(node1->getPosition())。这里的 node2 不一定是 node1 的父类,此操作的目的是让 node1 得到相对于 node2 坐标系的坐标点,返回的就是相对于 node2 坐标系的坐标点。
上述调用默认使用的是 (0, 0) 锚点。若要考虑锚点,则需使用 convertToWorldSpaceAR() 和 convertToNodeSpaceAR() 方法。具体来说:
nodeParent->convertToWorldSpaceAR(node->getPosition()):由于默认锚点为(0, 0),所以其得到的坐标点为ccpAdd(nodeParent->convertToWorldSpace(node->getPosition()), ccp(nodeParent->getContentSize().width * 0.5, nodeParent->getContentSize().height * 0.5))。node2->convertToNodeSpaceAR(node1->getPosition()):同样因为默认锚点为(0, 0),其得到的坐标点为ccpSub(nodeParent->convertToWorldSpace(node->getPosition()), ccp(node2->getContentSize().width * 0.5, node2->getContentSize().height * 0.5))。
四个坐标转换方法研究
Cocos2D - X 中有四个表示坐标的方法,下面我们来详细研究一下:
CCPoint convertToNodeSpace(const CCPoint& worldPoint);
CCPoint convertToWorldSpace(const CCPoint& nodePoint);
CCPoint convertToNodeSpaceAR(const CCPoint& worldPoint);
CCPoint convertToWorldSpaceAR(const CCPoint& nodePoint);
在理解这些方法之前,我们需要对世界坐标和本地坐标有一定的认识。
坐标系介绍
1. GL坐标系
Cocos2D以OpenGL ES为图形库,因此使用OpenGL ES坐标系。该坐标系的原点位于屏幕左下角,x轴向右,y轴向上。
2. 屏幕坐标系
苹果的Quartz2D使用的是不同的坐标系统,其原点在屏幕左上角,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),大小为 (40, 40),这时的本地坐标系以 (80, 80) 为坐标原点,x轴向右,y轴向上。总体而言,本地坐标系原点为 node 的左下角坐标。
四个方法详细解析
1. convertToNodeSpace
调用方式为 CCPoint point = node1->convertToNodeSpace(node2->getPosition());,该方法的作用是将 node2 的坐标转化成相对于 node1 的本地坐标。
2. convertToWorldSpace
调用方式为 CCPoint point = node1->convertToWorldSpace(node2->getPosition());,此方法是将 node2 的坐标转化成相对于 node1 的世界坐标。具体操作是先将 node1 的坐标当做世界坐标,然后让 node2 的坐标位置重置成相对于 node1 的世界坐标。
3. convertToNodeSpaceAR
该方法是把 node1 的坐标系原点设置在锚点的位置。若锚点为 (0, 0),则转化之后的坐标系位置和 convertToNodeSpace 一样,结果也相同。
4. convertToWorldSpaceAR
与 convertToNodeSpaceAR 同理。
测试代码及结果分析
第一次测试
CCSprite *sprite1 = CCSprite::spriteWithFile("CloseNormal.png");
sprite1->setPosition(ccp(20, 40));
sprite1->setAnchorPoint(ccp(0, 0));
this->addChild(sprite1);
CCSprite *sprite2 = CCSprite::spriteWithFile("CloseNormal.png");
sprite2->setPosition(ccp(-5, -20));
sprite2->setAnchorPoint(ccp(1, 1));
this->addChild(sprite2);
CCPoint point1 = sprite1->convertToNodeSpace(sprite2->getPosition());
CCPoint point2 = sprite1->convertToWorldSpace(sprite2->getPosition());
CCPoint point3 = sprite1->convertToNodeSpaceAR(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 = (15.000000,20.000000)
position = (-25.000000,-60.000000)
position = (15.000000,20.000000)
结果与预期相符。
第二次测试
sprite1->setAnchorPoint(ccp(0.5, 0.5));
sprite1->setPosition(ccp(100, 100));
CCPoint point5 = sprite1->convertToNodeSpaceAR(sprite2->getPosition());
CCPoint point6 = sprite1->convertToWorldSpaceAR(sprite2->getPosition());
CCLog("position = (%f,%f)", point5.x, point5.y);
CCLog("position = (%f,%f)", point6.x, point5.y);
运算结果:
size = (40.000000,40.000000)
position = (-105.000000,-120.000000)
position = (95.000000,80.000000)
分析:重置后的 sprite1 坐标为 (100, 100),锚点为 (0.5, 0.5),所以对于 convertToNodeSpaceAR 和 convertToWorldSpaceAR 这两个方法,其坐标系原点为 (100, 100)。使用 convertToNodeSpaceAR 转化之后的坐标为 (-105, -120),使用 convertToWorldSpaceAR 转化之后的坐标为 (95, 80),与运算结果一致。
通过以上内容,我们对Cocos2D的坐标转换有了更深入的理解,在实际开发中就能更准确地运用这些方法进行坐标转换。