第三章 cocos中級特性

3.1 菜單按鈕

菜單CCMenu只是提供了一個可以點擊的層,本質就是一個容器,用來裝菜單項,CCMenuItem是所有菜單項的父類,有下面5個子類

3.1.1 CCMenuItemFont 

  CCMenuItem * font=CCMenuItemFont::create("Start",this,menu_selector(T11Menu::menuCallBack));

3.1.2 CCMenuItemImage

  CCMenuItem * imageItem = CCMenuItemImage::create("CloseNormal.png", "CloseSelected.png");

3.1.3 CCMenuItemLabel

  CCMenuItem * labelItem = CCMenuItemLabel::create(bm, this, menu_selector(T11Menu::menuCallBack));

3.1.4 CCMenuItemSprite

  CCMenuItemSprite * spriteItem = CCMenuItemSprite::create(normal,selected, this, menu_selector(T11Menu::menuCallBack));

3.1.5 CCMenuItemToggle

  CCMenuItemToggle * toggle = CCMenuItemToggle::createWithTarget(this,  menu_selector(T11Menu::menuCallBack), t1, t2, t3, t4, NULL);

int idx = ((CCMenuItemToggle*)item)->getSelectedIndex();//獲取哪個菜單被選中

CCMenuCCMenuItem的錨點都是(0.5,0.5),menu的座標原點是中心點。爲了和其餘的一致,應該將座標原點設置爲左下角,menu在層上面封裝了很多函數。菜單項的原點是座標的窗口的中心,多個菜單項時,使用這個方法alignItemsVertically讓菜單項自動對齊,也可以自己來設置item的位置,alignItemsVerticallyWithPadding也可以自己設置中間的大小。另外一種menuCCMenuIteToggle,點擊的時候實現菜單項的轉換,比如開關,在構造之前需要先構造一個CCArray數組。

將在菜單項添加到menu層上,點擊一下字會變大,是CCMenu內部實現的。CCMenu的父類是CCLayer,本身也是一個層,並且定義了觸摸功能,並且優先級是-128,最高的優先級,其他的層不會捕獲消息。當menu層的優先級一樣的時候,最上層捕獲消息。

菜單可以設置回調函數setTarget,就是當鼠標點擊的時候如何處理,回調函數在轉換的時候用到了一個宏menu_selector,使代碼簡潔。菜單的響應是在鼠標按下之後彈起的時候調用的,在內部調用active來執行。如果希望在按下的時候就調用,這個時候可以重定義一個類,繼承自CCMenu,然後讓這個類,重寫一個觸摸函數,在CCTouchBegan的時候就處理觸摸,就是在裏面添加active方法即可。

3.2 課程菜單的製作

增加一個菜單Menu類,在這裏類裏面增加多個菜單項,在回調函數中處理,切換進入不同的場景。實現拖拽功能,首先註冊觸摸,在CCTouchmoved函數中添加下面的代碼,其實就是設置y軸座標

menu->setPositionY(menu->getPositionY() + pTouch->getDelta().y);

但是這樣的話可以無限的拖拽,應該在最上端和最下端menu進入窗口的時候,停止拖拽,CCMenuItem *)menu->getChildren()->objectAtIndex(0)。實現返回按鈕,可以添加一個Back類,然後讓每個類來繼承使用,這個類只有一個menu,返回到初始位置。但是,這樣改起來很麻煩,可以在切換場景的時候,在場景上面添加一個menu,這樣就不需要每個都改了。

replaceScene切換的時候,舊的scene內存會釋放。

教學程序的課程更改,加一個新的類,首先將其餘的頭文件加載過來,然後創建一個字符串數組,包含這些頭文件,然後創建一個menu,在這個menu上面添加多個menuitem。然後給這個menu實現觸摸的功能,這樣就可以拖動了。在moved的時候移動菜單,getDelta獲取偏移的距離,然後重新設置menu的位置即可。不希望無限向上向下觸摸。第一個菜單項位於了窗口就不再向上觸摸,最後一個菜單位於窗口也就不再向下觸摸。取出第一個的boundingBox,然後比較Y軸的座標是否在窗口內。這個時候注意座標體系的轉化,用的誰的座標體系就使用誰來調轉化函數。出來的時候顯示最上面的是T01,而不是放在中間,將菜單下移。在初始化的時候,找到偏移量,然後重新設置menu就可以了。下拉的時候有時候會漏出一些黑色,是因爲幀率比較卡。

