bool HelloWorld::init(){ bool bRet = false; do { CC_BREAK_IF(! CCLayer::init()); //opengl的坐标系和世界坐标系相同,都是以屏幕左下角为原点,向右为x轴的增加方向,向上为y轴的增加方向 //这里的世界指的是游戏世界 //屏幕坐标系是以左上角为原点,是我们熟悉的 //本地坐标系也叫节点坐标系,世界坐标系是相对于整体而言的,而本地坐标系是相对于父节点而言的,理解这点很重要 //CCDirector::sharedDirector()->convertToGL() 转换到OPENGL坐标系 //CCDirector::sharedDirector()->convertToUI() 转换到屏幕坐标系 //CCNode::convertToWorldSpace() 把本地坐标系转换到世界坐标系 //CCNode::convertToNodeSpace() 把世界坐标系转换到本地坐标系 //sprite1、sprite2的图片大小是100,100 CCSprite * sprite1 = CCSprite::create("image1.png"); sprite1->setPosition(ccp(100,100)); //将sprite2添加到sprite1节点中,这时候是以sprite1的左下角为原点,虽然sprite1的锚点是在它图片的中间 CCSprite * sprite2 = CCSprite::create("image2.png"); //setPosition中设置的坐标是sprite2的本地坐标 sprite2->setPosition(ccp(100,100)); sprite1->addChild(sprite2); //getPosition中获得的坐标也是sprite2的本地坐标 CCPoint point = sprite2->getPosition(); CCLog("point.x=%f,point.y=%f",point.x,point.y); //获得sprite2的opengl坐标系,屏幕坐标系,世界坐标系,本地坐标系 //convertToWorldSpace的传入参数是sprite2的节点坐标系(本地坐标),也就是setPosition中传入的参数,而convertToNodeSpace的传入参数是sprite2的世界坐标系,看清谁是调用者,传入的参数又是什么 CCPoint worldSpace = sprite1->convertToWorldSpace(point); CCPoint nodeSpace = sprite1->convertToNodeSpace(worldSpace); //以下俩个函数完成同样的功能,只不过这次的sprite2的坐标是基于sprite1的锚点的,而不是左下角了,所以我们传入了ccp(50,50) CCPoint worldSpaceAR = sprite1->convertToWorldSpaceAR(ccp(50,50)); CCPoint nodeSpaceAR = sprite1->convertToNodeSpaceAR(worldSpaceAR); //convertToUI中传入的是opengl坐标系,因为opengl坐标和世界坐标系是相同的,所以我们传入世界坐标 CCPoint ui = CCDirector::sharedDirector()->convertToUI(worldSpace); CCPoint opengl = CCDirector::sharedDirector()->convertToGL(ui); CCLog("opengl.x=%f,opengl.y=%f",opengl.x,opengl.y); CCLog("ui.x=%f,ui.y=%f",ui.x,ui.y); CCLog("worldspace.x=%f,worldspace.y=%f",worldSpace.x,worldSpace.y); CCLog("nodeSpace.x=%f,nodeSpace.y=%f",nodeSpace.x,nodeSpace.y); CCLog("worldspaceAR.x=%f,worldspaceAR.y=%f",worldSpaceAR.x,worldSpaceAR.y); CCLog("nodeSpaceAR.x=%f,nodeSpaceAR.y=%f",nodeSpaceAR.x,nodeSpaceAR.y); this->addChild(sprite1); bRet = true; } while (0); return bRet;}
补充:
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)]; //获得屏幕坐标
在调用任何需要设置位置的函数,或从函数获取位置信息前,必须要明确这个函数使用哪个坐标系。比如调用CCNode类的setPosition函数,它使用的就是GL坐标系。比如在处理触摸事件时CCTouch对象中的坐标就是屏幕坐标系。
另一个重要的坐标系就是和Node相关的本地坐标系。这个结构和一般做3D用的场景树的概念是一样的。所以从Node拿到的位置是该节点的本地坐标,需要通过特定的函数才能把本地坐标转换为世界坐标。而且这里的坐标都用的是GL坐标系。在CCNode对象中有几个方便的函数可以做坐标转换。convertToWorldSpace方法可以把基于当前node的本地坐标系下的坐标转换到世界坐标系中。convertToNodeSpace方法可以把世界坐标转换到当前node的本地坐标系中。 另一个关键的问题就是在cocos2d里面就是各种对象的大小问题。因为在cocos2d里CCNode对象有缩放的方法setScaleX和setScaleY。所以在获取对象大小的时候就必须根据情况明确指定获取对象原始大小,还是缩放后的大小。当然cocos2d里提供了对应的函数来完成这些操作。 getContentSize 函数用来获得节点原始的大小。 boundingBox 函数用来获得经过缩放和旋转之后的外框盒大小。pTouch对象中的坐标是屏幕坐标系,所以必须转换到GL坐标系,再转换到父节点的本地坐标下。好在convertTouchToNodeSpace这个函数一次完成了这两个转换,可以参考该库的源码,其中有具体的计算过程。