转载自:http://www.cnblogs.com/pengyingh/articles/2513010.html
cocos2d坐标系
支持以下几种坐标系:
1.屏幕坐标系 原点在左上角,X轴向右,Y轴向下。
2.GL坐标系 原点在左下角,X轴向右,Y轴向上。
3.世界坐标系 指相对于整个屏幕的坐标系,(0,0)就是屏幕的左下角,(320,480)就是屏幕的右上角。
4.本地坐标系 相对于父对象的坐标。
[obj.parent convertToWorldSpace:[obj position]]; //获得obj的世界坐标 [obj.parent convertToNodeSpace:[obj position]]; //获得obj的本地坐标 [[CCDirector sharedDirector] convertToGL:*****(0,0)]; //获得GL坐标 [[CCDirector sharedDirector] convertToUI:*****(0,0)]; //获得屏幕坐标
锚点(anchor):
锚点是对象的坐标参考点,比方说 如果你要把一个门牌钉在门上,那么那颗钉子就是门牌的锚点,之后设置position时将会相对于锚点来设置。
obj.anchor = *****(0,0) //obj的锚点是左下角 obj.position = *****(0,0) //此时 obj会以它的左下角会参考点贴在父对象的左下角
这里要注意的是 CCLayer默认是禁用锚点的,即使你设置了它的锚点也根没设置一样!你需要使用以下代码开启它对锚点的支持:
[obj setIsRelativeAnchorPoint:YES]; //启用 obj 的锚点
无论是搞2d还是3d开发,最需要搞清楚的就是坐标系,这部分混乱的话就没啥奔头了。所以玩cocos2d,一上来就先把各种与坐标有关的东西搞清楚。
基本的两个坐标系:屏幕坐标系和GL坐标系。
屏幕坐标系x轴朝右,y轴朝下。默认原点在左上角。
GL坐标系x轴朝右,y轴朝上。默认原点在左下角。
在调用任何需要设置位置的函数,或从函数获取位置信息前,必须要明确这个函数使用哪个坐标系。比如调用CCNode类的setPosition函数,它使用的就是GL坐标系。比如在处理触摸事件时CCTouch对象中的坐标就是屏幕坐标系。
另一个重要的坐标系就是和Node相关的本地坐标系。这个结构和一般做3D用的场景树的概念是一样的。所以从Node拿到的位置是该节点的本地坐标,需要通过特定的函数才能把本地坐标转换为世界坐标。而且这里的坐标都用的是GL坐标系。在CCNode对象中有几个方便的函数可以做坐标转换。convertToWorldSpace方法可以把基于当前node的本地坐标系下的坐标转换到世界坐标系中。convertToNodeSpace方法可以把世界坐标转换到当前node的本地坐标系中。
另一个关键的问题就是在cocos2d里面就是各种对象的大小问题。因为在cocos2d里CCNode对象有缩放的方法setScaleX和setScaleY。所以在获取对象大小的时候就必须根据情况明确指定获取对象原始大小,还是缩放后的大小。当然cocos2d里提供了对应的函数来完成这些操作。
getContentSize 函数用来获得节点原始的大小。
boundingBox 函数用来获得经过缩放和旋转之后的外框盒大小。
举个简单的例子:
bool ret = CCRect::CCRectContainsPoint(
this->boundingBox() , this->getParent()->convertTouchToNodeSpace( pTouch ));
这个例子的功能是来判定当前的触摸操作是否发生在自己的node对象上。其中pTouch是CCTouch对象的指针,包含了当前触摸事件发生点的坐标。
CCRectContainsPoint这个函数用来判断一个点是否在一个矩形范围内。我们就想用这个函数来判断当前触摸操作的这个点是否在当前node的范围内。
this->boundingBox() 方法获得了当前节点对象在父节点对象下的缩放之后的本地坐标大小,并且是用GL坐标系表示的。
pTouch对象中的坐标是屏幕坐标系,所以必须转换到GL坐标系,再转换到父节点的本地坐标下。好在convertTouchToNodeSpace这个函数一次完成了这两个转换,可以参考该库的源码,其中有具体的计算过程。
所有数据都转换到同一个坐标系下了以后,就可以通过CCRectContainsPoint函数完成最终的判定操作。
最后想说的一点是,尽可能用相对坐标。换句话说,程序中所有对象在设置大小和位置时,都应该以父对象的大小和位置为依据。 这样程序发布在以各种不同的分辨率发布时,只需要调整根对象的大小就可以了。
cocos2d-x 坐标研究
转载自:http://blog.163.com/zjf_to/blog/static/201429061201292193855498/
2012-10-21 22:42:06| 分类: cocos2d-x | 标签:cocos2d-x 世界坐标 本地坐标 converttonodespacear converttonodespace |字号 订阅
今天晚上,对cocos2d-x里面的四个表示坐标的方法进行了一下研究,特意做了下笔记,如下:
CCPoint convertToNodeSpace(const CCPoint& worldPoint);
CCPoint convertToWorldSpace(const CCPoint& nodePoint);
CCPoint convertToNodeSpaceAR(const CCPoint& worldPoint);
CCPoint convertToWorldSpaceAR(const CCPoint& nodePoint);
在理解这个之前,要多世界坐标和本地坐标有一定的理解,
GL坐标系Cocos2D以OpenglES为图形库,所以它使用OpenglES坐标系。GL坐标系原点在屏幕左下角,x轴向右,y轴向上。
屏幕坐标系苹果的Quarze2D使用的是不同的坐标系统,原点在屏幕左上角,x轴向右,y轴向下。ios的屏幕触摸事件CCTouch传入的位置信息使用的是该坐标系。因此在cocos2d中对触摸事件做出响应前需要首先把触摸点转化到GL坐标系。可以使用CCDirector的convertToGL来完成这一转化。
世界坐标系也叫做绝对坐标系,cocos2d中的元素是有父子关系的层级结构,我们通过CCNode的position设定元素的位置使用的是相对与其父节点的本地坐标系而非世界坐标系。最后在绘制屏幕的时候cocos2d会把这些元素的本地坐标映射成世界坐标系坐标。世界坐标系和GL坐标系一致,原点在屏幕左下角,
本地坐标系本地坐标系也叫做物体坐标系,是和特定物体相关联的坐标系。每个物体都有它们独立的坐标系,当物体移动或改变方向时,和该物体关联的坐标系将随之移动或改变方向。比如用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的左下角坐标
接下来,convertToNodeSpace:调用CCPoint point = node1->convertToNodeSpace(node2->getPosition());
将node2的坐标转化成相对于node1的本地坐标
,
比如坐标如上图所示,node1的锚点为(0,0),node2的锚点为(1,1),转化之后,node的坐标变成了(-25,-60)
而convertToWorldSpace:调用CCPoint point = node1->convertToWorldSpace(node2->getPosition());
是将node的坐标转化成相对于node1的世界坐标,如上图所示:首先将node1的坐标当做世界坐标,然后让node2的坐标位置重置成相对于node1的世界坐标,也就是(15,20)
convertToNodeSpaceAR,就是把node1的坐标系原点设置在锚点的位置,这里的锚点是(0,0)所以转化之后的坐标系位置和上面的convertToNodeSpace一样,结果也是一样的,convertToWorldSpaceAR同理
测试:
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的锚点设置成(0.5,0.5),对convertToNodeSpaceAR和convertToWorldSpaceAR进行了进一步的测试
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),和运算结果一样