這個時候就設好了,應該給每個menuitem設置一個回調函數,在這裏面切換場景。獲得nodetag之後,使用switch來處理,創建一個layer,然後加到場景中去。使用replaceScene來切換,啓動runwithScenepushScenepopScene是一對,用棧來維護,切換的時候不會釋放內存,而且場景狀態也會保留。這兩個函數不好操作,因爲耗費內存。很少使用,幫助和音量偶爾用到。這個時候給每一scene場景加一個按鈕,一種方法是創建一個類,這個類具有返回的功能,讓每一個類都繼承它,但是加起來很複雜,需要處理每個添加的類。給這個item註冊一個函數。將其設置在右下角。這個時候有個同學提了一個意見,在之前創建的scene上面加一個層即可,這樣處理起來就簡單多了。

切換的特效,CCTransition類都是特效類,第一個參數是時間,第二個參數是切換到那個場景。切換的特效類大概有38個。CCTransitionFade淡入淡出,CCTransitionPageTurn翻頁,給場景添加一個背景會清楚一點。CCTransition的原理是在場景切換的時候,舊的場景不能一下丟掉,添加進去的場景也不能一點顯示出來,就將舊場景和新的場景組合成爲一個新的場景,然後設置特效,等到結束的時候再去釋放舊的場景。

3.3 輸出控件

輸出控件lable,輸出在遊戲中很少用到,但是顯示分數的時候也會用到。文字輸出主要用到CCLableTTFCCLableAtlasCCLableBMFont這三個類。CCLableTTF父類是sprite,如果內容經常發生變化,需要渲染,效果不好,適合不變的顯示內容,而且跨平臺不適合,因爲需要在顯示的時候設置字體。可以使用這個做一個秒錶。

CCLabelTTF* label = CCLabelTTF::create("Label", "Arial", 24);

CCLableAtlas用到字符映射文件,字符要等寬等高,編碼是ASCII,並且顯示的字符在這個圖片中。磚塊,父類是node,對渲染做了優化,對於不斷變化的內容有利。對於不太規則的,有空白的文件,需要自己來設置字符的大小。如果顯示的內容不存在,就會顯示一個空隙。一次加載,可以多吃取用。

CCLabelAtlas*label2=CCLabelAtlas::create("100/.01","fonts/labelatlas2.png", 16, 30, '.');

CCLableBMFont也依賴ASCII表,是一個批處理精靈,裏面的內容是一個精靈,可以對每個精靈進行處理,使用objectAtIndex來獲取,有一個fnt文件來描述那個圖片文件,創建的時候更加自由。CCARRAY_FOREACH來遍歷CCArray數組,然後可以設置讓全部的精靈運動。

CCLabelBMFont*label3=CCLabelBMFont::create("ab","bitmap.fnt");

輸入控件CCEditBox,在手機上纔可以看到,需要用到頭文件cocos-ext.h,創建CCEditBox的時候需要用到九妹圖。手機上是彈出軟鍵盤,但是win下是彈出一個對話框。可以設置setPlaceHolder提示文字,也可以設置文件的顯示顏色,用ccColor3BccColor4Brgb,透明度),全是255變爲白色。使用getText獲取輸入的字符串。 

3.4 UI控件

UI 控件來自 cocos2dx 的擴展庫,完善了 UI 方面的元素,使 cocos2dx更加豐富多彩。

3.4.1 CCControlSlider滑動條

CCControlSlider * slider = CCControlSlider::create("sliderTrack.png","sliderProgress.png","sliderThumb.png");

slider->addTargetWithActionForControlEvents(this, cccontrol_selector(T12UI::controlCallback), CCControlEventValueChanged); //註冊響應函數

 CCControlSlider,也需要提供三個精靈,需要設置最大值和最小值,因爲默認是0.用來調節音量,也是設置一個回調函數來處理,在回調函數中調用的成員變量,之前需要創建好,否則會有bugv = slider->getValue()獲取活動條的值。在Windows下是設置音量無效的,因爲沒有寫代碼。

