【cocos2D-x学习】3.坐标系

44 篇文章 0 订阅


http://blog.csdn.net/ronintao/article/details/9017447


【目标】:调试通过《cocos2D-x权威指南》中实例3.1.4:通过节点控制屏幕中的全体渲染对象

【参考】:

《cocos2D-x权威指南》 (也就是我现在正在学的书,纯入门级不解释)

cocos2D-x源码: cocos2dx\base_nodes\CCNode.cpp

【第一部分】:helloWorld模板的超入门级架构解读心得

作为超级菜鸟,刚拿到模板代码的时候,研究了好久才找到在哪里动笔改。实际上模板架构还是很简单的:

1) main.cpp: _tWinMain 就是 win32程序入口不解释。

对比一般的WIN32程序流程:注册wndclass -> CreateWindow & ShowWindow -> 消息队列循环

可以看到这里的流程如下: CCEGLView::sharedOpenGLView(); - > CCApplication::sharedApplication()->run();

很显然,CCEGLView::sharedOpenGLView() 是创建窗口,而 CCApplication::sharedApplication()->run(); 完成绘制和消息队列功能

2) AppDelegate: tWinMain的开头会调用 AppDelegate app; 构造一个 AppDelegate 的实例,而 AppDelegate 是继承与 CCApplication 的,在CCApplication的初始化代码中,可以看到

[cpp]  view plain copy
  1. CCApplication::CCApplication()  
  2. : m_hInstance(NULL)  
  3. , m_hAccelTable(NULL)  
  4. {  
  5.     m_hInstance    = GetModuleHandle(NULL);  
  6.     m_nAnimationInterval.QuadPart = 0;  
  7.     CC_ASSERT(! sm_pSharedApplication);  
  8.     sm_pSharedApplication = this;  
  9. }  

将全局实例 sm_pSharedApplication 设置为了 AppDelegate app,所以后面调用 CCApplication::sharedApplication()->run() 实际上都是调用的 AppDelegate 的方法。

3) HelloWorldScene : AppDelegate::applicationDidFinishLaunching() 中构造并启动。可以参考其中的调用

【第二部分】:坐标系

1、 源程序无比简单,就是在helloWorld模板下,创建一个父节点CCNode anode,将场景中所有节点作为其子节点添加,然后通过对父节点的操作来达到操纵子节点的目的。

和初始代码相比,只需要将原有的 this->addChild(XXX, z); 改为 aNode->addChild(XXX, z);

2、注意到3.1.4.4 中对整体旋转的处理:

[cpp]  view plain copy
  1. aNode->setPosition(ccp(200, 200));   
  2. aNode->setRotation(90.0);  

只能围绕默认锚点(0,0)进行旋转,比较SB。

既然一个sprite可以通过设置锚点来实现中心旋转,那么作为父节点的CCNode为什么不可以呢?

3、坐标系

参考

http://www.cnblogs.com/pengyingh/articles/2433081.html

http://www.2cto.com/kf/201208/148630.html

http://article.ityran.com/archives/3367

这里有这几个概念,只说明我这个初学者的看法,很可能不正确。

1)世界坐标系:即原 WINDOWS 中的 MM_TEXT。原点左上,正方向为右下。根据参考文档中所述,触摸等事件使用的是该坐标系。

2)GL坐标系:即OPENGL坐标系,右手坐标系,原点左下,正方向为右上前。

【TODO:需要澄清的事实:坐标系的单位?】

在WINDOW上既然是MM_TEXT,那么就应该是以PX为单位了(实测确实如此),不过不知道android和IOS上是以什么为单位的。根据我自己的DEFY的显示情况,应该也是以PX为单位。

(PS:关于android PX DPI DENSITY DIP 可以参考 http://blog.csdn.net/zhuojiuyihu/article/details/7292669 )

3)节点坐标系:父节点提供给子节点的相对坐标系,自然场景可以参考物理学中的相对坐标系。其情况又可以分为两种:

3.1: 原点和正方向(不考虑锚点)

[cpp]  view plain copy
  1. aNode->convertToWorldSpace(testPoint);  
  2. aNode->convertToNodeSpace(testPoint);  

不考虑父节点 aNode 的锚点,以aNode的“原设定”左下为原点,“原设定”的右上为正方向。

注意这里指的是“原设定”,这是因为父节点本身可能会旋转,如果发生旋转的话,节点坐标系也会随着旋转。

3.2: 原点和正方向(考虑锚点)

[cpp]  view plain copy
  1. aNode->convertToWorldSpaceAR(testPoint);  
  2. aNode->convertToNodeSpaceAR(testPoint);  

考虑父节点的锚点,以锚点为原点,“原设定”的右上为正方向。坐标系同样会旋转,不过旋转是以锚点为中心,所以在这个方法中,原点倒是不会随旋转而乱跑。

3.3:单位

对于节点坐标系的单位,又需要特别说明,因为会随着 setScale 而变化。

[cpp]  view plain copy
  1. cin >> scale;  
  2. aNode->setScale( ((float)scale)/10 );  
  3. CCPoint anchorPoint = aNode->getAnchorPointInPoints();  
  4. aNode->setPosition(ccp(200, 200));  
  5. CCPoint testPoint = ccp(10, 10);  
  6. CCPoint nodePoint = aNode->convertToNodeSpace(testPoint);  

 

当setscale(1) 时输出结果是:(-190, -190); 当 setScale(0.5) 时,输出结果是 (-380, -380),也就是说坐标系的单位值也变成了原来的0.5倍。

