在图形图像和游戏应用开发中坐标系是非常重要的,我们在Android和iOS等平台应用开发的时候使用的二维坐标系它的原点是在左上角的。而在Cocos2d-x坐标系中它原点是在左下角的,而且Cocos2d-x坐标系又可以分为:世界坐标和模型坐标。

UI坐标

UI坐标就是Android和iOS等应用开发的时候使用的二维坐标系。它的原点是在左上角的。

UI坐标原点是在左上角,x轴向右为正,y轴向下为正。我们在Android和iOS等平台使用的视图、控件等都是遵守这个坐标系。然而在Cocos2d-x默认不是采用UI坐标,但是有的时候也会用到UI坐标,例如在触摸事件发生的时候,我们会获得一个触摸对象(Touch),触摸对象(Touch)提供了很多获得位置信息的函数,如下面代码所示:

Point touchLocation = touch->getLocationInView();

使用getLocationInView()函数获得触摸点坐标事实上就是UI坐标,它的坐标原点在左上角。而不是Cocos2d-x默认坐标,我们可以采用下面的语句进行转换:

Point touchLocation2 = Director::getInstance()->convertToGL(touchLocation);

通过上面的语句就可以将触摸点位置从UI坐标转换为OpenGL坐标,OpenGL坐标就是Cocos2d-x默认坐标。

OpenGL坐标

我们在上面提到了OpenGL坐标,OpenGL坐标是种三维坐标。由于Cocos2d-x底层采用OpenGL渲染,因此的默认坐标就是OpenGL坐标,只不过只采用两维(x和y轴)。如果不考虑z轴,OpenGL坐标的原点在左下角。

提示:  三维坐标根据z轴的指向不同分为:左手坐标和右手坐标。右手坐标是z轴指向屏幕外。左手坐标是z轴指向屏幕里.OpenGL坐标是右手坐标,而微软平台的Direct3D[1]是左手坐标。

世界坐标和模型坐标

由于OpenGL坐标有可以分为:世界坐标和模型坐标,所以Cocos2d-x的坐标也有世界坐标和模型坐标。

你是否有过这样的问路经历:张三会告诉你向南走一公里,再向东走500米。而李四会告诉你向右走一公里,再向左走500米。这里两种说法或许都可以找到你要寻找的地点。张三采用的坐标是世界坐标,他把地球作为参照物,表述位置使用地理的东、南、西和北。而李四采用的坐标是模型坐标,他让你自己作为参照物,表述位置使用你的左边、你的前边、你的右边和你的后边。

我们看看图3-21,从图中可以看到A的坐标是(5,5),B的坐标是(4,6),事实上这些坐标值就是世界坐标。如果采用A的模型坐标来描述B的位置,则B的坐标是(1,-1)。

有的时候我们需要将世界坐标与模型坐标互相转换。我们可以通过Node对象如下函数实现:

Point convertToNodeSpace ( const Point & worldPoint )。将世界坐标转换为模型坐标。

Point convertToNodeSpaceAR ( const Point & worldPoint )。将世界坐标转换为模型坐标。AR表示相对于锚点。

Point convertTouchToNodeSpace ( Touch * touch )。将世界坐标中触摸点转换为模型坐标。

Point convertTouchToNodeSpaceAR ( Touch * touch )。将世界坐标中触摸点转换为模型坐标。AR表示相对于锚点。

Point convertToWorldSpace ( const Point & nodePoint )。将模型坐标中触摸点转换为世界坐标。

Point convertToWorldSpaceAR ( const Point & nodePoint )。将模型坐标中触摸点转换为世界坐标。AR表示相对于锚点。

下面我们通过两个例子了解一下世界坐标与模型坐标互相转换。

1、世界坐标转换为模型坐标

下面是世界坐标转换为模型坐标实例运行结果。

在游戏场景中有两个Node对象,其中Node1的坐标是(400, 500),大小是300 x 100像素。Node2的坐标是(200, 300),大小也是300 x 100像素。这里的坐标事实上就是世界坐标,它的坐标原点是屏幕的左下角。