3.4.2 CCControlSwitch開關按鈕 

CCControlSwtich,需要提供四個精靈,實現開關的轉換。設置一個回調函數,來確定是開還是關,addTargetWithActionForControlEvents,用來監聽一些事件,數值發生變化的時候調用。在回調函數中,判斷是isOn,還是關閉,setOn設置默認值。可以用來打開和關閉音樂。

3.2.3 CCScale9Sprite  九妹圖

背景是使用一小塊圖片,通過拉伸,但是比例不一定,使得可以當做大的圖片來使用。九妹圖是將圖片分爲9部分,只擴展中間的部分,其餘的部分不變,正常的顯示在圖片的邊緣。正常的圖片拉伸之後,邊角比較模糊,但是九妹圖沒有那個情況,縮小的時候就達不到效果。九妹圖創建的時候,設置如何切割,有的時候效果不是很好,最好是默認的。

3.2.4 CCControlButton

 CCControlButton * button = CCControlButton::create(titlebutton,bgbutton);

button->setBackgroundSpriteForState(bgbuttonlighted, CCControlStateHighlighted); //設置背景高亮

3.5 幀循環-定時器

遊戲的本質就是不斷的繪圖,遊戲的主邏輯就是循環(循環的繪圖,定時處理事件和處理用戶輸入),主循環在CCDirector類的mainLoop函數,這是一個虛函數,在子類CCDisplayLinkDirctor類中重寫。在這個函數中調用drawScene函數,之後調用visit遍歷每個node,還有一個pool內存池管理。只要是CCNode派生的子類都可以設置定時器。

(1)幀循環定時器:scheduUpdate函數啓動幀定時器,啓動之後調用update回調函數,updateCCNode定義的虛函數,使用unschedualUpdate停止,停止也可以通過設置一個標誌flag來停止,當觸摸的時候flag變爲true,然後在update的函數中判斷。對實時性要求高的,比如碰撞檢測會用到幀循環定時器。

(2)自定義定時器:schedule參數是一個回調函數,可以設計隔多久調用,單位是秒,處理函數在回調函數中處理,回調函數是自定義的。unschedule停止某個回調函數。schedule還有一個參數較多的構造函數,功能更加強大。回調函數的參數,是這次和上次調用定時器的時間差,因爲存在誤差,比如一些跑酷遊戲,會越來越偏移,也會卡。儘量一個定時器對應一個回調函數。unscheduleAllSelectors停止所有的定時器。  

(3)一次性的定時器:scheduleOnce只用一次的定時器,用的比較少。schedule_selector是一個宏,經過了兩次包裝,得到的是函數的入口地址。

動畫的本質就是定時器+屬性的改變。幀循環實現來回巡邏,在幀循環提供一個速度,由於幀循環提供一個時間,通過setPositionX來設置X軸的位置,增加一個flag,當爲true的時候,X軸增加,到了一定距離之後改變flag;當爲false的時候,X軸減少。

3.6 碰撞檢測

精靈之間簡化的碰撞檢測:爲了防止遊戲變卡,簡化算法

外切矩形的碰撞檢測:intersectsRect

點和矩形之間的檢測:containsPoint

圓和圓之間的碰撞:getDistancegetDistanceSq(不用開根,效率高)

圓和點之間的碰撞:getDistanceSq

線段相交:ccpSegmentIntersect

直線檢測:ccpLineIntersect

穿透:預測下一個時刻會不會撞牆,如果遊戲變卡的時候,就會穿透過去。解決方案:如果dt很大,就丟棄,就不移動,幀循環丟棄;也可以不是檢測目標地點有沒有牆,而是檢測下一時刻移動的時候路途上有沒有牆。

3.7 數據結構

CCString萬能類型,可以轉換爲任意類型,在cocos3.x中是value

