閱讀323 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Cocos2d-x坐標係介紹

在圖形圖像和遊戲應用開發中坐標係是非常重要的我們在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 HelloWorld::init()
{
   
    if( !Layer::init() )
    {
         returnfalse;
    }
 
    SizevisibleSize = Director::getInstance()->getVisibleSize();
    Pointorigin = Director::getInstance()->getVisibleOrigin();
    autocloseItem = MenuItemImage::create(
         "CloseNormal.png",
         "CloseSelected.png",
         CC_CALLBACK_1(HelloWorld::menuCloseCallback,this));
 
    closeItem->setPosition(Point(origin.x+ visibleSize.width - closeItem->getContentSize().width/2 ,
         origin.y+ closeItem->getContentSize().height/2));
 
    automenu = Menu::create(closeItem, NULL);
    menu->setPosition(Point::ZERO);
    this->addChild(menu,1);
    //創建背景
    autobg = Sprite::create("bg.png");                                                                                         ①
    bg->setPosition(Point(origin.x+ visibleSize.width/2,
         origin.y+ visibleSize.height/2));
 
    this->addChild(bg,0);                                                                                                                      ②
    //創建Node1
    autonode1 = Sprite::create("node1.png");                                                                           ③
    node1->setPosition(Point(400,500));
    node1->setAnchorPoint(Point(1.0,1.0));
 
    this->addChild(node1,0);                                                                                                               ④
    //創建Node2
    autonode2 = Sprite::create("node2.png");                                                                           ⑤
    node2->setPosition(Point(200,300));         
    node2->setAnchorPoint(Point(0.5,0.5));
 
    this->addChild(node2,0);                                                                                                               ⑥
 
    PointPoint1 = node1->convertToNodeSpace(node2->getPosition());                                      ⑦
    PointPoint3 = node1->convertToNodeSpaceAR(node2->getPosition());                                 ⑧
   
    log("Node2NodeSpace = (%f,%f)",Point1.x,Point1.y);
    log("Node2NodeSpaceAR = (%f,%f)",Point3.x,Point3.y);
 
    returntrue;
}

代碼①~②行是創建背景精靈對象這個背景是一個白色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像素。

編寫代碼如下

bool HelloWorld::init()
{
    if( !Layer::init() )
    {
         returnfalse;
    }
 
    SizevisibleSize = Director::getInstance()->getVisibleSize();
    Pointorigin = Director::getInstance()->getVisibleOrigin();
 
    autocloseItem = MenuItemImage::create(
         "CloseNormal.png",
         "CloseSelected.png",
         CC_CALLBACK_1(HelloWorld::menuCloseCallback,this));
 
    closeItem->setPosition(Point(origin.x+ visibleSize.width - closeItem->getContentSize().width/2 ,
         origin.y+ closeItem->getContentSize().height/2));
 
    automenu = Menu::create(closeItem, NULL);
    menu->setPosition(Point::ZERO);
    this->addChild(menu,1);
 
    //創建背景
    autobg = Sprite::create("bg.png");
    bg->setPosition(Point(origin.x+ visibleSize.width/2,
         origin.y+ visibleSize.height/2));
    this->addChild(bg,0);
 
    //創建Node1
    autonode1 = Sprite::create("node1.png");
    node1->setPosition(Point(400,500));
    this->addChild(node1,0);
 
    //創建Node2
    autonode2 = Sprite::create("node2.png");
    node2->setPosition(Point(0.0,0.0));                                                                                              ①
    node2->setAnchorPoint(Point(0.0,0.0));                                                                              ②
    node1->addChild(node2,0);                                                                                                 ③
 
    PointPoint2 = 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);
 
    returntrue;
}

上述代碼我們主要關注第③行它是將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同為計算機繪圖軟件和計算機遊戲最常使用的兩套繪圖編程接口之一。—— 引自於維基百科 https://zh.wikipedia.org/wiki/Direct3D

更多內容請關注最新Cocos圖書《Cocos2d-x實戰 C++卷》
本書交流討論網站https://www.cocoagame.net
更多精彩視頻課程請關注智捷課堂Cocos課程https://v.51work6.com
歡迎加入Cocos2d-x技術討論群257760386


《Cocos2d-x實戰 C++卷》現已上線各大商店均已開售

京東https://item.jd.com/11584534.html

亞馬遜https://www.amazon.cn/Cocos2d-x%E5%AE%9E%E6%88%98-C-%E5%8D%B7-%E5%85%B3%E4%B8%9C%E5%8D%87/dp/B00PTYWTLU

當當https://product.dangdang.com/23606265.html

互動出版網https://product.china-pub.com/3770734

《Cocos2d-x實戰 C++卷》源碼及樣章下載地址

源碼下載地址https://51work6.com/forum.php?mod=viewthread&tid=1155&extra=page%3D1 

樣章下載地址https://51work6.com/forum.php?mod=viewthread&tid=1157&extra=page%3D1

歡迎關注智捷iOS課堂微信公共平台

最後更新:2017-04-03 12:56:32

  上一篇:go Cracking the coding interview
  下一篇:go CareerCup之1.2C風格字符串翻轉