Cocos2d-x坐标系介绍

原载:http://2009315319.blog.51cto.com/701759/1416619

本文在原载基础上理解增删



在图形图像和游戏应用开发中坐标系是非常重要的,我们在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像素。这里的坐标事实上就是世界坐标,它的坐标原点是屏幕的左下角。

编写代码如下:

bool Test::init()
{
    
    if( !Layer::init() )
    {
         return false;
    }
  
    Size visibleSize = Director::getInstance()->getVisibleSize();
    Point origin = Director::getInstance()->getVisibleOrigin();
    auto closeItem = MenuItemImage::create(
         "CloseNormal.png",
         "CloseSelected.png",
         CC_CALLBACK_1(Test::menuCloseCallback,this));
  
    closeItem->setPosition(Point(origin.x+ visibleSize.width - closeItem->getContentSize().width/2 ,
         origin.y+ closeItem->getContentSize().height/2));
  
    auto menu = Menu::create(closeItem, NULL);
    menu->setPosition(Point::ZERO);
    this->addChild(menu,1);
    //创建背景
    auto bg = Sprite::create("bg.jpg");          //①
    bg->setPosition(Point(origin.x+ visibleSize.width/2,
         origin.y+ visibleSize.height/2));
  
    this->addChild(bg,0);                    // ②
    //创建Node1
    auto node1 = Sprite::create("node1.jpg");// ③
    node1->setPosition(Point(400,500));
    node1->setAnchorPoint(Point(1.0,1.0));
  
    this->addChild(node1,0);                   //④
    //创建Node2
    auto node2 = Sprite::create("node2.jpg");  //⑤
    node2->setPosition(Point(200,300));         
    node2->setAnchorPoint(Point(0.5,0.5));
  
    this->addChild(node2,0);                    //⑥
  
    Point Point1 = node1->convertToNodeSpace(node2->getPosition());//⑦
    Point Point3 = node1->convertToNodeSpaceAR(node2->getPosition());//⑧
    
    log("Node2NodeSpace = (%f,%f)",Point1.x,Point1.y);
    log("Node2NodeSpaceAR = (%f,%f)",Point3.x,Point3.y);
  
    return true;
}

代码①~②行是创建背景精灵对象,这个背景是一个白色900 x 640像素的图片。

代码第③~④行是创建Node1对象,并设置了位置和锚点属性。

代码第⑤~⑥行是创建Node2对象,并设置了位置和锚点属性。

第⑦行代码将Node2的世界坐标转换为相对于Node1的节点坐标。

而第⑧行代码是类似的,它是相对于Node1锚点的节点坐标。

运行结果如下:

Node2 NodeSpace = (100.000000,-100.000000)

Node2 NodeSpaceAR =(-200.000000,-200.000000)


Point Point1 = node1->convertToNodeSpace(node2->getPosition());//⑦ Node2的世界坐标转换为相对于Node1的节点坐标

node2->getPosition(); 获得node2的坐标C点的世界坐标(200,300);

node1的节点坐标原点(0,0)即左下角A点;对应的世界坐标是(100,400);

以A点为原点的坐标系中获得C点的坐标:C点坐标-A点坐标:(200,300) - (100,400) = (100,-100);//x轴100,右方100;y轴-100,下方100



Point Point3 = node1->convertToNodeSpaceAR(node2->getPosition());//⑧

意思是将node1的锚点B点作为节点坐标系的原点,对应的世界坐标是(400,500);

以B点为原点的坐标系中获得C点的坐标:C点坐标-B点坐标:(200,300) - (400,500) = (-200,-200);//x轴-200,左方100;y轴-200,下方200



2、节点坐标转换为世界坐标

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



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

编写代码如下:

bool Test::init()
{
    
    if( !Layer::init() )
    {
         return false;
    }
  
    Size visibleSize = Director::getInstance()->getVisibleSize();
    Point origin = Director::getInstance()->getVisibleOrigin();
    auto closeItem = MenuItemImage::create(
         "CloseNormal.png",
         "CloseSelected.png",
         CC_CALLBACK_1(Test::menuCloseCallback,this));
  
    closeItem->setPosition(Point(origin.x+ visibleSize.width - closeItem->getContentSize().width/2 ,
         origin.y+ closeItem->getContentSize().height/2));
  
    auto menu = Menu::create(closeItem, NULL);
    menu->setPosition(Point::ZERO);
    this->addChild(menu,1);
    //创建背景
    auto bg = Sprite::create("bg.jpg");          
    bg->setPosition(Point(origin.x+ visibleSize.width/2,
         origin.y+ visibleSize.height/2));
  
    this->addChild(bg,0);                   
    //创建Node1
    auto node1 = Sprite::create("node1.jpg");
    node1->setPosition(Point(400,500));  
    this->addChild(node1,0);                  


    //创建Node2
    auto node2 = Sprite::create("node2.jpg"); 
    node2->setPosition(Point(0,0));         //①
    node2->setAnchorPoint(Point(0,0));   // ②
    node1->addChild(node2,0);             // ③ 
  
	Point Point2 = node1->convertToWorldSpace(node2->getPosition()); //④
	Point Point4 =node1->convertToWorldSpaceAR(node2->getPosition()); //⑤
  
  
    log("Node2WorldSpace = (%f,%f)",Point2.x,Point2.y);
    log("Node2WorldSpaceAR = (%f,%f)",Point4.x,Point4.y);
  
    return true;
}

上述代码我们主要关注第③行,它是将Node2放到Node1中,这是与之前的代码的区别。

这样第①行设置的坐标就变成了相对于Node1的节点坐标了。

第④行代码将Node2的节点坐标转换为世界坐标。

而第⑤行代码是类似的,它是相对于锚点的位置。

运行结果如下:

Node2 WorldSpace =(250.000000,450.000000)

Node2 WorldSpaceAR =(400.000000,500.000000)


Point Point2 = node1->convertToWorldSpace(node2->getPosition()); //④把node2在node1的节点坐标系中的坐标转换为世界坐标

node2->getPosition()得到的是node2在node1节点坐标系中的坐标(0,0)

node1坐标系的原点A转换为世界坐标为(250,450);

node2的节点坐标转换为世界坐标:(0,0) + (250,450) = (250,450);


 Point Point4 =node1->convertToWorldSpaceAR(node2->getPosition()); //⑤把node2在node1锚点为原点的坐标系中的坐标转换为世界坐标

node2->getPosition()得到的是node2在node1节点坐标系中的坐标(0,0)

node1锚点坐标系的原点B点转换为世界坐标为(400,500);

node2的节点坐标转换为世界坐标:(0,0) + (400,500) = (400,500);


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

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

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

this->addChild(node2, 0);


如果把node1的锚点设为(0.0,0.0);

可用世界坐标 node2->setPosition(Point(400, 500));

保持node2相对node1的位置不变






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值