编写代码如下:

  1. bool HelloWorld::init()
  2. {
  3. if( !Layer::init() )
  4. {
  5. returnfalse;
  6. }
  7. SizevisibleSize = Director::getInstance()->getVisibleSize();
  8. Pointorigin = Director::getInstance()->getVisibleOrigin();
  9. autocloseItem = MenuItemImage::create(
  10. "CloseNormal.png",
  11. "CloseSelected.png",
  12. CC_CALLBACK_1(HelloWorld::menuCloseCallback,this));
  13. closeItem->setPosition(Point(origin.x+ visibleSize.width - closeItem->getContentSize().width/2 ,
  14. origin.y+ closeItem->getContentSize().height/2));
  15. automenu = Menu::create(closeItem, NULL);
  16. menu->setPosition(Point::ZERO);
  17. this->addChild(menu,1);
  18. //创建背景
  19. autobg = Sprite::create("bg.png");                                                                                         ①
  20. bg->setPosition(Point(origin.x+ visibleSize.width/2,
  21. origin.y+ visibleSize.height/2));
  22. this->addChild(bg,0);                                                                                                                      ②
  23. //创建Node1
  24. autonode1 = Sprite::create("node1.png");                                                                           ③
  25. node1->setPosition(Point(400,500));
  26. node1->setAnchorPoint(Point(1.0,1.0));
  27. this->addChild(node1,0);                                                                                                               ④
  28. //创建Node2
  29. autonode2 = Sprite::create("node2.png");                                                                           ⑤
  30. node2->setPosition(Point(200,300));
  31. node2->setAnchorPoint(Point(0.5,0.5));
  32. this->addChild(node2,0);                                                                                                               ⑥
  33. PointPoint1 = node1->convertToNodeSpace(node2->getPosition());                                      ⑦
  34. PointPoint3 = node1->convertToNodeSpaceAR(node2->getPosition());                                 ⑧
  35. log("Node2NodeSpace = (%f,%f)",Point1.x,Point1.y);
  36. log("Node2NodeSpaceAR = (%f,%f)",Point3.x,Point3.y);
  37. returntrue;
  38. }

代码①~②行是创建背景精灵对象,这个背景是一个白色900 x 640像素的图片。代码第③~④行是创建Node1对象,并设置了位置和锚点属性。代码第⑤~⑥行是创建Node2对象,并设置了位置和锚点属性。第⑦行代码将Node2的世界坐标转换为相对于Node1的模型坐标。而第⑧行代码是类似的,它是相对于锚点的位置。

运行结果如下:

Node2 NodeSpace = (100.000000,-100.000000)

Node2 NodeSpaceAR =(-200.000000,-200.000000)

Node2的世界坐标转换为相对于Node1的模型坐标,就是将Node1的左下角作为坐标原点(图3-22中的A点),我们不难计算出A点的世界坐标是(100,400),那么convertToNodeSpace函数就是A点坐标减去C点坐标,结果是(-100,100)。而convertToNodeSpaceAR函数要考虑锚点,因此坐标原点是B点,B点坐标减去C点坐标,结果是(-200, -200)。

2、模型坐标转换为世界坐标

下面是模型坐标转换为世界坐标实例运行结果。

在游戏场景中有两个Node对象,其中Node1的坐标是(400, 500),大小是300 x 100像素。Node2是放置在Node1中的,它对于Node1的模型坐标是(0, 0),大小也是150 x 50像素。

