关于Cocos2d-x中坐标系的种类和转换

一.UI坐标系

在进行iOS或者Android界面开发时,它的坐标系规则如下图所示:

  • 原点坐标(x=0, y=0)位于左上角;
  • X轴从屏幕最左边开始,由左向右渐增;
  • Y轴坐标从屏幕最上方开始,由上向下渐增

二.Cocos2d-x坐标系

Cocos2d-x坐标系是这里的重点,也是我们开发时考虑的最多的。由于Cocos2d-x是基于OpenGL和OpenGL ES的。该坐标系的规则如下:

  • 原点坐标(x=0, y=0)位于左下角;
  • X轴从屏幕最左边开始,由左向右渐增;
  • Y轴从屏幕最下方开始,由下向上渐增;

在Cocos2d-x中的场景,就是使用的该坐标系。

三.世界坐标系

世界坐标系也叫绝对坐标系,是游戏开发中建立的概念。它建立了描述其它坐标系所需要的参考标准。我们都可以使用世界坐标系来描述其它坐标系的位置。

Cocos2d-x中元素是有父子关系的层次结构,通过Node设置位置使用的是相对其父节点的本地坐标系,而非世界坐标系,最后在绘制屏幕的时候,Cocos2d-x会把这些元素的本地节点坐标映射成世界坐标系坐标。世界坐标系和OpenGL坐标系方向一致,原点在屏幕左下角,X轴向右,Y轴向上。

四.节点坐标系

节点坐标系也叫相对坐标系,它是与特定节点相关联的坐标系。每个节点都有独立的坐标系,当节点移动或改变方向时,和该节点关联的坐标系(它的子节点)将随之移动或改变方向。比如一个Layer上面有10个精灵,当移动这个Layer的时候,这些精灵也会跟着一起移动的。

Node节点类中,我们可以对节点进行位置的操作,而这些设置位置使用的就是父节点的节点坐标系。它和OpenGL坐标系方向一致,原点在屏幕左下角,X轴向右,Y轴向上。有的时候,我们需要将节点坐标转换成世界坐标,或者将世界坐标转换成节点坐标。在Node节点类中,就提供了对应的转换函数,下面我们就使用一下这些函数,加深对Cocos2d-x坐标系、世界坐标系和节点坐标系的理解。

转换API

在Cocos2d-x中提供了以下的API用来进行坐标转换。

/**
* 将世界坐标转换成节点坐标,忽略锚点的影响;结果是以点为单位。
*/
Vec2 convertToNodeSpace(const Vec2& worldPoint) const;

/**
* 将节点坐标转换成世界坐标,忽略锚点的影响;结果是以点为单位。
*/
Vec2 convertToWorldSpace(const Vec2& nodePoint) const;

/**
* 将世界坐标转换成节点坐标;结果是以点为单位。
* 会考虑到锚点的影响
*/
Vec2 convertToNodeSpaceAR(const Vec2& worldPoint) const;

/**
* 将节点坐标转换成世界坐标;结果是以点为单位。
* 会考虑到锚点的影响。
*/
Vec2 convertToWorldSpaceAR(const Vec2& nodePoint) const;

/**
* 将Touch对应的点转换成节点坐标,忽略锚点的影响。
*/
Vec2 convertTouchToNodeSpace(Touch * touch) const;

/**
* 将Touch对应的点转换成节点坐标,考虑锚点的影响。
*/
Vec2 convertTouchToNodeSpaceAR(Touch * touch) const;

好了,世界坐标系转节点坐标系,节点坐标系转世界坐标系,就这么几个函数就能搞定了,剩下的就是实际的应用了。对了,在实际中,一定要考虑到锚点的影响,可能你得到的结果,就是因为锚点的影响,而完全不同的。

坐标系变换原理

上面总结了坐标系之间转换的一些API函数,下面就来看看它们之间到底是如何转换的。看了网上很多人的博客,写的转换原理,写的都不错,就是看的云里雾里的,很多人都配上了坐标图,搞笑的是那些坐标图都是“一副”,也不知道谁抄袭的谁的。

下面就做一些简单的原理,没有过的图来说明,就是一些简短的文字,按照这些文字说明,你肯定能看的懂的。

1.convertToNodeSpace
Vec2 newPosition = node1->convertToNodeSpace(node2->getPosition());
将node2的位置坐标转换成相对于node1左下角顶点的坐标。转换方法:node1和node2位置不变,将坐标轴原点设置为node1的左下角顶点,重新计算node2->getPosition()这个点的坐标即为newPosition。
当调用以下代码时,返回的是相对于其父节点的节点坐标,当然了,以下代码的实际用处并不大。

