cocos2dx學習之路----第七篇(座標系統中本地座標與世界座標的轉換詳解)
這一篇我們來談談關於座標系統中本地座標與世界座標的轉換問題。
在上一篇中我們知道了標準的螢幕座標系、本地座標與世界座標的區別,還了解了關於cocos2dx的座標系問題。
其實關於OpenGL的座標,如果我們做2d程式設計,是可以暫時忽略Z軸座標的。但是卻需要記住的是渲染的深度問題,即Z_Older的值,這個值越大,其渲染出的圖將會越在上面。關於這個值暫時記住就行。
在進入正題之前,我們需要知道什麼是錨點?
錨點其實就是關於變換的參考點,比如旋轉,平移縮放等。
錨點被規範化了,就像百分比一樣,(0,0)意味著在節點的左下角,而(1,1)就在節點的右上角,你可以改變錨點的值在(0,0)到(1,1)範圍內。
預設的錨點為(0.5,0.5),即中心點。
值得注意的是,如果這個節點是一個物理節點(physics body),它的錨點被固定在中間(in the middle),不可以改變。
我們來看一張圖片:
如果我們把錨點設定為A點,那麼,讓它順時針旋轉90°之後,變成了如下圖所示:
對每個Node節點都可以通過node->setAnthorPoint();來設定。
好了,下面進入正題吧~
Node物件給我們提供以下函式進行本地座標的和世界座標的轉換:
Vec2 convertToNodeSpace(const Vec2& worldPoint) const ;//將世界座標轉換為本地座標
Vec2 convertToWorldSpace(const Vec2& nodePoint) const;//將本地座標轉換為世界座標
Vec2 convertToNodeSpaceAR(const Vec2& worldPoint) const;//不忽略參考點錨點的情況下,將世界座標轉換為本地座標
Vec2 convertToWorldSpaceAR(const Vec2& nodePoint) const;//不忽略參考點錨點的情況下,將本地座標轉換為世界座標
Vec2 convertTouchToNodeSpace(Touch * touch) const;//將世界座標中的觸控點轉換為本地座標
Vec2 convertTouchToNodeSpaceAR(Touch * touch) const;//不忽略參考點錨點的情況下,將世界座標中的觸控點轉換為本地座標
這些函式都會返回一個值,這個值便是轉換後坐標點的值,即返回一個型別為Vec2的點。
這裡我們就只講一下前面四個函式的轉換問題。
將世界座標轉換為本地座標,這個會比較簡單一點。我們先來看下下面的執行圖:
我就不先貼程式碼出來,先來講講它們是如何轉換的,表格是它們的相關資訊:
屬性 方塊 |
錨點 |
位置 |
寬度 |
高度 |
Block1 |
(1,1) |
(300,300) |
200 |
200 |
Block2 |
(0,0) |
(0,0) |
100 |
100 |
我們把方塊Block2以方塊Block1為參考點從方塊Block1為本地座標中轉換為世界座標,轉換的過程是:
第一種情況,在不考慮參考點錨點的前提下,轉換後點的座標 = 父節點的座標 + 子節點在父節點的座標
所以,轉換之後的點的值為:(100,100)+(0,0) =(100,100)
實現程式碼如下:
Vec2 ConvertPoint = Block1->convertToNodeSpace(Block2->getPosition());
第二種情況,在考慮點錨點的前提下,轉換後的點座標 = 父節點的座標 + 子節點的座標 + 父節點錨點位置點*父節點實際大小
所以,轉換之後的點的值為:(100,100)+ (0,0)+(1,1) * (200,200) = (300,300)
實現程式碼如下:
Vec2 ConvertPoint = Block1->convertToNodeSpaceAR(Block2->getPosition());
以上是本地座標轉換為世界座標的實現。
現在來看看怎麼由世界座標轉換為本地座標,同樣我我們先來看下執行圖:
屬性 方塊 |
錨點 |
位置 |
寬度 |
高度 |
Block1 |
(1,1) |
(100,100) |
100 |
100 |
Block2 |
(0,0) |
(100,100) |
100 |
100 |
現在,我們可以以方塊Block1為參考點把方塊Block2轉化為方塊Block1的本地座標。
思路也是和上面差不多,轉換的過程如下:
第一種情況,不考慮參考點錨點的前提下,轉換後的座標 = 方塊Block2的座標 - 方塊Block1的左下角點的座標,
所以,轉換後點的座標 = (100,100)- (0,0) = (100,100)
實現程式碼如下:
Vec2 ConvertPoint = Block1->convertToNodeSpace(layer_block2->getPosition());
第二種情況,考慮參考點錨點的前提下,轉換後的座標 = 方塊Block2的座標 - 方塊Block1的左下角座標 - 錨點的位置點 * 方塊Block1的大小,
所以,轉換後點的座標 = (100,100)- (0,0) - (1,1) * (100,100) = (0,0)
Vec2 ConvertPoint = Block1->convertToNodeSpaceAR(layer_block2->getPosition());
好了,現在把上面的所有程式碼都貼出來吧~
ConvertCoordinateDemo.h:
#pragma once
#include"cocos2d.h"
USING_NS_CC;
class ConvertCoordinateDemo :public Layer{
public:
virtual bool init();
static Scene *createScene();
CREATE_FUNC(ConvertCoordinateDemo);
};
ConvertCoordinateDemo.cpp:#include"ConvertCoordinateDemo.h"
Scene *ConvertCoordinateDemo::createScene()
{
Scene* scene = Scene::create();
ConvertCoordinateDemo *layer = ConvertCoordinateDemo::create();
scene->addChild(layer);
return scene;
}
bool ConvertCoordinateDemo::init(){
if (!Layer::init()){
return false;
}
/*********************************************************
本地座標轉換為世界座標
************************************************************/
//方塊一
LayerColor *layer_block1 = LayerColor::create(Color4B::RED, 100, 100);
this->addChild(layer_block1);
layer_block1->ignoreAnchorPointForPosition(false);//不忽略錨點
layer_block1->setAnchorPoint(Vec2(1,1));
layer_block1->setPosition(Vec2(100, 100));
auto mark1 = Label::createWithSystemFont("Block1", "", 30);
mark1->setPosition(Vec2(50, 50));
layer_block1->addChild(mark1);
//方塊二
LayerColor *layer_block2 = LayerColor::create(Color4B::GREEN, 100, 100);
this->addChild(layer_block2);
layer_block2->ignoreAnchorPointForPosition(false);//層和場景都是忽略錨點的,預設為(0,0),這是設定不忽略錨點,即在中心點
layer_block2->setAnchorPoint(Vec2::ZERO);
layer_block2->setPosition(Vec2(100, 100));
auto mark2 = Label::createWithSystemFont("Block2", "", 30);
mark2->setPosition(Vec2(50, 50));
layer_block2->addChild(mark2);
auto Block2_convertToNodeSpace = layer_block1->convertToNodeSpace(layer_block2->getPosition());
auto Block2_convertToNodeSpaceAR = layer_block1->convertToNodeSpaceAR(layer_block2->getPosition());
log("Block2_convertToNodeSpace:_x = %f,_y = %f", Block2_convertToNodeSpace.x, Block2_convertToNodeSpace.y);
log("Block2_convertToNodeSpaceAR:_x = %f,_y = %f", Block2_convertToNodeSpaceAR.x, Block2_convertToNodeSpaceAR.y);
/*****************************************************************
世界座標轉換為本地座標
*******************************************************************/
//方塊一
//LayerColor *layer_block1 = LayerColor::create(Color4B::RED, 200, 200);
//this->addChild(layer_block1);
//layer_block1->ignoreAnchorPointForPosition(false);
//layer_block1->setAnchorPoint(Vec2(1,1));
//layer_block1->setPosition(Vec2(300, 300));
//auto mark1 = Label::createWithSystemFont("Block1", "", 50);
//mark1->setPosition(Vec2(100, 120));
//layer_block1->addChild(mark1);
//方塊二
//LayerColor *layer_block2 = LayerColor::create(Color4B::GREEN, 100, 100);
//layer_block1->addChild(layer_block2);
//layer_block2->ignoreAnchorPointForPosition(false);//層和場景都是忽略錨點的,預設為(0,0),這是設定不忽略錨點,即在中心點
//layer_block2->setAnchorPoint(Vec2::ZERO);
//layer_block2->setPosition(Vec2::ZERO);
//auto mark2 = Label::createWithSystemFont("Block2", "", 30);
//mark2->setPosition(Vec2(50, 50));
//layer_block2->addChild(mark2);
//auto Block2_convertToWorldSpace = layer_block1->convertToWorldSpace(layer_block2->getPosition());
//auto Block2_convertToWorldSpaceAR = layer_block1->convertToWorldSpaceAR(layer_block2->getPosition());
//log("Block2_convertToWorldSpace:_x = %f,_y = %f", Block2_convertToWorldSpace.x, Block2_convertToWorldSpace.y);
//log("Block2_convertToWorldSpaceAR:_x = %f,_y = %f", Block2_convertToWorldSpaceAR.x, Block2_convertToWorldSpaceAR.y);
return true;
}
說明一下,這裡的方塊是用一個顏色層來建立,而層和場景預設是忽略錨點的,預設為(0,0),所以,為了能夠重新設定層的錨點,我們先把層的設定為不忽略錨點,即呼叫ignoreAnchorPointForPosition()這個方法把它設定為false。其它的就不再多說了。希望能夠對你有所幫助,如果有什麼問題或是錯誤可以留下你的評論,我會很樂意為你解答的~
下一篇我會來談談關於cocos2dx裡面的觸控事件該如何實現。