编写代码如下:

  1. bool HelloWorld::init()
  2. {
  3. if( !Layer::init() )
  4. {
  5. returnfalse;
  6. }
  7. SizevisibleSize = Director::getInstance()->getVisibleSize();
  8. Pointorigin = Director::getInstance()->getVisibleOrigin();
  9. autocloseItem = MenuItemImage::create(
  10. "CloseNormal.png",
  11. "CloseSelected.png",
  12. CC_CALLBACK_1(HelloWorld::menuCloseCallback,this));
  13. closeItem->setPosition(Point(origin.x+ visibleSize.width - closeItem->getContentSize().width/2 ,
  14. origin.y+ closeItem->getContentSize().height/2));
  15. automenu = Menu::create(closeItem, NULL);
  16. menu->setPosition(Point::ZERO);
  17. this->addChild(menu,1);
  18. //创建背景
  19. autobg = Sprite::create("bg.png");
  20. bg->setPosition(Point(origin.x+ visibleSize.width/2,
  21. origin.y+ visibleSize.height/2));
  22. this->addChild(bg,0);
  23. //创建Node1
  24. autonode1 = Sprite::create("node1.png");
  25. node1->setPosition(Point(400,500));
  26. this->addChild(node1,0);
  27. //创建Node2
  28. autonode2 = Sprite::create("node2.png");
  29. node2->setPosition(Point(0.0,0.0));                                                                                              ①
  30. node2->setAnchorPoint(Point(0.0,0.0));                                                                              ②
  31. node1->addChild(node2,0);                                                                                                 ③
  32. PointPoint2 = node1->convertToWorldSpace(node2->getPosition());                                              ④
  33. Point Point4 =node1->convertToWorldSpaceAR(node2->getPosition());                                  ⑤
  34. log("Node2WorldSpace = (%f,%f)",Point2.x,Point2.y);
  35. log("Node2WorldSpaceAR = (%f,%f)",Point4.x,Point4.y);
  36. returntrue;
  37. }

上述代码我们主要关注第③行,它是将Node2放到Node1中,这是与之前的代码的区别。这样第①行设置的坐标就变成了相对于Node1的模型坐标了。

第④行代码将Node2的模型坐标转换为世界坐标。而第⑤行代码是类似的,它是相对于锚点的位置。

运行结果如下:

Node2 WorldSpace =(250.000000,450.000000)

Node2 WorldSpaceAR =(400.000000,500.000000)

所示的位置,可以用世界坐标描述。代码①~③行修改如下:

node2->setPosition(Point(250, 450));

node2->setAnchorPoint(Point(0.0,0.0));

this->addChild(node2, 0);


[1] Direct3D(简称:D3D)是微软公司在Microsoft Windows操作系统上所开发的一套3D绘图编程接口,是DirectX的一部份,目前广为各家显卡所支持。与OpenGL同为计算机绘图软件和计算机游戏最常使用的两套绘图编程接口之一。—— 引自于维基百科 http://zh.wikipedia.org/wiki/Direct3D