Vec2 newPosition = node1->convertToNodeSpace(node1->getPosition());

2.convertToNodeSpaceAR
Vec2 newPosition=node1->convertToNodeSpaceAR(node2->getPosition());
将node2的位置坐标转换成相对于node1锚点的坐标。转换方法:node1和node2位置不变,将坐标轴原点设置为node1的锚点,重新计算node2->getPosition()这个点的坐标即为newPosition。

3.convertToWorldSpace
Vec2 newPosition=node1->convertToWorldSpace(node2->getPosition());
将node2的位置坐标转换成世界坐标。转换方法:node1的位置不变,世界坐标的坐标轴也不变,以node1的左下角顶点再建立一个坐标系(其实就是本地坐标),将node2->getPosition()这个点设置到新建的坐标系中,以原来的世界坐标系为参考,重新计算node2->getPosition()这个点的坐标即为newPosition。

4.convertToWorldSpaceAR
Vec2 newPosition=node1->convertToWorldSpaceAR(node2->getPosition());
将node2的位置坐标转换成世界坐标。转换方法:node1的位置不变,世界坐标的坐标轴也不变,以node1的锚点再建立一个坐标系,将node2->getPosition()这个点设置到新建的坐标系中,以原来的世界坐标系为参考,重新计算node2->getPosition()这个点的坐标即为newPosition。

另一个例子

首先我们添加两个测试精灵(宽:27,高:40)到场景里面:

Sprite *sprite1 = Sprite::create("player.png");
sprite1->setPosition(Vec2(20, 40));
sprite1->setAnchorPoint(Vec2(0, 0));
this->addChild(sprite1);

Sprite *sprite2 = Sprite::create("player.png");
sprite2->setPosition(Vec2(-15, -30));
sprite2->setAnchorPoint(Vec2(1, 1));
this->addChild(sprite2);

然后调试,在场景中大概是下图这样显示(以左下角为坐标原点,从左到右为x方向,从下到上为y方向,废话了:)):

在cocos2d-x中,每个精灵都有一个锚点,以后对精灵的操作(比如旋转)都会围绕锚点进行,我们暂且可以看作是精灵的中心位置,一般来说有每个方向有三种可能的值:0,0.5,1。上图中红色圆点即为各自的锚点,sprite1 锚点为 (0,0) 左下角,sprite2锚点为(1,1)在右上角。

现在我们来看看坐标系转换,同样地,我们先写点测试代码:

Point p1 = sprite2->convertToNodeSpace(sprite1->getPosition());
Point p2 = sprite2->convertToWorldSpace(sprite1->getPosition());
Point p3 = sprite2->convertToNodeSpaceAR(sprite1->getPosition());
Point p4 = sprite2->convertToWorldSpaceAR(sprite1->getPosition());

接着,再打印出各点的x,y值:

Log("p1:%f,%f", p1.x, p1.y);
Log("p2:%f,%f", p2.x, p2.y);
Log("p3:%f,%f", p3.x, p3.y);
Log("p4:%f,%f", p4.x, p4.y);

由于cocos2d-x的坐标系(本地坐标系)是以左下角为坐标原点的,所以 sprite1和sprite2的坐标原点在上图的位置分别是(20,40)、(-42,-70),那么很明显的:

p1就是sprite1锚点相对于sprite2原点来说在sprite2坐标系中的位置,经过对比上图,我们可以得到(20-(-42),40-(-70))即(62,110)

p2就是sprite1锚点相对于sprite2原点来说在上图坐标系中的位置,这样我们可以计算出sprite1在sprite2坐标系中的位置:(20+(-42),40+(-70)),即(-22,-30)

p3就是sprite1锚点相对于sprite2锚点来说在sprite2坐标系中的位置,也就是(20-(-15),40-(-30)),即(35,70)

p4就是sprite1锚点相对于sprite2锚点来说在上图坐标系中的位置,也就是(20+(-15),40+(-30)),即(5,10)

现在我们可以知道,计算方法都是用sprite1的坐标去加减sprite2的坐标,针对本地坐标系就用减法,针对世界坐标系就用加法。

时间: 2024-07-28 12:30:01

关于Cocos2d-x中坐标系的种类和转换的相关文章

关于Unity中坐标系的种类

