Cocos2d-x 3.0座標系詳解

原本地址:http://www.cocos2d-x.org/docs/manual/framework/native/v3/coordinate-system/zh

Cocos2d-x座標系和OpenGL座標系相同,都是起源於笛卡爾座標系。

笛卡爾座標系

笛卡爾座標系中定義右手系原點在左下角,x向右,y向上,z向外,OpenGL座標系爲笛卡爾右手系。

RightHand

屏幕座標系和Cocos2d座標系

標準屏幕座標系使用和OpenGL不同的座標系,而Cocos2d則使用和OpenGL相同的座標系。

iOS, Android, Windows Phone等在開發應用時使用的是標準屏幕座標系,原點爲屏幕左上角,x向右,y向下。

Cocos2d座標系和OpenGL座標系一樣,原點爲屏幕左下角,x向右,y向上。

UICoordinate

在開發中,我們經常會提到兩個比較抽象的概念-世界座標系和本地座標系。這兩個概念可以幫助我們更好的理解節點在Cocos2d座標系中的位置以及對應關係。

世界座標系(World Coordinate) VS 本地座標系(Node Local)

世界座標系也叫做絕對座標系,是遊戲開發中建立的概念。因此,“世界”指遊戲世界。cocos2d中的元素是有父子關係的層級結構,我們通過Node的setPosition設定元素的位置使用的是相對與其父節點的本地座標系而非世界座標系。最後在繪製屏幕的時候cocos2d會把這些元素的本地座標映射成世界座標系座標。

本地座標系也叫相對座標系,是和節點相關聯的座標系。每個節點都有獨立的座標系,當節點移動或改變方向時,和該節點關聯的座標系將隨之移動或改變方向。

錨點(Anchor Point)

將一個節點添加到父節點裏面時,需要設置其在父節點上的位置,本質上是設置節點的錨點在父節點座標系上的位置。

  • Anchor Point的兩個參數都在0~1之間。它們表示的並不是像素點,而是乘數因子。(0.5, 0.5)表示Anchor Point位於節點長度乘0.5和寬度乘0.5的地方,即節點的中心

  • 在Cocos2d-x中Layer的Anchor Point爲默認值(0, 0),其他Node的默認值爲(0.5, 0.5)。

我們用以下代碼爲例,使用默認Anchor Point值,將紅色層放在屏幕左下角,綠色層添加到紅色層上:

auto red = LayerColor::create(Color4B(255, 100, 100, 128), visibleSize.width/2, visibleSize.height/2);

auto green = LayerColor::create(Color4B(100, 255, 100, 128), visibleSize.width/4, visibleSize.height/4);

red->addChild(green);

this->addChild(red, 0);

anchorPoint

我們用以下代碼爲例,將紅色層的Anchor Point設爲中點放在屏幕中央,綠色層添加到紅色層上,綠色層錨點爲右上角:

注:因爲Layer比較特殊,它默認忽略錨點,所以要調用ignoreAnchorPointForPosition()接口來改變錨點,關於ignoreAnchorPointForPosition()接口的使用說明,我們將在後面詳細講解。

auto red = LayerColor::create(Color4B(255, 100, 100, 128), visibleSize.width/2, visibleSize.height/2);
red->ignoreAnchorPointForPosition(false);
red->setAnchorPoint(Point(0.5, 0.5));
red->setPosition(Point(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

auto green = LayerColor::create(Color4B(100, 255, 100, 128), visibleSize.width/4, visibleSize.height/4);
green->ignoreAnchorPointForPosition(false);
green->setAnchorPoint(Point(1, 1));
red->addChild(green);

this->addChild(red, 0);

anchorPoint

忽略錨點(Ignore Anchor Point)

Ignore Anchor Point全稱是ignoreAnchorPointForPosition,作用是將錨點固定在一個地方。

如果設置其值爲true,則圖片資源的Anchor Pont固定爲左下角,否則即爲所設置的位置。

我們用以下代碼爲例,將兩個層的ignoreAnchorPointForPosition設爲true,並將綠色的層添加到紅色的層上:

auto red = LayerColor::create(Color4B(255, 100, 100, 128), visibleSize.width/2, visibleSize.height/2);
red->ignoreAnchorPointForPosition(true);
red->setPosition(Point(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

auto green = LayerColor::create(Color4B(100, 255, 100, 128), visibleSize.width/4, visibleSize.height/4);
green->ignoreAnchorPointForPosition(true);

red->addChild(green);

this->addChild(red, 0);

ignore

VertexZ,PositionZ和zOrder

  • VerextZ是OpenGL座標系中的Z值
  • PositionZ是Cocos2d-x座標系中Z值
  • zOrder是Cocos2d-x本地座標系中Z值

在實際開發中我們只需關注zOrder。

可以通過setPositionZ接口來設置PositionZ。

以下是setPositionZ接口的說明:

Sets the 'z' coordinate in the position. It is the OpenGL Z vertex value.

即PositionZ的值即爲opengl的z值VertexZ。同樣節點的PositionZ也是決定了該節點的渲染順序,值越大,但是與zOrder不同的區別在於,PositionZ是全局渲染順序即在根節點上的渲染順序,而zOrder則是局部渲染順序,即該節點在其父節點上的渲染順序,與Node的層級有關。用以下事例來說明:

    auto red = LayerColor::create(Color4B(255, 100, 100, 255), visibleSize.width/2, visibleSize.height/2);
    red->ignoreAnchorPointForPosition(false);
    red->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2));

    auto green = LayerColor::create(Color4B(100, 255, 100, 255), visibleSize.width/4, visibleSize.height/4);
    green->ignoreAnchorPointForPosition(false);
    green->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2 - 100));
    red->setPositionZ(1);
    green->setPositionZ(0);
    this->addChild(red, 0);
    this->addChild(green, 1);

