有關座標和適配的問題往往讓人髮指,最近項目對worldtoNode,nodetoworld搞的我頭都大了好多圈,加上ancher和適配,筆者都快瘋了,這裏準備做個系類,把這裏的東西屢一下,整理個文檔。
先從座標系和錨點開始。這裏想提醒讀者,這部分看似簡單,其實挺混亂的,而且相當重要。
coco2dx中涉及四種座標
GL座標系:
Cocos2D以OpenglES爲圖形庫,所以它使用OpenglES座標系。GL座標系原點在屏幕左下角,x軸向右,y軸向上。
屏幕座標:
系蘋果的Quarze2D使用的是不同的座標系統,原點在屏幕左上角,x軸向右,y軸向下。ios的屏幕觸摸事件CCTouch傳入的位置信息使用的是該座標系。因此在cocos2d中對觸摸事件做出響應前需要首先把觸摸點轉化到GL座標系。可以使用CCDirector的convertToGL來完成這一轉化。
世界座標系:
也叫做絕對座標系。世界座標系和GL座標系一致,原點在屏幕左下角。
本地座標系:
本地座標系也叫做物體座標系,是和特定物體相關聯的座標系(父節點)
其實GL座標和世界座標是一樣的,屏幕座標對於使用cocos2dx的開發者而言大部分時間可以無視,那麼其實需要大家理解的就是——世界座標,本地座標。
本地座標是相對於父節點而言的座標,例如在一個CCLayer中添加一個CCSprite,此時setPosition設置的就是相對CCLaye的本地座標。在渲染的過程中會將本地座標變成世界座標,所以我們很難發現其實我們設置的是相對座標。那麼相對座標究竟是什麼座標?世界座標是以屏幕坐下角爲(0,0),x軸向右,y軸向上的座標,本地座標則是以其父節點座標爲(0,0),x軸向右,y軸向上的座標。帶入個場景:
一個Layer裏添加一個sprite,設置layer座標爲(100,100),sprite座標(0,0)
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !CCLayer::init() )
{
return false;
}
<span style="white-space:pre"> </span>//this->setPosition(ccp(100,100));
// add "HelloWorld" splash screen"
CCSprite* pSprite = CCSprite::create("HelloWorld.png");
pSprite->setScale(0.5f);
pSprite->setPosition(ccp(0,0));
this->addChild(pSprite, 1);
return true;
}
然後放開註釋,this->setPosition(ccp(100,100))
相信大家有些理解相對座標了,在不設置layer座標的情況下layer座標(0,0),sprite的setposition(0,0)與世界座標一樣,都是坐下角爲原點。但是layer座標變爲(100,100)之後,sprite座標就變成了父節點layer的座標(100,100)爲原點的相對座標位置。
cocos2dx在這裏提供了2個方法,將世界座標與本地座標相對轉化,只不過有點坑的是你需要知道世界座標與父節點的座標。
CCRect pRect = pSprite->boundingBox();
pRect.origin = pSprite->convertToWorldSpace(ccp(0,0));
if(pRect.containsPoint(ccp(x,y)))
{
CCLOG("監測到點擊精靈事件");
CCActionInterval* anim = CCMoveTo::create(1.0f,ccp(x,y));
pSprite->runAction(anim);
}
如果運行以上代碼,如果sprite的父節點座標爲(0,0),那麼精靈會點擊的時候移動到點擊位置,如果不是(0,0),那麼恭喜你,精靈會移動到想都想不到的地方。怎麼解決?我的方法是使用moveBy,計算點擊位置與精靈位置的矢量差,通過moveBy移動。
接下來咱們說說錨點:
這是一個難以理解的東西,什麼是錨點?這個不好說,還是看看下邊的例子吧。
首先ignoreAnchorPointForPosition這個東西,很神奇,先看看設置爲false的情況。
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !CCLayer::init() )
{
return false;
}
// add "HelloWorld" splash screen"
CCSprite* pSprite = CCSprite::create("HelloWorld.png");
pSprite->setScale(0.5f);
pSprite->setPosition(ccp(0,0));
pSprite->ignoreAnchorPointForPosition(false);
pSprite->setAnchorPoint(ccp(0,0));
CCPoint point = this->getAnchorPoint();
this->addChild(pSprite, 1);
//initScroll();
return true;
}
pSprite->setAnchorPoint(ccp(0.5,0.5));
在ignoreAnchorPointForPosition(false);的情況下,設置錨點可以這樣理解,設置位置就是設置錨點的位置,當錨點爲(0,0)的時候,圖片的左下角爲錨點,圖片左下角與設置位置重合。當錨點爲(0.5,0.5)時候,圖片的中點爲錨點,設置位置(0,0)就是圖片中點位置爲(0,0)。
在說說ignoreAnchorPointForPosition(true)的情況,設置錨點爲(0.5,0.5),運行後如下
這是什麼情況? 我們先命名一個變量:父子點,父節點提供給子節點的座標系原點。經過測試,設置爲ture之後,設置子節點錨點時父子點一同被設置,父節點的父子點和sprite的錨點都被設置到了中點上,所以當setPosition爲(0.5,0.5),sprite位置(0,0)的時候,就是父節點的父子點與sprite的錨點重合,得到如上情況。
總結一下:所謂的設置位置,用的都是本地座標,設置的是相對位置。設置位置就是設置父子點與子錨點之間的相對位置關係。錨點從0-1,及從左到右,從下到上。默認情況下父子點位置爲父節點左下角。默認情況下ignoreAnchorPointForPosition爲FALSE,錨點爲(0.5,0.5)