Cocos2d-x坐标系介绍的更多相关文章

  1. cocos2dx坐标系介绍

    GL坐标系 Cocos2D以OpenglES为图形库,所以它使用OpenglES坐标系.GL坐标系原点在屏幕左下角.x轴向右.y轴向上. 屏幕坐标系 苹果的Quarze2D使用的是不同的坐标系统,原点 ...

  2. cocos2D(五岁以下儿童)---- CCNode

    本将主要介绍下CCNode这个类.CCNode是全部节点的基类,当中包含我们经常使用的CCScene(场景).CCLayer(图层).CCSprite(精灵)等.它是一个不可以可视化显示的抽象类,仅仅 ...

  3. Cesium中的坐标系及转换

    在我们开始学习Entity之前,我们首先需要先学习下Cesium中的坐标系,Cesium中有多个坐标系,在进行添加Entity时经常会使用到. 一.坐标系介绍 我们先来列举下Cesium中的坐标系:W ...

  4. 五、CCNode

    本将主要介绍下CCNode这个类,CCNode是所有节点的基类,其中包括我们常用的CCScene(场景).CCLayer(图层).CCSprite(精灵)等,它是一个不能够可视化显示的抽象类,只是用来 ...

  5. cocos2d-x学习笔记

    转自:http://blog.csdn.net/we000636/article/details/8263503 接受触屏事件的优先级是值越小,响应触屏事件的优先级越高 Z值越大,越外面 JNI:允许 ...

  6. Unity3D 学习——入门资料整理

    感觉可以写3D游戏,还是用C#,很好玩的样子.整理最近学习资料 介绍:游戏引擎,可以用C#配置的游戏引擎.嗯,就这样.其余度娘. 安装:官网,因为现在个人版是免费的.直接官网下.干净利落. 调试插件: ...

  7. flash 动画数据导出 到 coco2d-js ,cocos2d-x 问题的记录

    1:必须搞清flash坐标系 和 cocos2d 的坐标系的差异2:对于cocos2d系列坐标系的深入理解: 以前我们常认为 coco2d-x的X,Y是相对坐标系,相对于父节点的X,Y的坐标,这种说法 ...

  8. C#程序员整理的Unity 3D笔记(十):Unity3D的位移、旋转的3D数学模型

    遇到一个想做的功能,但是实现不了,核心原因是因为对U3D的3D数学概念没有灵活吃透.故再次系统学习之—第三次学习3D数学. 本次,希望实现的功能很简单: 如在小地图中,希望可以动态画出Player当前 ...

  9. PHP自学之路---报表及绘图技术

    Ø  报表 a)        什么是报表 报表就是用表格.图表等格式来动态显示数据. b)        PHP绘图坐标系 1.  坐标系介绍 下图说明了PHP坐标系.坐标原点位于左上角,以像素为单 ...

随机推荐

  1. Codeforces Round #310 (Div. 2) B. Case of Fake Numbers 水题

    B. Case of Fake Numbers Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/5 ...

  2. Android学习笔记(四十):Preference的使用

    Preference直译为偏好,博友建议翻译为首选项.一些配置数据,一些我们上次点击选择的内容,我们希望在下次应用调起的时候依旧有效,无须用户再一次进行配置或选择.Android提供preferenc ...

  3. Android——ViewGroup的一个用法实例(转载)

    找了很久,终于找到了. <?xml version="1.0" encoding="UTF-8" ?> <merge xmlns:androi ...

  4. 将 Android 应用移植到 BlackBerry PlayBook 上

    美国西部时间18号早上,也就是我们的19号凌晨,BlackBerry DevCon活动隆重举行,PlayBook 2.0开发测试版随之发布.PlayBook 2.0的一个重要功能就是支持Android ...

  5. HTML5 <script>元素async,defer异步加载

    原文地址:HTML5′s async Script Attribute原文日期: 2010年09月22日翻译日期: 2013年08月22日 (译者注: 异步加载,可以理解为无阻塞并发处理.) (译者再 ...

  6. repeater复杂表格的显示

    首先简要的描述一下所要完成的事情:将某一个方言中的每一个声韵调组合,按照格式显示一个字 数据库中的信息:****,声母(Initial),韵母(Final),声调(Tone),一个汉字(Word),* ...

  7. ios上比较好用的Cydia插件

    1.iFile查看系统文件 2.KuaiDial归属地数据库 3.KuaiDial电话拨号助手 4.搜狗输入法 Photo Editor 房贷计算器

  8. Android操作系统服务(Context.getSystemService() )

    getSystemService是Android很重要的一个API,它是Activity的一个方法,根据传入的NAME来取得对应的Object,然后转换成相应的服务对象.下面介绍系统相应的服务: 传入 ...

  9. linux shell “(())” 双括号运算符使用

    导读 在刚开始学习inux shell脚本编程时候,对于它的 四则运算以及逻辑运算.估计很多朋友都感觉比较难以接受.特变逻辑运算符"[]"使用时候,必须保证运算符与算数 之间有空格 ...

  10. QQ上传大文件为什么这么快

    今天和同事在群里讨论“QQ上传大文件/QQ群发送大文件时,可以在极短的时间内完成”是如何做到的. 有时候我们通过QQ上传一个几百M的文件,竟然只用了几秒钟,从带宽上限制可以得出,实际上传文件是不可能的 ...