zOrder

雖然green的zOrder大於red的zOder,但是因爲red的PositionZ較大,所以red還是在green上面顯示。

觸摸點(Touch position)

所以在處理觸摸事件時需要用重寫以下四個函數:

    virtual bool onTouchBegan(Touch *touch, Event * event);
    virtual void onTouchEnded(Touch *touch, Event * event);
    virtual void onTouchCancelled(Touch *touch, Event * event);
    virtual void onTouchMoved(Touch *touch, Event * event);

在函數中獲取到touch,我們在設計遊戲邏輯時需要用到觸摸點在Cocos2d座標系中的位置,就需要將touch的座標轉換成OpenGL座標系中的點座標。

Touch position是屏幕座標系中的點,OpenGL position是Cocos2d-x用到的OpenGL座標系上的點座標。通常我們在開發中會使用兩個接口getLocation()getLocationInView()來進行相應座標轉換工作。

在開發中一般使用getLocation()獲取觸摸點的GL座標,而getLocation()內部實現是通過調用Director::getInstance()->convertToGL(_point);返回GL座標。

此外,關於世界座標系和本地座標系的相互轉換,在Node中定義了以下四個常用的座標變換的相關方法。

    // 把世界座標轉換到當前節點的本地座標系中
    Point convertToNodeSpace(const Point& worldPoint) const;

    // 把基於當前節點的本地座標系下的座標轉換到世界座標系中
    Point convertToWorldSpace(const Point& nodePoint) const;

    // 基於Anchor Point把基於當前節點的本地座標系下的座標轉換到世界座標系中
    Point convertToNodeSpaceAR(const Point& worldPoint) const;

    // 基於Anchor Point把世界座標轉換到當前節點的本地座標系中
    Point convertToWorldSpaceAR(const Point& nodePoint) const;

下面通過一個例子來說明這四個方法的理解和作用:

    auto *sprite1 = Sprite::create("HelloWorld.png");
    sprite1->setPosition(ccp(20,40));
    sprite1->setAnchorPoint(ccp(0,0));
    this->addChild(sprite1);  //此時添加到的是世界座標系,也就是OpenGL座標系

    auto *sprite2 = Sprite::create("HelloWorld.png");
    sprite2->setPosition(ccp(-5,-20));
    sprite2->setAnchorPoint(ccp(1,1));
    this->addChild(sprite2); //此時添加到的是世界座標系,也就是OpenGL座標系

    //將 sprite2 這個節點的座標ccp(-5,-20) 轉換爲 sprite1節點 下的本地(節點)座標系統的 位置座標
    Point point1 = sprite1->convertToNodeSpace(sprite2->getPosition());

    //將 sprite2 這個節點的座標ccp(-5,-20) 轉換爲 sprite1節點 下的世界座標系統的 位置座標
    Point point2 = sprite1->convertToWorldSpace(sprite2->getPosition());

    log("position = (%f,%f)",point1.x,point1.y);
    log("position = (%f,%f)",point2.x,point2.y);
運行結果:

Cocos2d: position = (-25.000000,-60.000000)
Cocos2d: position = (15.000000,20.000000)

convert1

convert2

其中:Point point1 = sprite1->convertToNodeSpace(sprite2->getPosition());

相當於sprite2這個節點添加到(實際沒有添加,只是這樣理解)sprite1這個節點上,那麼就需要使用sprite1這個節點的節點座標系統,這個節點的節點座標系統的原點在(20,40),而sprite1的座標是(-5,-20),那麼經過變換之後,sprite1的座標就是(-25,-60)。

其中:Point point2 = sprite1->convertToWorldSpace(sprite2->getPosition());

此時的變換是將sprite2的座標轉換到sprite1的世界座標系下,而其中世界座標系是沒有變化的,始終都是和OpenGL等同,只不過sprite2在變換的時候將sprite1作爲了”參照“而已。所以變換之後sprite2的座標爲:(15,20)。

convert3

 

發佈了21 篇原創文章 · 獲贊 6 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章