Cocos2d-x坐標研究
GL坐標系
Cocos2D以OpenglES為圖形庫,所以它使用OpenglES坐標系。GL坐標系原點在屏幕左下角,x軸向右,y軸向上。
屏幕坐標系
蘋果的Quarze2D使用的是不同的坐標系統(tǒng),原點在屏幕左上角,x軸向右,y軸向下。ios的屏幕觸摸事件CCTouch傳入的位置信息使用的是該坐標 系。因此在cocos2d中對觸摸事件做出響應前需要首先把觸摸點轉化到GL坐標系。可以使用CCDirector的convertToGL來完成這一轉化。
世界坐標系
世界坐標系也叫做絕對坐標系,是游戲開發(fā)中的概念,它建立了描述其他坐標系所需要的參考框架。我們能夠用世界坐標系來描述其他坐標系的位置,而不能用更大的,外部的坐標系來描述世界坐標系。cocos2d中的元素是有父子關系的層級結構,我們通過CCNode的position設定元素的位置使用的是相對 與其父節(jié)點的本地坐標系而非世界坐標系。***在繪制屏幕的時候cocos2d會把這些元素的本地坐標映射成世界坐標系坐標。世界坐標系和GL坐標系一致, 原點在屏幕左下角,x軸向右,y軸向上。
本地坐標系
本地坐標系也叫做物體坐標系,是和特定物體相關聯(lián)的坐標系。每個物體都有它們獨立的坐標系,當物體移動或改變方向時,和該物體關聯(lián)的坐標系將隨之移動或改變方向。例如坐出租車的時候對駕駛員說“向左轉”,我們使用的是車的物體坐標系,“前”、“后”、“左”、“右”只有在物體坐標系中才有意義。但如果我們說 “向東開”,我們使用的就是世界坐標系了,無論是車內(nèi)還是車外的人都知道應該向什么方向開。CCNode的position使用的就是父節(jié)點的本地坐標 系,它和GL坐標系也是一致的,x軸向右,y軸向上,原點在父節(jié)點的左下角。如果父節(jié)點是場景樹中的頂層節(jié)點,那么它使用的本地坐標系就和世界坐標系重合了。在CCNode對象中有幾個方便的函數(shù)可以做坐標轉換:convertToWorldSpace方法可以把基于當前節(jié)點的本地坐標系下的坐標轉換到世 界坐標系中。convertToNodeSpace方法可以把世界坐標轉換到當前節(jié)點的本地坐標系中。注意這些方法轉換的是基于當前節(jié)點的坐標,而一個節(jié) 點的position所使用的坐標是基于它父節(jié)點的本地坐標,因此我們要把node的位置轉換到世界坐標系中應該調(diào)用父節(jié)點的 convertToWorldSpace函數(shù) node->getParent()->convertToWorldSpace(node->getPosition)。幾 乎所有的游戲引擎都會使用本地坐標系而非世界坐標系來指定元素的位置,這樣做的好處是當計算物體運動的時候使用同一本地坐標系的元素可以作為一個子系統(tǒng)獨 立計算,***再加上坐標系的運動即可,這是物理研究中常用的思路。例如一個在行駛的車廂內(nèi)上下跳動的人,我們只需要在每幀繪制的時候計算他在車廂坐標系中 的位置,然后加上車的位置就可以計算出人在世界坐標系中的位置,如果使用單一的世界坐標系,人的運動軌跡就變復雜了。
錨點
每一個CCNode都有一個錨點(anchorpoint),錨點指定了texture上和所在節(jié)點原點(也就是position所表示的點)重合的點的位 置,因此只有在節(jié)點使用了texture的情況下,錨點才有意義。錨點的默認值是(0.5,0.5),它表示的并不是一個像素點,而是一個乘數(shù)因子。 (0.5, 0.5)表示錨點位于texture長度乘以0.5和寬度乘以0.5的地方,即texture的中心。改變錨點的值并不會改變節(jié)點的位置 (position),雖然可能看起來節(jié)點的圖像位置發(fā)生了變化,其實變化的只是texture相對于position的位置,相當于你在移動節(jié)點里面的 texture,而非節(jié)點本身。如果把錨點設置成(0,0),texture的左下角就會和節(jié)點的position點重合,這可能使得元素定位更為方便, 但會影響到元素的縮放和旋轉等一系列變換,所以不推薦這么做。因此在錨點為默認值(0.5,0.5)的情況下要把一個精靈放置到屏幕底部中央,應該如下設 置position:
- [plain] view plaincopy CGSize screenSize = [[CCDirectorsharedDirector] winSize];
- float imageHeight = player.contentSize.height;
- player.position = CGPointMake(screenSize.width / 2,imageHeight / 2);
個人研究
今天晚上,對cocos2d-x里面的四個表示坐標的方法進行了一下研究,特意做了下筆記,如下:
CCPoint convertToNodeSpace(const CCPoint& worldPoint);
CCPoint convertToWorldSpace(const CCPoint& nodePoint);
CCPoint convertToNodeSpaceAR(const CCPoint& worldPoint);
CCPoint convertToWorldSpaceAR(const CCPoint& nodePoint);
在理解這個之前,要多世界坐標和本地坐標有一定的理解,
GL坐標系Cocos2D以OpenglES為圖形庫,所以它使用OpenglES坐標系。GL坐標系原點在屏幕左下角,x軸向右,y軸向上。
屏幕坐標系蘋果的Quarze2D使用的是不同的坐標系統(tǒng),原點在屏幕左上角,x軸向右,y軸向下。ios的屏幕觸摸事件CCTouch傳入的位置信息使用的是該坐標 系。因此在cocos2d中對觸摸事件做出響應前需要首先把觸摸點轉化到GL坐標系??梢允褂肅CDirector的convertToGL來完成這一轉化。
世界坐標系也叫做絕對坐標系,cocos2d中的元素是有父子關系的層級結構,我們通過CCNode的position設定元素的位置使用的是相對與其父節(jié)點的本地坐標系而非世界坐標系。***在繪制屏幕的時候cocos2d會把這些元素的本地坐標映射成世界坐標系坐標。世界坐標系和GL坐標系一致,原點在屏幕左下角,
本地坐標系本 地坐標系也叫做物體坐標系,是和特定物體相關聯(lián)的坐標系。每個物體都有它們獨立的坐標系,當物體移動或改變方向時,和該物體關聯(lián)的坐標系將隨之移動或改變 方向。比如用cocos2d-x創(chuàng)建了個矩形colorLayer:CCRect(10,10,100,100),這是的本地坐標系為以(10,10)為 坐標原點,x軸向右,y軸向上。如果創(chuàng)建了一個CCSprite,錨點為(0.5,0.5),位置為(100,100),size為(40,40),這時的本地坐標系為以(80,80)為坐標原點,x軸向右,y軸向上??傊?,本地坐標系原點為node的左下角坐標
接下來,convertToNodeSpace:調(diào)用CCPoint point = node1->convertToNodeSpace(node2->getPosition());
將node2的坐標轉化成相對于node1的本地坐標
比如坐標如上圖所示,node1的錨點為(0,0),node2的錨點為(1,1),轉化之后,node的坐標變成了(-25,-60)
下頁為您接續(xù)帶來Cocos2d-x個人研究
#p#
而convertToWorldSpace:調(diào)用CCPoint point = node1->convertToWorldSpace(node2->getPosition());
是將node的坐標轉化成相對于node1的世界坐標,如上圖所示:首先將node1的坐標當做世界坐標,然后讓node2的坐標位置重置成相對于node1的世界坐標,也就是(15,20)
convertToNodeSpaceAR,就是把node1的坐標系原點設置在錨點的位置,這里的錨點是(0,0)所以轉化之后的坐標系位置和上面的convertToNodeSpace一樣,結果也是一樣的,convertToWorldSpaceAR同理
測試:
CCSprite *sprite1 = CCSprite::spriteWithFile("CloseNormal.png");
sprite1->setPosition(ccp(20,40));
sprite1->setAnchorPoint(ccp(0,0));
this->addChild(sprite1);
CCSprite *sprite2 = CCSprite::spriteWithFile("CloseNormal.png");
sprite2->setPosition(ccp(-5,-20));
sprite2->setAnchorPoint(ccp(1,1));
this->addChild(sprite2);
CCPoint point1 = sprite1->convertToNodeSpace(sprite2->getPosition());
CCPoint point2 = sprite1->convertToWorldSpace(sprite2->getPosition());
CCPoint point3 = sprite1->convertToNodeSpaceAR(sprite2->getPosition());
CCPoint point4 = sprite1->convertToWorldSpaceAR(sprite2->getPosition());
CCLog("position = (%f,%f)",point1.x,point1.y);
CCLog("position = (%f,%f)",point2.x,point2.y);
CCLog("position = (%f,%f)",point3.x,point3.y);
CCLog("position = (%f,%f)",point4.x,point4.y);
運行結果:
position = (-25.000000,-60.000000)
position = (15.000000,20.000000)
position = (-25.000000,-60.000000)
position = (15.000000,20.000000)
和預算的一樣
這里在將sprite1的錨點設置成(0.5,0.5),對convertToNodeSpaceAR和convertToWorldSpaceAR進行了進一步的測試
sprite1->setAnchorPoint(ccp(0.5,0.5));
sprite1->setPosition(ccp(100,100));
CCPoint point5 = sprite1->convertToNodeSpaceAR(sprite2->getPosition());
CCPoint point6 = sprite1->convertToWorldSpaceAR(sprite2->getPosition());
CCLog("position = (%f,%f)",point5.x,point5.y);
CCLog("position = (%f,%f)",point6.x,point5.y);
運算結果:
size = (40.000000,40.000000)
position = (-105.000000,-120.000000)
position = (95.000000,80.000000)
分析:重置的sprite1的坐標為(100,100),錨點為(0.5,0.5)所以對于convertToNodeSpaceAR和convertToWorldSpaceAR這兩個方法的坐標系為原點(100,100),所以用convertToNodeSpaceAR轉化之后的坐標為(-105,-120)用convertToWorldSpaceAR化之后的坐標為(95,80),和運算結果一樣