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

来源:互联网 发布:数据库分库分表 编辑:程序博客网 时间:2024/05/10 05:12


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 plaincopy
  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 plaincopy
  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 plaincopy
  1. aNode->convertToWorldSpace(testPoint);  
  2. aNode->convertToNodeSpace(testPoint);  

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

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

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

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

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

3.3:单位

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

[cpp] view plaincopy
  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 plaincopy
  1. aNode->setAnchorPoint(ccp(0.5,0.5));  
  2. aNode->setRotation(90.0);  

会发现界面完全没有动。

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

[cpp] view plaincopy
  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 plaincopy
  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 plaincopy
  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);) 容易看到坐标轴实际上随着图片转动了


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 上海医保卡丢了怎么办 户口转到西安后医保怎么办 上海医保卡掉了怎么办 上海医保本丢了怎么办? 新版医保卡丢了怎么办 武汉社保卡掉了怎么办 职工社保卡丢了怎么办 杭州社保卡丢了怎么办 农村医疗卡丢了怎么办 陕西省医保卡丢了怎么办 小孩社保卡掉了怎么办 社区医保本丢了怎么办 宝宝医保卡掉了怎么办 同煤医疗卡丢了怎么办 杭州医保卡丢了怎么办 新的医保卡丢了怎么办 二代医保卡丢了怎么办 老医保卡丢了怎么办 上海医保卡余额用完了怎么办 身份证丢了医疗报销怎么办 取公积金身份证丢了怎么办 身份证丢了怎么办就诊卡 人在外地怎么办农村社保卡 武汉医保卡丢了怎么办 济宁社保卡丢了怎么办 农村医疗本丢了怎么办 常熟医保卡丢了怎么办 农民社保卡丢了怎么办 常熟社保卡坏了怎么办 社保卡丢失补办期看病怎么办 社保卡补办期间看病怎么办 医保卡冻结了出院结算怎么办 住院医保卡钱不够怎么办 住院押金条丢了怎么办 急用新社保卡要怎么办 看病没带社保卡怎么办 医保卡掉了住院怎么办 厦门医保卡丢了怎么办 成都医保卡丢了怎么办 长春医保卡丢了怎么办 县城医保卡丢了怎么办