原地址:http://blog.csdn.net/teng_ontheway/article/details/18360925
cocos2dx-坐标系
支持以下几种坐标系:
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函数完成最终的判定操作。
最后想说的一点是,尽可能用相对坐标。换句话说,程序中所有对象在设置大小和位置时,都应该以父对象的大小和位置为依据。 这样程序发布在以各种不同的分辨率发布时,只需要调整根对象的大小就可以了。
cocos2dx判断点击命中的几种方法:
- //重载
- virtual bool ccTouchBegan(CCTouch *touch, CCEvent *pEvent);
- virtual void ccTouchMoved(CCTouch *touch, CCEvent *pEvent);
- virtual void ccTouchEnded(CCTouch *touch, CCEvent *pEvent);
- virtual void onEnter();
- virtual void onExit();
- //添加支持触摸事件
- void CTestLayer::onEnter()
- {
- CCLayer::onEnter();
- this->setTouchEnabled(true);
- CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true);
- }
- void CTestLayer::onExit()
- {
- CCLayer::onExit();
- CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
- }
- //用自己的坐标系相对于原点进行判断
- bool checkTouchInSelf(CCTouch *touch);
- //用自己的坐标系相对于锚点进行判断
- bool checkTouchInSelf_AR(CCTouch *touch);
- //用父元素坐标系及自己在父坐标中的位置进行判断
- bool checkTouchInSelf_Parent(CCTouch *touch);
- //______________________________________________________________________________________________
- //用自己的坐标系相对于原点进行判断
- bool CTestLayer::checkTouchInSelf(CCTouch *touch)
- {
- //方案一
- //将点击点转换成自己坐标系中的坐标,相对于0,0点
- CCPoint pt = convertTouchToNodeSpace(touch);
- printf("pt.x=%.1f pt.y=%.1f\n", pt.x, pt.y);
- int nw = getContentSize().width;
- int nh = getContentSize().height;
- CCRect rc(0, 0, nw, nh);
- if(rc.containsPoint(pt))
- {
- //获得点击的OpenGL的世界坐标值
- CCPoint touchPoint = touch->getLocation();
- printf("ccTouchBegan x=%.1f y=%.1f\n", touchPoint.x, touchPoint.y);
- return true;
- }
- return false;
- }
- //______________________________________________________________________________________________
- //用自己的坐标系相对于锚点进行判断
- bool CTestLayer::checkTouchInSelf_AR(CCTouch *touch)
- {
- //方案二
- //将点击点转换成自己坐标系中的坐标,相对于锚点
- CCPoint ptAR = convertTouchToNodeSpaceAR(touch);
- printf("ptAR.x=%.1f ptAR.y=%.1f\n", ptAR.x, ptAR.y);
- CCPoint pp = this->getAnchorPoint();
- int nw = getContentSize().width;
- int nh = getContentSize().height;
- int nx = -(nw * pp.x);
- int ny = -(nh * pp.y);
- CCRect rcar(nx, ny, nw, nh);
- if(rcar.containsPoint(ptAR))
- {
- //获得点击的OpenGL的世界坐标值
- CCPoint touchPoint = touch->getLocation();
- printf("ccTouchBegan x=%.1f y=%.1f\n", touchPoint.x, touchPoint.y);
- return true;
- }
- return false;
- }
- //______________________________________________________________________________________________
- //用父元素坐标系及自己在父坐标中的位置进行判断
- bool CTestLayer::checkTouchInSelf_Parent(CCTouch *touch)
- {
- //方案三
- //获得点击的OpenGL的世界坐标值
- CCPoint touchPoint = touch->getLocation();
- //将点击的位置转换成父元素坐标系中的相对坐标
- CCPoint pt=getParent()->convertToNodeSpace(touchPoint);
- printf("pt.x=%.1f, pt.y=%.1f\n", pt.x, pt.y);
- //得到自己在父元素坐标系中的位置范围
- CCRect rect=boundingBox();
- printf("rect.l=%.1f, rect.b=%.1f, rect.r=%.1f, rect.t=%.1f\n",\
- rect.getMinX(), rect.getMinY(), rect.getMaxX(), rect.getMaxY());
- //判断是否点击落在自己的范围当中, 以上判断全是在父元素坐标系中进行计算
- if(rect.containsPoint(pt))
- {
- printf("ccTouchBegan x=%.1f y=%.1f\n", touchPoint.x, touchPoint.y);
- return true;
- }
- return false;
- }