坐标空间 1:物体空间: 3D物体自己的坐标空间 一般设计时几何体以中心为原点,人物以双脚为原点; 2: 世界空间: 3D物体在场景中的世界坐标, 整个游戏场景的空间; 3: 摄像机空间: 以观察摄像机为原点的坐标系下的坐标空间; 4: 投影成像 3D坐标转换到屏幕空间;

ArcGIS中利用ArcMap将地理坐标系转换成投影坐标系(从WKID=4326到WKID=102100)

原文:ArcGIS中利用ArcMap将地理坐标系转换成投影坐标系(从WKID=4326到WKID=102100) 对于非地理专业的开发人员,对与这些生涩的概念,我们不一定都要了解,但是我们要理解,凡是以经纬度为单位的都是地理坐标系,因为它归根结底是一个椭球体,只不过各个国家为了反映该国家所在区域地球的真实形状,而采用不同的数学模型对本不是椭球体的地球进行椭球体化.而投影坐标系,是对地理坐标系按照某种方式投影到平面上的,所以可以认为它是一个平面坐标系,单位自然是米或千米. 我们在做开发的时候,尤其

如何在Cocos2D游戏中实现A*寻路算法(一)

大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流之用,请勿进行商业用途.同时,转载时不要移除本申明.如产生任何纠纷,均与本博客所有人.发表该翻译稿之人无任何关系.谢谢合作! 该篇博客由iOS课程团队的Johann Fradj发布,他现在是一个全职开发iOS的开发者.他是Hot Apps Factory(其是App Cooker的创造者)的共同创建

【iOS7的一些总结】8、破解UIView中坐标系的秘密:关于UIView中的frame、bound和center

对于刚刚接触iOS开发不久的新手来说,UIView中的frame.bound和center的确容易产生思维的误区,尤其是想要对视图类的bound这个概念若想要理解深入,真的要花一番功夫.在经过一系列查阅参考资料和动手试验之后,终于对这几个概念产生了一些领悟,记录于此可供有同样困惑的同学参考. 首先贴一篇博文做参考,http://blog.csdn.net/mad1989/article/details/8711697:这篇博文已经对UIView的frame和bound做了一些阐述,但是我依然觉得

C++中字母大写和小写转换实现的优化

C++中字母大写和小写转换实现的优化 write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie 讨论新闻组及文件 在本文中所有以转换为小写为例. 从推荐复用代码的角度来看,用库函数是不错的办法: 方案一: char gc1[53] = "abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ"; void wayOne() { strlwr(gc1); } 长处是使用方便,别人看着也easy理解

Java中数据类型及其之间的转换

Java中数据类型及其之间的转换 基本的数据类型 基本类型有以下四种: 1)int长度数据类型有:byte(8bits).short(16bits).int(32bits).long(64bits). 2)float长度数据类型有:单精度(32bits float).双精度(64bits double),JAVA中将小数默认为double类型,若要定义float需在数据后面用f声明: 3)boolean类型变量的取值有:ture.false 4)char数据类型有:unicode字符,16位 对

将传入结构体 pMtInfo 中包含的数据内容转换成 JSON 字符串返回

upu_struct.h封装了有关  pMtInfo结构体的内容,用到的部分如下图所示: 利用jansson库实现将传入结构体 pMtInfo 中包含的数据内容转换成 JSON 字符串返回 代码如下: #include <stdio.h> #include <string.h> #include "jansson.h" #include "upu_struct.h" #include "upu_proto_parse.h"

C语言extern引用AT&T汇编中的变量,任意转换类型

今天研究出了一个小问题,在C语言里引用汇编的变量,会是什么结果,汇编中的变量没有像C语言中int类型那样的类型约束,可以把数据当作任何类型处理,那么传到C语言中我们应该当作什么类型处理呢. 换句话说,在汇编里定义变量var,在C语言里引用,我们肯定要用extern声明var外部变量,那么extern后面接什么类型?难道是extern int var么?还是 extern short var 实例: 一. 汇编程序:(是的,就这么短小) .global var  #注意现在的汇编器不再要求被C语言

QT中字符串QString类型的转换

把QString转换为 double类型 方法1.QString str="123.45"; double val=str.toDouble(); //val=123.45 方法2.很适合科学计数法形式转换 bool ok; double d; d=QString("1234.56e-02").toDouble(&ok); //ok=true;d;12.3456. 把QString转换为float形 1.QString str="123.45&qu