CCArray動態數組(二級指針),只能存儲CCObject及子類,如果保存CCPoint就會報錯。CCArray 是一個面向對象包裝類繼承至 CCObject。(insetObject效率低(會發生移動),addObject插入後面,removeObject刪除;遍歷的時候,可以使用objectAtIndex(i),遍歷的時候從後面遍歷到前面更加安全,因爲即使刪除也不會發生越界。CCArray 一般不會被增加到其他類中,所以他的引用計數是 1,並且設置爲autorelease 對象。創建 CCArray 對象並且 retain,然後在這個類中的析構函數中調用 release 方法來釋放內存。在cocos3.x中是vector

CCDictionary字典,很少用來插入數據,一般用來查找valueForKey,返回CCString類型,遍歷的時候,首先獲得allKeys,返回的是CCArray指針,也可以removeObjectForKey刪除數據。setObjectobjectForKey獲取數據,key的類型必須一致。中文顯示問題,支持中文顯示。在cocos3.x中是map

3.8 背景音樂和音效

需要包含SimpleAudioEngine頭文件,音效遊離於場景之外,是一個全局的,切換場景的時候要注意。播放音樂是一個單例,與音樂相關的頭文件位於CocosDenshion文件中。playBackgroudMusic音樂,playEffect音效,應該在播放之前將音樂緩衝下來preloadBackgroudMusicpreloadEffect,只有在手機下面預加載纔會顯現,電腦上顯示不出來。stopBackgroundMusic關閉音樂只會有一個,多個會發生混亂。stopEffect(id)關閉音效,id是由playEffect返回。pauseBackgroudMusic暫停,resumeBackgroudMusic恢復setBackgroudMusicVolume設置音量,unloadEffect卸載。

切換場景replaceScene。錯誤案例:在一個場景init的時候播放音效,在切換到另一個場景的時候打開音樂,在OnExit函數中關閉,然後在新場景的init函數中播放音樂。但是切換之後竟然沒有繼續播放。這是因爲在切換函數中播放下一個場景的音樂,但是其實這個時候這個場景並沒有結束,於是在onExit的時候調用關閉音樂的時候,將剛剛打開的音樂關閉了。所以在工作中,播放音樂在onEnter中播放,在onExit停止,這樣就會繼續播放,否則出現錯誤。new->init->onEnter->onExit->delete步驟來表示生命週期。

引申:場景之間使用的全局變量,都要在onEnter中申請資源,在onExit中釋放資源。

3.9 string類實現

實現簡單的string類,包含拷貝構造函數和默認構造函數,析構函數,賦值運算符重載。在構造函數中,當參數爲空的時候,同樣需要開闢內存_str = new char[1];

*_str = '\0'。在賦值重載的時候,首先需要判斷是否和自己一樣,不相同的話先刪除自己,然後再重新創建。

3.10 cast類型轉換

基本類型在隱式轉換的時候,有可能溢出或者截斷。如果希望轉換爲什麼類型,必須自己制定。爲了避免浪費總線,一般定義爲int類型,這樣也避免轉換出錯。如果對象A的空間比對象B的空間大,給B賦值的時候出現,踩內存,有可能崩潰。這種強制轉換在編譯的時候無法發現。

static_cast靜態類型轉換,在編譯的時候就出錯。如果ab可以進行隱式轉換,那麼ba就可以進行static_cast轉換。經常用到結構體指針轉爲void類型,父類指針轉換爲子類指針。

dynamic_cast沒有虛函數的指針不可以進行轉換,只用於父子之間轉換,轉換失敗變爲NULL

const_cast去掉變量的const屬性。const int a=10;相當於在編譯的時候就確定a是多少,即使強制轉換之後,a也是那個值。類型轉換的坑很多,最好不要使用。

3.11 ZOrder

 默認是0。設置兩個精靈,重疊在一起,看哪個顯示,如果沒有設置的話,先進入的先渲染,看到的是後渲染的。setOrderOfArrival是系統自動調用的,是在create或者addChild的時候設置的,有一個靜態變量,每次調用就會加1,所以越到後面越大,這個是邏輯上的,其實ZOrder還都是0。也可以setZOrder自己設置,必須是相同父節點纔有意義。和settag的值是一樣的,必須是相同父節點纔有意義,不同父節點之間tag的值相同也沒有關係。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章