Cocos2d-x 3.0坐标系详解
Cocos2d-x坐标系和OpenGL坐标系相同,都是起源于笛卡尔坐标系。 笛卡尔坐标系 笛卡尔坐标系中定义右手系原点在左下角,x向右,y向上,z向外,OpenGL坐标系为笛卡尔右手系。
屏幕坐标系和Cocos2d坐标系 标准屏幕坐标系使用和OpenGL不同的坐标系,而Cocos2d则使用和OpenGL相同的坐标系。 iOS,Android,Windows Phone等在开发应用时使用的是标准屏幕坐标系,原点为屏幕左上角,x向右,y向下。 Cocos2d坐标系和OpenGL坐标系一样,原点为屏幕左下角,x向右,y向上。
在开发中,我们经常会提到两个比较抽象的概念-世界坐标系和本地坐标系。这两个概念可以帮助我们更好的理解节点在Cocos2d坐标系中的位置以及对应关系。
世界坐标系(World Coordinate) VS 本地坐标系(Node Local) 世界坐标系也叫做绝对坐标系,是游戏开发中建立的概念。因此,“世界”指游戏世界。cocos2d中的元素是有父子关系的层级结构,我们通过Node的setPosition设定元素的位置使用的是相对与其父节点的本地坐标系而非世界坐标系。最后在绘制屏幕的时候cocos2d会把这些元素的本地坐标映射成世界坐标系坐标。 本地坐标系也叫相对坐标系,是和节点相关联的坐标系。每个节点都有独立的坐标系,当节点移动或改变方向时,和该节点关联的坐标系将随之移动或改变方向。 锚点(Anchor Point) 将一个节点添加到父节点里面时,需要设置其在父节点上的位置,本质上是设置节点的锚点在父节点坐标系上的位置。
我们用以下代码为例,使用默认Anchor Point值,将红色层放在屏幕左下角,绿色层添加到红色层上: CCDirector* pDirector = CCDirector::sharedDirector(); CCPoint visibleOrigin = pDirector->getVisibleOrigin(); CCSize visibleSize = pDirector->getVisibleSize();
auto red = CCLayerColor::create(ccc4(255,100,128),visibleSize.width/2,visibleSize.height/2); auto green = CCLayerColor::create(ccc4(100,255,visibleSize.width/4,visibleSize.height/4); red->addChild(green); this->addChild(red,0); printf("red Position:%f--%f Anchor:%f--%fn",red->getPosition().x,red->getPosition().y,red->getAnchorPoint().x,red->getAnchorPoint().y); printf("green Position:%f--%f Anchor:%f--%fn",green->getPosition().x,green->getPosition().y,green->getAnchorPoint().x,green->getAnchorPoint().y); 1)输出: red Position:0.000000--0.000000 Anchor:0.500000--0.500000 green Position:0.000000--0.000000 Anchor:0.500000--0.500000 显示: 2)加上语句: red->ignoreAnchorPointForPosition(false); red->setAnchorPoint(ccp(0.5f,0.5f)); 输出: red Position:0.000000--0.000000 Anchor:0.500000--0.500000 green Position:0.000000--0.000000 Anchor:0.500000--0.500000 显示: 3)加上语句: red->setPosition(ccp(visibleSize.width/2 + visibleOrigin.x,visibleSize.height/2 + visibleOrigin.y)); 输出: red Position:240.000000--160.000000 Anchor:0.500000--0.500000 green Position:0.000000--0.000000 Anchor:0.500000--0.500000 显示: 4)加上语句: green->ignoreAnchorPointForPosition(false); green->setAnchorPoint(ccp(1,1)); 输出: red Position:240.000000--160.000000 Anchor:0.500000--0.500000 green Position:0.000000--0.000000 Anchor:1.000000--1.000000 显示:
忽略锚点(Ignore Anchor Point) Ignore Anchor Point全称是ignoreAnchorPointForPosition,作用是将锚点固定在一个地方。 如果设置其值为true,则图片资源的Anchor Pont固定为左下角,否则即为所设置的位置。 我们用以下代码为例,将两个层的ignoreAnchorPointForPosition设为true,并将绿色的层添加到红色的层上: CCDirector* pDirector = CCDirector::sharedDirector(); CCPoint visibleOrigin = pDirector->getVisibleOrigin(); CCSize visibleSize = pDirector->getVisibleSize();
red->ignoreAnchorPointForPosition(true); red->setPosition(ccp(visibleSize.width/2 + visibleOrigin.x,visibleSize.height/2 + visibleOrigin.y)); green->ignoreAnchorPointForPosition(true); green->setAnchorPoint(ccp(1,1)); red->addChild(green);
输出: red Position:240.000000--160.000000 Anchor:0.500000--0.500000 green Position:0.000000--0.000000 Anchor:1.000000--1.000000 显示: 触摸点(Touch position) 所以在处理触摸事件时需要用重写以下四个函数: virtual bool onTouchBegan(Touch *touch,Event * event); virtual void onTouchEnded(Touch *touch,240)"> virtual void onTouchCancelled(Touch *touch,240)"> virtual void onTouchMoved(Touch *touch,240); min-height:17px"> 在函数中获取到touch,我们在设计游戏逻辑时需要用到触摸点在Cocos2d坐标系中的位置,就需要将touch的坐标转换成OpenGL坐标系中的点坐标。 Touch position是屏幕坐标系中的点,OpenGL position是Cocos2d-x用到的OpenGL坐标系上的点坐标。通常我们在开发中会使用两个接口getLocation()和getLocationInView()来进行相应坐标转换工作。 在开发中一般使用getLocation()获取触摸点的GL坐标,而getLocation()内部实现是通过调用Director::getInstance()->convertToGL(_point);返回GL坐标。 // returns the current touch location in OpenGL coordinates CCPoint CCTouch::getLocation() const { return CCDirector::sharedDirector()->convertToGL(m_point); } 此外,关于世界坐标系和本地坐标系的相互转换,在Node中定义了以下四个常用的坐标变换的相关方法。 // 把世界坐标转换到当前节点的本地坐标系中 Point convertToNodeSpace(const Point& worldPoint) const;
// 把基于当前节点的本地坐标系下的坐标转换到世界坐标系中 Point convertToWorldSpace(const Point& nodePoint) const; // 把世界坐标转换到当前节点的基于Anchor Point的本地坐标系中 Point convertToNodeSpaceAR(const Point& worldPoint) const; //把基于当前节点Anchor Point的本地坐标系下的坐标转换到世界坐标系中 Point convertToWorldSpaceAR(const Point& nodePoint) const; 下面通过一个例子来说明这四个方法的理解和作用: auto *sprite1 = CCSprite::create("ccb/btn-b-0.png");//btn-b-0.png 100*100 sprite1->setPosition(ccp(20,40)); this->addChild(sprite1); //此时添加到的是世界坐标系,也就是OpenGL坐标系
CCSize s = sprite1->getContentSize(); CCPoint p = sprite1->getPosition(); CCPoint ap = sprite1->getAnchorPoint(); CCRect rect = CCRectMake(p.x - ap.x * s.width,p.y - ap.y * s.height,s.width,s.height); auto *sprite2 = CCSprite::create("ccb/btn-b-1.png"); sprite2->setPosition(ccp(-5,-20)); this->addChild(sprite2); //此时添加到的是世界坐标系,也就是OpenGL坐标系 //将 sprite2 这个节点的坐标ccp(-5,-20) 转换为 sprite1节点下的本地(节点)坐标系统的位置坐标 CCPoint point1 = sprite1->convertToNodeSpace(sprite2->getPosition()); CCPoint point2 = sprite1->convertToNodeSpaceAR(sprite2->getPosition()); 转换为 sprite1节点下的世界坐标系统的位置坐标 CCPoint point3 = sprite1->convertToWorldSpace(sprite2->getPosition()); CCPoint point4 = sprite1->convertToWorldSpaceAR(sprite2->getPosition()); printf("point1 = (%.0f,%.0f) n",point1.x,point1.y); printf("point2 = (%.0f,%.0f) n",point2.x,point2.y); printf("point3 = (%.0f,point3.x,point3.y); printf("point4 = (%.0f,point4.x,point4.y); 先给出输出结果,再来说明是怎么转化的: point1 = (0,-35) point2 = (-25,-60) point3 = (-10,-5) point4 = (15,20)
先拿point1和point2来说说没有AR和有AR的区别: point1和point2都是把sprite2的世界坐标转化为节点sprite1的本地坐标。区别在于他们基于的的本地坐标系(节点坐标系)的位置不一样。节点的本地坐标系默认的原点位置在节点的左下角位置,即图1的X1'-A1'-Y1'。用convertToNodeSpace来转换的时候基于的sprite1的本地坐标系的原点就是在sprite1的左下角的位置(图1的X1'-A1'-Y1'),而用convertToNodeSpace来转换的时候基于的sprite1的本地坐标系的原点在sprite1的锚点的位置(图1的X1-A1-Y1),因为我们知道一般节点的锚点在(0.5,0.5)的位置。上述代码中并没有设置sprit1的锚点,所以sprite1的默认为(0.5,0.5)。结论:没有AR后缀在转化的时候,实际上是以参照物的左下角,向上,向右来建立本地坐标系的,而有AR后缀在转化的时候,以参照物的锚点,向上向右来建立本地坐标系的。 再来说说世界坐标转本地坐标的计算方法: point1 = A2-A1‘ = (-5,-20) - (-5,15)=(0,-35) point2 = A2-A1 = (-5,-20)-(20,40)=(-25,-60) 结论:作为函数参数的世界坐标 - 参照物本地坐标系原点 再来说说convertToWorldSpace的计算方法(节点坐标转世界坐标) Point3 = A2+A1'=(-5,-20)+(-5,15)=(-10,-5) point4 = A2+A1 =(-5,-20)+(20,40)=(15,20) 结论:节点坐标 + 参照物本地坐标系原点 在上面如果把sprite1的锚点修改成: sprite1->setAnchorPoint(ccp(0,0)); 则此时锚点就在左下角的位置(如图2),那么输出结果就是: point1 = (-25,-60) point3 = (15,20)
另外,这里没有提到sprite2的锚点对转换的结果的影响,因为转换结果和它没有半毛钱关系。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |