上一篇講解實現引導的組成模塊及整個引導流程,並給出整個引導的源碼及演示代碼。本文來看看怎麼應用。node
sz.Guide引導庫已經能夠簡單地工做了,但離真實的遊戲項目、使用場景時還須要本身作一些事情。git
進度讀取與保存github
sz.Guide默認對進度的讀取和保存,是記錄在localStorage中的,請看以下代碼:緩存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/**
* 讀取進度
*/
loadProgress: function() {
//獲取localStorage對象,同時兼容jsb
var localStorage = localStorage || cc.sys.localStorage;
//sz.GuideIndexName爲一字符串常量作爲key,讀取進度,不存在時進度爲0
this
._index = parseInt(localStorage.getItem(sz.GuideIndexName)) || 0;
},
/**
* 保存進度
* @param isForward 進度是否前進
* @param cb 保存完的回調
*/
saveProgress: function(isForward, cb) {
var localStorage = localStorage || cc.sys.localStorage;
localStorage.setItem(sz.GuideIndexName, isForward ? ++
this
._index :
this
._index + 1);
if
(cb) {
cb();
}
}
|
_index便是進度的記錄器,又是任務隊列的索引下標,所以進度保存有兩種狀況: 服務器
1.當任務完成(任務中的步驟都解決掉時),使用++this._index保存進度,並修改任務索引,進入下一個任務。 網絡
2.做爲保存進度的步驟時, 使用this._index + 1保存,並不修改當前任務進度,但遊戲重啓後,這這任務將會跳過。框架
有人可能會問saveProgress函數的cb回調參數是什麼用了?請看下面的使用場景。異步
自定義進度的讀取與保存async
由於sz.Guide只簡單實現了本地保存,對於如今大多數網絡遊戲來講並不適合,因此你須要根據本身的項目狀況來擴展sz.Guide,這裏簡單說明幾種方法:ide
修改sz.Guide的源碼來適應你的項目,但不推薦這種作法,由於sz.Guide還會持續改進、修改BUG。
寫兩個新函數來覆蓋sz.GuideLayer上的loadProgress、saveProgress方法。 此方法能夠,但不夠完美,若是一個項目中有多個引導實例時怎麼辦呢?
繼承sz.GuideLayer生成一個子類,重寫loadProgress、saveProgress方法,比較推薦使用這個方法。
如下是我在項目中具體使用方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
xl.MyGuideLayer = sz.GuideLayer.extend({
//保存進度到服務器上
saveProgress: function(isForward, cb) {
//生成當前進度
var index = isForward ? ++
this
._index :
this
._index + 1;
//經過網絡服務器NetClient發送進度,服務器作保存
NetClient.send(ActionCode.SAVE_NEW_PLAYER_GUIDE_STEP, index, function(isSucc) {
//當接收到保存成功的服務器響應後,執行cb回調函數
if
(isSucc && cb) {
cb()
}
})
},
loadProgress: function() {
//緩存對象上獲取玩家對象,並讀取新手引導步驟id
this
._index = CacheManager.getPlayer().newPlayerGuideStep || 0;
},
});
|
這時應該能明白saveProgress函數的cb函數的意義了吧!由於將進度保存到網絡時,絕大多數是異步操做,當服務器真實保存成功能,才能繼續。所以cb函數就是在通知引導框架,進度保存完畢了,能夠進行下一個任務或步驟了。
步驟對象上的事件函數
爲了使用引導配置適應更多的需求,在步驟對象上目前能夠配置三個事件函數,分別爲:
onEnter 當步驟將要開始時
onLocateNode 當定位到節點時(須要配合定位器和相應指令時)
onExit 當步驟結束時
確定有不少人看到個人演示程序,發現下面這個BUG:
這是bug的緣由是,表示燈火的粒子對象,默認沒有高、寬,錨點爲0,高、寬是在代碼啓動時設置上去的。 手型圖標默認指向的位置是 node.getPosition(),也就是錨點位置。
這確實是一個bug,在不修改sz.Guide源碼的狀況下,咱們使用步驟配置來解決這個問題
onLocateNode
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
1: [
{
log
:
"關閉第一盞燈"
,
command: sz.GuideCommand.GC_FINGER_HINT,
locator:
"_fire1"
,
//onLocateNode,當定位到_fire1節點時響應些函數
onLocateNode: function(node) {
//node爲'_fire1'節點對象
var pt = node.getPosition();
pt = node.getParent().convertToWorldSpace(pt);
pt.x += node.width / 2;
pt.y += node.height / 2;
//this爲sz.GuideLayer對象實例,調用_fingerToPoint函數指向新的位置
this
._fingerToPoint(pt,
true
);
}
},
...
|
從新運行代碼,效果以下:
步驟中事件函數的this上下文爲sz.GuideLayer對象實例,你能夠在這裏方便調用sz.GuideLayer上的方法,作一些事情。這裏就使用了sz.Guide._fingerToPoint方法修正手指的位置。
可是這裏也有問題,能夠從遮罩區看出,定位矩形並無把燈火所有包裹住,在體驗上不好。 咱們從新再改進一次配置onLocateNode函數:
1
2
3
4
5
6
7
|
onLocateNode: function(node) {
//修改_touchRect觸摸矩形的起點
this
._touchRect.x -= node.width / 2;
this
._touchRect.y -= node.height / 2;
//計算矩形中心位置
var point = cc.p(
this
._touchRect.x + node.width / 2,
this
._touchRect.y + node.height / 2);
//刷新遮罩顯示
this
.showMask(
true
);
//指向新的位置
this
._fingerToPoint(point,
true
);
}
|
再次運行,效果以下:
onEnter&onExit
onEnter與onExit從名字上就應該很好理解,是由步驟處理開始前和處理完成後觸發。
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
|
//步驟開始_processTasks: function() {
...
//一個step
var stepHandle = function(step, callback) {
self._curStepConfig = step;
async.series({
//步驟開始
stepBegin: function(cb) {
self._guideLayer._setLocateNode(null);
if
(step.onEnter) {
//執行步驟對象上的onEnert函數,注意cb函數參數
step.onEnter.call(self._guideLayer, cb);
}
else
{
cb();
}
},
//步驟處理
stepProcess: function(cb) {
if
(step.delayTime) {
self._guideLayer.scheduleOnce(function() {
self._processStep(step, cb);
}, step.delayTime);
}
else
{
self._processStep(step, cb);
}
},
//步驟完畢
stepEnd: function() {
if
(step.onExit) {
//步驟完畢,退出時執行onExit方法,注意第二個callback參數
step.onExit.call(self._guideLayer, callback);
}
else
{
callback();
}
}
});
};
...
}
|
onEnter、onExit事件函數都有一個cb回調函數的參數,表示事件完成後的通知。
使用場景常會出如今onEnter時播放一個動畫或顯示一個臨時窗口, 須要動畫完成後執行步驟命令。 這都是一個異步過程,因此須要招待一次cb()操做才能讓步驟向下執行。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
1:[
{
...
//在步驟開始時,播放一個動畫
onEnter: function(cb) {
var label =
new
cc.LabelTTF(
"關閉第一盞燈"
,
"宋體"
, 48); var pt = cc.p(
this
.width / 2,
this
.height / 2);
label.setPosition(pt);
this
.addChild(label); var faceOut = cc.fadeOut(3); var call = cc.callFunc(function() {
label.removeFromParent();
cb();
//當執行cb函數時才進入指令處理
},
this
);
label.runAction(cc.sequence(faceOut, call))
}
...
}
|
引導配置中的參數功能
1
2
3
4
5
6
7
8
9
|
var guideConfig = {
//編寫具體引導任務
tasks: {
...
}
//定位器搜索節點的間隔時間
locateNodeDurationTime: 0.1,
//手型提示圖片資源路徑
fingerImage:
'res/finger.png'
,
//常規事件響應的事件類型:0=touchBegan,1=touchMoved,2=touchEnded
eventType: 2,
//表示在touchEnded中檢查事件是否完成
//是否顯示遮罩
isShowMask:
true
};
|
這裏解釋下這些參數的功能可能的使用場景:
locateNodeDurationTime
1
|
locateNodeDurationTime: 0.1
//定位器搜索節點的間隔時間
|
有時在引導步驟中定位一個節點時,這個節點並未建立在當前場景的渲染樹中,在第一次定位節點時並無找到節點對象。所以須要一個持續的節點定位的操做,操做的間隔時間由此參數控制。
fingerImage
1
|
fingerImage: ‘res/finger.png’
//手型提示圖片資源路徑
|
fingerImage很是簡單,就不作過多解釋了。
eventType
1
|
eventType: 2
//表示在touchEnded中檢查事件是否完成
|
前面幾篇文章中介紹了,如何檢查定位節點的事件函數已經被執行。以前的講解中說到通常都是在Widget控件的touchEnded中來處理事件函數。這樣的設定不夠靈活,萬一有時須要在touchBegan時呢?
eventType:2爲引導的全局配置,若是某一個步驟定位節點的事件處理函數放在touchBegan時能夠以下處理:
1
2
3
4
5
6
7
|
...
//一個任務步驟對象{
log
:
'點擊home'
,
command: sz.GuideCommand.GC_FINGER_HINT,
locator:
"_btnHome"
,
eventType:0
//"_btnHome"控件的事件函數爲touchBegan}
...
eventType: 2
|
在演示代碼中你能夠發現 _onBtnHomeTouchBegan: function(){…}函數,因此這裏上步驟中的事件檢測須要在eventType:0
isShowMask
1
|
isShowMask:
true
//是否顯示遮罩
|
此開關方便開始遮罩,特別是在調試時,能夠方便看到咱們的觸摸矩形區大小。
並且在單個任務步驟中也能夠臨時開打或關閉遮罩的顯示:
1
2
3
4
5
|
{
log
:
"點亮第二盞燈"
,
command: sz.GuideCommand.GC_FINGER_HINT,
locator:
"_fire2"
,
showMask:
true
//強制打開當前步驟的遮罩顯示},
|
上面總結了sz.Guide引導庫的基本功能的使用,能夠經過配置、事件函數靈活實現特殊的引導需求。
補充
delayTime
步驟對象上還有一個隱藏的屬性爲delayTime,值爲一個Number,它是間於步驟的onEnter事件與步驟處理操做之間的延時。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
async.series({
//步驟開始
stepBegin: function(cb) {
...
},
//步驟處理
stepProcess: function(cb) {
//若是配置有delayTime屬性,使用scheduleOnce推遲步驟處理
if
(step.delayTime) {
self._guideLayer.scheduleOnce(function() {
self._processStep(step, cb);
}, step.delayTime);
}
else
{
self._processStep(step, cb);
}
},
//步驟完畢
stepEnd: function() {
...
}
|
我主要的使用場景是這樣的狀況:
一個UI界面中有一個按鈕button,建立時在A位置,一個子類繼承成了他,修改成B位置。若是當即定位button節點,所指向的位置並非按鈕的最終位置,這裏使用delayTime能夠輕鬆解決此問題。
指令擴展計劃
sz.Guide內部定義了四個指令,其中實現了三個:
1
2
3
4
5
6
|
sz.GuideCommand = {
GC_NULL: undefined,
//空指令
GC_SET_PROPERTY: 1,
//設置屬性
GC_FINGER_HINT: 2,
//手型提示
GC_SAVE_PROGRESS: 3
//保存進度
};
|
對於一個上線的遊戲項目來講,估計這三個指令是遠遠不夠的。咱們也能經過步驟對象上的onEnter和onExite事件來豐富一些操做,但須要編寫較多的代碼,且代碼是爲一個特定的操做而作的,不可以很好的複用。好比在步驟處理開始前,先滾動TableView。
目前sz.Guide的指令是簡單的用switch後分別調用不一樣的函數實現的。
1
2
3
4
5
6
7
8
9
10
|
switch
(step.command) {
case
sz.GuideCommand.GC_SET_PROPERTY:
...;
break
;
case
sz.GuideCommand.GC_FINGER_HINT:
...;
break
;
case
sz.GuideCommand.GC_SAVE_PROGRESS:
...;
break
;
default
:
cc.
log
(
"guide command is not define"
);
}
|
本人計劃將指令的實現獨立於引導框架,能夠靈活的向引導框架註冊指令,你能夠編寫本身的指令操做。
源碼地址:點此下載
本篇代碼演示:git checkout step1