使用Cocos2d-JS製做遊戲新手引導(一)

想到新手引導的功能時可能不少人都會以爲頭痛,難如下手。特別是在遊戲自己功能或需求還不穩定的狀況,更是難以應付,本人就是在這種狀況下接受了一個艱鉅的任務。在痛定思痛以後,開始了引導功能開發。在作的過程當中一點點發現不少有意思的東西,想分享給你們。css

 

1、痛點:新手引導製做的難點及弊端html

  • 須要在具備引導功能的代碼單元插入引導代碼或邏輯判斷,干擾正常流程。html5

  • 引導代碼的加入會影響原有的代碼邏輯與流程,使代碼變得複雜加大維護難度。node

  • 界面或需求發生變化後引導功能須要大幅修改或從新制做。c++

  • 指引(手指提示)對應的矩形區定位麻煩,特別是須要適應不一樣尺寸屏幕的時候更加困難。web

  • 編寫引導配置文件也很頭痛,須要策劃、程序的高度配合。編程

 

2、指望:新手引導編程體驗json

筆者進入遊戲開發應該說是手機遊戲開發並非很長時間,雖然參於過多個項目,但親自編寫新手引導這仍是頭一次。當時接到新人引導任務時,咱們的項目只完成了:登陸->主界面->抽卡->佈陣->章節->關卡->戰鬥這樣一個基本流程,界面美術、功能需求都極不穩定。但在公司的硬性要求下,冒着九死一輩子的危險開始了新手引導功能開發。在瞭解到傳統的引導製做過程當中的難點與弊端後,一直在思考沒有更好的實現方式,我心中的引導編程的方式有如下幾點:服務器

  • 不須要在每一個單元中去插入引導代碼,遊戲代碼與引導代碼應該儘可能分離。本人很難忍受漂亮的代碼被無情引導打亂,更難忍受原本糟糕的代碼被引導弄得支離破碎。框架

  • 界面只發生簡單UI位移、節點層次改變不須要修改引導代碼。

  • 定位指引矩形區應該儘可能的簡單,且自適應不一樣尺寸屏幕。最好能作到策劃人員均可以來製做部分流程引導。

  • 在引導需求明確、遊戲功能正常的狀況下,製做一個常規的引導步驟應該是很是快捷的,不會超過3分鐘,快的話1分鐘內就應該搞定(不是筆者說大話,確實已經實現)。

 

3、思想:引導功能的設計思路

在描述引導功有設計思路以前,有個重要的前題:命名規範。

 

命名規範主要有兩個方面:

  1. Cocos Studio中的控件名字

  2. 代碼中動態建立的控件名字,以及類成員變量的名字。

在筆者的項目中使用了sw.UILoader來管理cocostudio的UI命名和事件。 如不瞭解請參見個人另一篇教程《在Cocos2d-JS中實現自動綁定Cocos Studio UI控件與事件

 

咱們這裏引入兩個概念:任務與任務組。任務:把引導中的一個最小步驟稱之爲一個任務,好比提示點擊某個按鈕。任務組:把一系列的任務放在一個任務組中,當這個任務組中的任務所有完成,咱們會保存一次任務進度。此時從新進入遊戲將不會再執行這個任務,而是執行它的下一個任務組中的任務。能夠理解任務組是引導中的一個步驟。

 

用json格式表示如:

{

    [{任務1},{任務2},{任務3}]

    [{任務7},{任務8},{任務9}]

    [{任務4},{任務5},{任務6}]

}

當從一個任務組中的任務中斷後,再次進入引導 須要從新從這個任務組的第一個任務開始。

見下圖演示了一個從主界面點擊召喚->靈石召喚一次->點擊得到->肯定->仙玉召喚一次->點擊得到->肯定->點擊空白退出召喚界面的流程。

js1.gif

上圖演示的引導我分紅兩個任務組:靈石召喚、仙玉召喚。 任務配置以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
"3" :[
     {
         "name" "4.提示指向靈石召喚按鈕" ,
         "command" "手型提示" ,
         "tag" "_oneMoneyButton"
     },
     {
         "name" "保存進度" ,
         "command" "保存進度"
     },
     {
         "name" "5.提示指向角色肯定按鈕" ,
         "command" "手型提示" ,
         "tag" "_UILotteryHero > _confirmBtn"
     },
     {
         "name" "6.提示指向角色圖標肯定按鈕" ,
         "command" "手型提示" ,
         "tag" "_UILotteryTimes > _confirmBtn"
     }
],
 
"4" :[
     {
         "name" "7.提示指向仙玉召喚按鈕" ,
         "command" "手型提示" ,
         "tag" "_oneGoldButton"
     },
     {
         "name" "保存進度" ,
         "command" "保存進度"
     },
     {
         "name" "8.提示指向角色肯定按鈕" ,
         "command" "手型提示" ,
         "tag" "_UILotteryHero/Panel_33/Image_10/_confirmBtn"
     },
     {
         "name" "9.提示指向角色圖標肯定按鈕" ,
         "command" "手型提示" ,
         "tag" "_UILotteryTimes/Panel_11/Image_1/_confirmBtn"
     },],

其中每一個任務中的name用於調試打印的對引導自己無實際用處,在任務開始和結速都會有提示,若是出錯方便定位。 command這裏應該叫作指令,對應一段具體功能的代碼或函數,我這裏設置了兩個:手型提示、保存進度。

  • 手型提示:須要配合tag字段的值,tag描述了一個當前任務狀態下的一個node節點的索引。具體tag的編寫方式請看下面一節"實如今節點樹中定位控件"。

  • 進度保存:手動進度保存是爲了確保在任務中斷後,遊戲流程不受影響。 在招喚這個功能裏,是隻能召喚一次的,若是已經召喚成功了,服務器已經更新數據 ,後面的引導都是客戶端的界面顯示、關閉引導。若是在召喚以後,作一次進度保存,任務中斷後再次進入引導會跳過這個任務組中的任務。