另外需要注意的是,setPosition 使用的显然不是节点坐标系,由于这里锚点设置的是默认的原点(0,0), 所以无论输入什么 scale, 其左下角原点在世界坐标系上的位置都是固定的。

这里和锚点牵扯的比较厉害,下面研究了锚点再来看一个稍微复杂一些的例子。

【第三部分:锚点】

名称还是挺形象的,我理解就是图像转换的中心点。需要注意的是,和原点并不是一个概念。

1、设置锚点的方法

第二部分提到书上 3.1.4.4 这个示例只是按照默认锚点旋转,对于图像旋转而言,并不是很好用。

书上有这样一句话:“只有CCNode节点使用贴图的情况下,锚点才有意义。”

不过在某些情况下,一个本身无贴图的CCNode节点,可能是作为几个有贴图的子节点的集中管理器出现的,那么提供一个锚点来进行操作还是挺有意义的。所以还是要尝试启用这个功能。现在我们的代码中的 aNode 就是这样一个CCNode,那么下面要为他设置锚点,然后再进行旋转。

如果我们直接使用一般节点的锚点设置方法是无效的:

[cpp]  view plain copy
  1. aNode->setAnchorPoint(ccp(0.5,0.5));  
  2. aNode->setRotation(90.0);  

会发现界面完全没有动。

查阅CCNode.cpp 源代码,可以看到

[cpp]  view plain copy
  1. CCAffineTransform CCNode::nodeToParentTransform(void)  
  2. {  
  3.     if (m_bIsTransformDirty)   
  4.     {  
  5.   
  6.         // Translate values  
  7.         float x = m_tPosition.x;  
  8.         float y = m_tPosition.y;  
  9.   
  10.         if (m_bIgnoreAnchorPointForPosition)   
  11.         {  
  12.             x += m_tAnchorPointInPoints.x;  
  13.             y += m_tAnchorPointInPoints.y;  
  14.         }  
  15.   
  16.         // Rotation values  
  17.         float c = 1, s = 0;  
  18.         if (m_fRotation)   
  19.         {  
  20.             float radians = -CC_DEGREES_TO_RADIANS(m_fRotation);  
  21.             c = cosf(radians);  
  22.             s = sinf(radians);  
  23.         }  
  24.   
  25.         bool needsSkewMatrix = ( m_fSkewX || m_fSkewY );  
  26.   
  27.   
  28.         // optimization:  
  29.         // inline anchor point calculation if skew is not needed  
  30.         if (! needsSkewMatrix && !m_tAnchorPointInPoints.equals(CCPointZero))  
  31.         {  
  32.             x += c * -m_tAnchorPointInPoints.x * m_fScaleX + -s * -m_tAnchorPointInPoints.y * m_fScaleY;  
  33.             y += s * -m_tAnchorPointInPoints.x * m_fScaleX +  c * -m_tAnchorPointInPoints.y * m_fScaleY;  
  34.         }  


可以看到,在实现旋转的时候,关键的几个变量是 m_bIgnoreAnchorPointForPosition 和 m_tAnchorPointInPoints。

m_bIgnoreAnchorPointForPosition 可以通过 ignoreAnchorPointForPosition(true) 来打开,

至于 m_tAnchorPointInPoints 则需要再设置setAnchorPoint "之前"调用 setContentSize(size) 来设置 size,这是因为 m_tAnchorPointInPoints 是根据 setAnchorPoint 设置进去的相对值和 ContentSize 的值相乘得到的,而一个没有设置贴图的 CCNode , 其contentSize 是 0, 所以如果直接设置 setAnchorPoint, 会发现用 getAnchorPointInPoints 查出来的锚点值仍然是0。

具体来说,代码如下:

[cpp]  view plain copy
  1. CCSize size = CCDirector::sharedDirector()->getWinSize();  
  2. aNode->ignoreAnchorPointForPosition(true);  
  3. aNode->setContentSize(size);    //这里的aNode实际装载的是整个界面,所以size也是整个winSize  
  4. aNode->setAnchorPoint(ccp(0.5,0.5));  
  5. aNode->setRotation(90.0);  

这样就可以实现旋转了。

可以看到这样设置锚点还挺麻烦的,肯定不是最好的方法,我看到后面scene节点和layer节点设置要容易的多,可能是更好的办法。

2. 锚点、旋转和节点坐标系

缩放和坐标系前面讨论过了,这里主要讨论旋转。实际上,节点坐标系是随着节点一起旋转的。只看一个例子,基本上就可以理解了:

[cpp]  view plain copy
  1. aNode->ignoreAnchorPointForPosition(true);  
  2. aNode->setContentSize(size);  
  3. aNode->setAnchorPoint(ccp(0.5,0.5));  
  4.   
  5. CCPoint anchorPoint = aNode->getAnchorPointInPoints();  
  6. cout << "x = " << anchorPoint.x  << "; y = " << anchorPoint.y << endl;  
  7. aNode->setPosition(ccp(200, 200));  
  8. aNode->setRotation(90.0);  
  9.   
  10. CCPoint testPoint = ccp(10, 10);  
  11. CCPoint nodePoint = aNode->convertToNodeSpace(testPoint);  
  12. cout << "node point x = "<< nodePoint.x << "; y = " << nodePoint.y << endl;  

输出的结果是 x = 590; y = -270 (辅助信息:eglView->setFrameSize(480, 320);) 容易看到坐标轴实际上随着图片转动了


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值