在理解了任務的功能後,須要有一個上層框架來一個一個的執行這些任務。

 

引導框架:在任務條件知足時(好比:等級要達到多少或者無任何條件),指示用戶進行某項任務(好比按鈕的點擊)。當任務完成後,執行下一個任務,直接到所有任務被完成。它須要具備如下幾點功能:

  • 條件檢查:檢查是否該執行該任務,默認爲無條件執行。這須要檢查任務是否有onTaskBegan函數 ,不存在或返回ture才能執行任務指令

  • UI定位:找到出當前任務中UI節點對應的矩形區。在指引任務中準確編寫UI定位描述,由框架去檢索UI節點,當檢索到節點後調用任務的onLocateNode函數,傳入節點對像,這可讓整個引導能夠有更多的擴展。

  • 指引動畫:當定位成功後,引導框播放指引提示動畫,提示用戶操做該矩形區。

  • 觸摸限制:屏蔽定位節點矩形區外的操做所有。

  • 事件檢查:矩形區對應的UI事件是否被執行。

  • 任務完成:通知引導框架任務完成,進入下一個任務。

 

4、定位:實如今節點樹中定位控件

以上幾點中首要解決的是對UI控件的定位,對UI定位最直接有效的方法是在拿到這個UI控件對象,而後取出他的BoundingBox、錨點信息,進行座標轉換。但如何才能拿到這個控件對象呢? 這裏有兩種實現方式:

1. 遍歷場景樹,把它搜索出來。

2. 事先把這個控件對象註冊到你的引導框架中。

 

我採起的是第一種方法來定位控件,由於我不想在處處代碼中添加遊戲邏輯之外的東西。並且cocos2d-js中提供有現成的函數cc.helper.seekWidgetByName,若是你作的是手機遊戲是不能直接使用這個函數的。在HTML5上這個函數能夠遍歷整個節點樹 ,在jsb上只是遍歷的Widget節點。 有兩種方法解決這個問題:

1.把cc.helper.seekWidgetByName函數複製到本身代碼文件中,從新取個名字叫:xxx.helper.seekNodeByName。在html5和jsb上都使用這個函數。

2.在c++ jsb上把cc.Helper.seekWidgetByName的參數修改爲在Node節點上作遍歷,或都從新封裝一個jsb上的seekNodeByName函數 。

 

我這裏偷懶仍是使用第一種方法。經過上面的方法是否已經解決UI定位的問題呢?應該沒那麼簡單吧!經過這種方法定位控件,就不用在引導配置文件裏填寫座標或矩形數據,那是極其愚蠢的辦法。

打住,還有問題!!! 若是一個場景樹中有兩個相同節點名字怎搞?

這個問題確實問的很正確。由於咱們常常會有名字相同的節點存在。好比下圖:

20150301092305852.jpg

若是他們名字都叫button,使用seekNodeByName是來定位控件的話只能找到其中一個。具體是那個是根據你addChild時的順序來決定的。這個問題如何解決?能惟一肯定一個控件在場景樹中的方法就是他的「完整路徑」,像這樣一下來描述兩個button:

"招喚界面/靈石招喚/召喚一次"

"招喚界面/仙玉招喚/召喚一次"

其實咱們已經能定位到靈石招喚和仙玉招喚了(我這裏爲了方便理解使用中文名字)只須要這樣寫:

"靈石招喚/召喚一次"

"仙玉招喚/召喚一次"

這樣也能精肯定位到你想要的那個按鈕。

 

在這裏我實現了一個簡易的定位器描述規則,咱們之後經過如下方式在任務中定位一個控件 :

  • 名字描述:在場景中有獨一無二的名字時,直接描述控件名如:'_loginButton'。

  • 路徑名描述:在場景中須要定位的節點可能有重名時,找到其父節點,確保父節點不會有重名時使用:'parentName/button'。若是父節點也有重名,那就再向上使用其父節點名的父節點以此類推。

  • js屬性描述:有一種狀況經過getChildByName沒法直接訪問的節點,如ccui.ScollView容器中的節點。我定義了一種簡單的獲取方式,例如 'layer1.button' 經過「.」這個符號來定位layer1下的一個屬性爲button。這種方式是在js中最爲直接的方式。

  • 子節點描述:使用完整路徑描述一個控件時,有時會以爲比較長,例如: 'mainLayer/layer1/button' 能夠簡寫成 'mainLayer>button' 表示定位mainLayer下一個名字叫button的子節點,有能夠是1級子節點,也可能爲二、三、n級子節點。

  • 複合描述:將以上幾個方式組合使用,來描述一個控件:'mainLayer>homeLayer/layer1.button' 。用人話翻譯下就是:mainLayer下有一個homeLayer子節點(不論是幾級)下的一級子節點layer1下的一個變量名爲button的節點.

 

描述符號總結:

  • 「/」: 表示一級子節點

  • 「>」: 表示一級~n級子節點

  • 「.」: 表示屬性名

這裏就體現了爲何要注意名命規範的問題。有web開發經驗的人一眼就能看出這裏有一點css選擇器的味道,呵呵!很是正確,正是借鑑了css選擇器的思想,實現一個十分簡單的選擇器,咱們這裏能夠稱之爲「定位器」,由於咱們只須要定位出一個節點。

(未完待續)

相關文章
相關標籤/搜索