一、最後的前言
依舊使用久方法:順藤摸瓜,一點一點發現,打開ChooseLevelScene.lua吧
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
43
44
45
46
47
|
local AdBar = import( "..views.AdBar" ) local LevelsList = import( "..views.LevelsList" ) local ChooseLevelScene = class ( "ChooseLevelScene" , function() return display.newScene( "ChooseLevelScene" ) end) function ChooseLevelScene:ctor() -- 背景 local bg = display.newSprite( "#OtherSceneBg.png" ) -- make background sprite always align top 用於對齊頂部 bg:setPosition(display.cx, display.top - bg:getContentSize().height / 2) self:addChild(bg) -- 標題 local title = display.newSprite( "#Title.png" , display.cx, display.top - 100) self:addChild(title) -- 信息條 local adBar = AdBar. new () self:addChild(adBar) -- create levels list 創建等級列表 local rect = cc.rect(display.left, display.bottom + 180, display.width, display.height - 280) self.levelsList = LevelsList. new (rect) self.levelsList:addEventListener( "onTapLevelIcon" , handler(self, self.onTapLevelIcon)) self:addChild(self.levelsList) -- 後退按鈕 cc.ui.UIPushButton. new ({normal = "#BackButton.png" , pressed = "#BackButtonSelected.png" }) :align(display.CENTER, display.right - 100, display.bottom + 120) :onButtonClicked(function() app:enterMenuScene() end) :addTo(self) end function ChooseLevelScene:onTapLevelIcon(event) audio.playSound(GAME_SFX.tapButton) app:playLevel(event.levelIndex) end function ChooseLevelScene:onEnter() self.levelsList:setTouchEnabled( true ) end return ChooseLevelScene |
不難,唯一需要繼續深入的就是這段代碼:
1
2
3
4
5
|
-- create levels list 創建等級列表 local rect = cc.rect(display.left, display.bottom + 180, display.width, display.height - 280) self.levelsList = LevelsList. new (rect) self.levelsList:addEventListener( "onTapLevelIcon" , handler(self, self.onTapLevelIcon)) self:addChild(self.levelsList) |
其實,想要順着代碼往看下,我們將會把要這個遊戲剩下的五個腳本關聯起來:
1
2
3
4
5
|
LevelsList.lua LevelsListCell.lua PageControl.lua ScrollView.lua ScrollViewCell.lua |
只要明白了這五個腳本,就懂得了該遊戲的關卡選擇場景是如何建立的,進而整個遊戲也就完整了解了一遍。先讓大家瞭解下我對這最後的五個腳本理解的關係:
-
LevelsList繼承自→PageControl繼承自→ScrollView
-
LevelsListCell繼承自→ScrollViewCell
-
LevelsList在內部使用了LevelsListCell
讓我們先從簡單的講起,就是cell(單元),先明白,該遊戲運用時,一個頁面就是一個cell(單元),如下圖:
包含了1到16有一個看不見的矩形,它就一個cell(單元),你向左滑動一下就會進入下一個cell(單元):17到32
二、cell(單元)
從ScrollViewCell.lua開始:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
local ScrollViewCell = class ( "ScrollViewCell" , function(contentSize) local node = display.newNode() -- 該類基礎只是一個節點 if contentSize then node:setContentSize(contentSize) end -- 根據傳入參入確立該節點的ContentSize node:setNodeEventEnabled( true ) --設置該節點可以 爲特定事件設置處理函數 cc(node):addComponent( "components.behavior.EventProtocol" ):exportMethods() return node end) function ScrollViewCell:onTouch(event, x, y) end function ScrollViewCell:onTap(x, y) end -- 退出時調用 function ScrollViewCell:onExit() --移除所用的事件響應事件 self:removeAllEventListeners() end return ScrollViewCell |
ScrollViewCell.lua並不複雜,因爲它只是作爲一個“骨架”存在,很多功能並沒有實現,所以需要我們再去擴展,所以有了LevelsListCell.lua,一定有人覺得爲什麼不直接寫一個LevelsListCell.lua就夠了呢?反正我們就擴展一個類而已,幹嘛要“骨架”呢? 這我回答不好,只能說這樣編程遵循了良好的設計模式,對以後程序的改良有很大的好處。
回到正題,進入LevelsListCell.lua:
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
local ScrollViewCell = import( "..ui.ScrollViewCell" ) -- 繼承自ScrollViewCell local LevelsListCell = class ( "LevelsListCell" , ScrollViewCell) function LevelsListCell:ctor(size, beginLevelIndex, endLevelIndex, rows, cols) local rowHeight = math. floor ((display.height - 340) / rows) -- 每行的高度 local colWidth = math. floor (display.width * 0.9 / cols) -- 每列的寬度 -- 使用了批量渲染對象,在Board.lua也用過 local batch = display.newBatchNode(GAME_TEXTURE_IMAGE_FILENAME) self:addChild(batch) self.pageIndex = pageIndex -- button集合 self.buttons = {} -- 第一個將要加入的button的X,Y座標 local startX = (display.width - colWidth * (cols - 1)) / 2 local y = display.top - 220 -- 捕獲傳入參數beginLevelIndex local levelIndex = beginLevelIndex -- 添加button,每個cell(單元)是16個按鈕哦 for row = 1, rows do local x = startX for column = 1, cols do -- button的一系列處理 local icon = display.newSprite( "#LockedLevelIcon.png" , x, y) batch:addChild(icon) icon.levelIndex = levelIndex self.buttons[#self.buttons + 1] = icon -- 等級標籤 local label = cc.ui.UILabel. new ({ UILabelType = 1, text = tostring(levelIndex), font = "UIFont.fnt" }) :align(cc.ui.TEXT_ALIGN_CENTER, x, y - 4) self:addChild(label) -- 處理完一個button後,重置數據,爲添加下一個button做準備 x = x + colWidth levelIndex = levelIndex + 1 if levelIndex > endLevelIndex then break end end y = y - rowHeight if levelIndex > endLevelIndex then break end end -- add highlight level icon self.highlightButton = display.newSprite( "#HighlightLevelIcon.png" ) self.highlightButton:setVisible( false ) self:addChild(self.highlightButton,100) end -- 觸摸響應函數 function LevelsListCell:onTouch(event, x, y) if event == "began" then local button = self:checkButton(x, y) if button then self.highlightButton:setVisible( true ) self.highlightButton:setPosition(button:getPosition()) end elseif event ~= "moved" then self.highlightButton:setVisible( false ) end end -- 觸摸敲中button的響應函數 function LevelsListCell:onTap(x, y) local button = self:checkButton(x, y) if button then self:dispatchEvent({name = "onTapLevelIcon" , levelIndex = button.levelIndex}) end end -- 獲取傳入參數X,Y座標所對應的button function LevelsListCell:checkButton(x, y) local pos = cc.p(x, y) -- 遍歷所有的button for i = 1, #self.buttons do local button = self.buttons<i> -- 如果傳入的點在該button的方位內,則返回該button if cc.rectContainsPoint(button:getBoundingBox(), pos) then return button end end return nil end return LevelsListCell |
擴展後的Cell,在ctor中對Cell的視覺界面進行了排版和佈局,同時還有兩個響應函數:onTouch(event, x, y)和onTap(x, y);
這裏我要特別解釋一句代碼: self:dispatchEvent({name = "onTapLevelIcon", levelIndex = button.levelIndex}) 意思就委派一個Event,其中name屬性是必須,作爲事件的名字,但要觸發該事件時就需要用到,而其他屬性可以任意。這句代碼結束後就相當LevelsListCell 這個類有了一個Event,可以看做一個表event={{name = "onTapLevelIcon", levelIndex = button.levelIndex}}
三、滾動控件ScrollView.lua
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
|
local ScrollView = class ( "ScrollView" , -- 創建一個控件基礎的節點 function(rect) if not rect then rect = cc.rect(0, 0, 0, 0) end local node = display.newClippingRegionNode(rect) -- 剪裁區域的節點 node:setNodeEventEnabled( true ) cc(node):addComponent( "components.behavior.EventProtocol" ):exportMethods() return node end) ScrollView.DIRECTION_VERTICAL = 1 -- 垂直方向 ScrollView.DIRECTION_HORIZONTAL = 2 -- 水平方向 -- 參數:區域,拖動方向 function ScrollView:ctor(rect, direction) assert (direction == ScrollView.DIRECTION_VERTICAL or direction == ScrollView.DIRECTION_HORIZONTAL, "ScrollView:ctor() - invalid direction" ) self.dragThreshold = 40 -- 拖動最小臨界值 self.bouncThreshold = 140 -- 拖動到能翻頁的最小臨界值 self.defaultAnimateTime = 0.4 -- 默認動畫時間 self.defaultAnimateEasing = "backOut" -- 默認的ease self.direction = direction -- 滾動方向 self.touchRect = rect -- 觸摸矩形 self.offsetX = 0 -- X軸偏移量 self.offsetY = 0 -- Y軸偏移量 self.cells = {} -- 單元集合 self.currentIndex = 0 -- 當前索引(對應self.cells) -- 爲self的節點事件cc.NODE_EVENT 設置處理函數(返回一個id表示註冊成功) self:addNodeEventListener(cc.NODE_EVENT, function(event) if event.name == "enter" then self:onEnter() elseif event.name == "exit" then self:onExit() end end) -- create container layer 創建一個容器層 self.view = display.newLayer() self:addChild(self.view) -- 爲self.view的觸摸事件cc.NODE_TOUCH_EVENT 設置處理函數 self.view:addNodeEventListener(cc.NODE_TOUCH_EVENT, function(event) return self:onTouch(event.name, event.x, event.y) end) end ---- 一些簡單的對外接口函數 -- 得到當前索引所指向的單元 function ScrollView:getCurrentCell() if self.currentIndex > 0 then return self.cells[self.currentIndex] else return nil end end -- 得到當前索引 function ScrollView:getCurrentIndex() return self.currentIndex end -- 設置當前索引 function ScrollView:setCurrentIndex(index) self:scrollToCell(index) end -- 添加單元 function ScrollView:addCell(cell) self.view:addChild(cell) self.cells[#self.cells + 1] = cell self:reorderAllCells() self:dispatchEvent({name = "addCell" , count = #self.cells}) end -- 根據索引插入一個單元 function ScrollView:insertCellAtIndex(cell, index) self.view:addChild(cell) table.insert(self.cells, index, cell) self:reorderAllCells() self:dispatchEvent({name = "insertCellAtIndex" , index = index, count = #self.cells}) end -- 根據索引移除一個單元 function ScrollView:removeCellAtIndex(index) local cell = self.cells[index] cell:removeSelf() table. remove (self.cells, index) self:reorderAllCells() self:dispatchEvent({name = "removeCellAtIndex" , index = index, count = #self.cells}) end -- 得到容器層 function ScrollView:getView() return self.view end -- 得到可觸摸矩形 function ScrollView:getTouchRect() return self.touchRect end -- 設置可觸摸矩形 function ScrollView:setTouchRect(rect) self.touchRect = rect self:dispatchEvent({name = "setTouchRect" , rect = rect}) end -- 得到剪裁後的矩形 function ScrollView:getClippingRect() return self:getClippingRegion() end -- 設置剪裁後的矩形 function ScrollView:setClippingRect(rect) self:setClippingRegion(rect) -- 委派事件 ,名字:setClippingRect self:dispatchEvent({name = "setClippingRect" , rect = rect}) end -- 滾動cell(單元) 傳入參數,index當前頁碼, 後面三個爲跳轉Cell時執行動作的參數 function ScrollView:scrollToCell(index, animated, time , easing) -- cell(單元)總數 local count = #self.cells if count < 1 then self.currentIndex = 0 return end -- 對index進行判斷與處理 if index < 1 then index = 1 elseif index > count then index = count end self.currentIndex = index -- 根據滾動方向,設置偏移量 local offset = 0 for i = 2, index do local cell = self.cells[i - 1] local size = cell:getContentSize() if self.direction == ScrollView.DIRECTION_HORIZONTAL then offset = offset - size.width else offset = offset + size.height end end self:setContentOffset(offset, animated, time , easing) -- 委派事件 self:dispatchEvent({name = "scrollToCell" , animated = animated, time = time , easing = easing}) end -- 檢測容器層self.view是否允許觸摸 function ScrollView:isTouchEnabled() return self.view:isTouchEnabled() end -- 設置容器層是否允許觸摸響應(默認是 false ) function ScrollView:setTouchEnabled(enabled) self.view:setTouchEnabled(enabled) -- self:setTouchEnabled(enabled) self:dispatchEvent({name = "setTouchEnabled" , enabled = enabled}) end ---- events 事件處理函數 -- Began function ScrollView:onTouchBegan(x, y) self.drag = { currentOffsetX = self.offsetX, currentOffsetY = self.offsetY, startX = x, startY = y, isTap = true , } local cell = self:getCurrentCell() cell:onTouch(event, x, y) return true end -- Moved function ScrollView:onTouchMoved(x, y) local cell = self:getCurrentCell() if self.direction == ScrollView.DIRECTION_HORIZONTAL then if self.drag.isTap and math. abs (x - self.drag.startX) >= self.dragThreshold then self.drag.isTap = false cell:onTouch( "cancelled" , x, y) end if not self.drag.isTap then self:setContentOffset(x - self.drag.startX + self.drag.currentOffsetX) else cell:onTouch(event, x, y) end else if self.drag.isTap and math. abs (y - self.drag.startY) >= self.dragThreshold then self.drag.isTap = false cell:onTouch( "cancelled" , x, y) end if not self.drag.isTap then self:setContentOffset(y - self.drag.startY + self.drag.currentOffsetY) else cell:onTouch(event, x, y) end end end -- Ended 裏面調用了onTouchCancelled(x, y)與onTouchEndedWithTap(x, y) function ScrollView:onTouchEnded(x, y) if self.drag.isTap then self:onTouchEndedWithTap(x, y) else self:onTouchEndedWithoutTap(x, y) end self.drag = nil end -- Cancelled function ScrollView:onTouchCancelled(x, y) self.drag = nil end -- 觸摸結束時,結束點敲中按鈕 function ScrollView:onTouchEndedWithTap(x, y) local cell = self:getCurrentCell() cell:onTouch(event, x, y) cell:onTap(x, y) -- 該函數的啓動將會觸發許多函數!! end -- 觸摸結束時,結束點沒有敲中按鈕 function ScrollView:onTouchEndedWithoutTap(x, y) error( "ScrollView:onTouchEndedWithoutTap() - inherited class must override this method" ) end -- onTouch 根據事件調用 Began、Moved、Ended與Cancelled function ScrollView:onTouch(event, x, y) if self.currentIndex < 1 then return end if event == "began" then -- 判斷起始的觸摸點是否在可觸摸矩形中,若不在則直接返回不做任何操作 if not cc.rectContainsPoint(self.touchRect, cc.p(x, y)) then return false end return self:onTouchBegan(x, y) elseif event == "moved" then self:onTouchMoved(x, y) elseif event == "ended" then self:onTouchEnded(x, y) else -- cancelled self:onTouchCancelled(x, y) end end ---- private methods 私有方法 -- 重新整理所有的單元 function ScrollView:reorderAllCells() -- 1、設置每個Cell(單元)的position,注意cell的錨點在(0,0) local count = #self.cells local x, y = 0, 0 local maxWidth, maxHeight = 0, 0 for i = 1, count do local cell = self.cells<i> cell:setPosition(x, y) -- 根據滾動方向確定下個cell的position if self.direction == ScrollView.DIRECTION_HORIZONTAL then local width = cell:getContentSize().width if width > maxWidth then maxWidth = width end x = x + width else local height = cell:getContentSize().height if height > maxHeight then maxHeight = height end y = y - height end end -- 2、重置數據 if count > 0 then if self.currentIndex < 1 then self.currentIndex = 1 elseif self.currentIndex > count then self.currentIndex = count end else self.currentIndex = 0 end -- 3、添加完所有Cell後,根據滾動方向,設置好容器層的大小 local size if self.direction == ScrollView.DIRECTION_HORIZONTAL then size = cc.size(x, maxHeight) else size = cc.size(maxWidth, math. abs (y)) end self.view:setContentSize(size) end -- 根據偏移量觸發動作 function ScrollView:setContentOffset(offset, animated, time , easing) local ox, oy = self.offsetX, self.offsetY local x, y = ox, oy if self.direction == ScrollView.DIRECTION_HORIZONTAL then self.offsetX = offset x = offset local maxX = self.bouncThreshold local minX = -self.view:getContentSize().width - self.bouncThreshold + self.touchRect.width if x > maxX then x = maxX elseif x < minX then x = minX end else self.offsetY = offset y = offset local maxY = self.view:getContentSize().height + self.bouncThreshold - self.touchRect.height local minY = -self.bouncThreshold if y > maxY then y = maxY elseif y < minY then y = minY end end -- 根據傳入的動作參數執行動作 if animated then transition.stopTarget(self.view) transition.moveTo(self.view, { x = x, y = y, time = time or self.defaultAnimateTime, easing = easing or self.defaultAnimateEasing, }) else -- 如果animated這項爲空,就沒有動作了,直接使用setPosition跳轉到下一個Cell self.view:setPosition(x, y) end end -- onExit function ScrollView:onExit() -- 移除所有指定類型的事件處理函數 self:removeAllEventListeners() end return ScrollView |
該腳本代碼很多,可能比較麻煩看,但基本可以爲四大部分:
-
ctor,在裏面設置了基本屬性;
-
對外接口函數,大部分爲對屬性進行操作的簡單接口函數;
-
events 事件處理函數;
-
private methods 私有方法;
剩下的需要大家看着註釋慢慢理解了。
四、PageControl
PageControl繼承自ScrollView,並且改動很小,只是重寫一個方法,就是:onTouchEndedWithoutTap(x, y),原本該方法只在未點中時輸出信息,但重寫後會根據觸摸偏移量進行翻頁動作
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
43
44
45
|
local ScrollView = import( ".ScrollView" ) -- 繼承自ScrollView local PageControl = class ( "PageControl" , ScrollView) -- 重新定義了觸摸點未敲中button時的函數,會根據觸摸的偏移量執行翻頁的動作 function PageControl:onTouchEndedWithoutTap(x, y) local offsetX, offsetY = self.offsetX, self.offsetY local index = 0 local count = #self.cells if self.direction == ScrollView.DIRECTION_HORIZONTAL then offsetX = -offsetX local x = 0 local i = 1 while i <= count do local cell = self.cells<i> local size = cell:getContentSize() if offsetX < x + size.width / 2 then index = i break end x = x + size.width i = i + 1 end if i > count then index = count end else local y = 0 local i = 1 while i <= count do local cell = self.cells<i> local size = cell:getContentSize() if offsetY < y + size.height / 2 then index = i break end y = y + size.height i = i + 1 end if i > count then index = count end end self:scrollToCell(index, true ) end return PageControl |
五、最終的成品LevelsList
LevelsList繼承自PageControl ,重寫了兩個方法:ctor和scrollToCell,與其說是重寫不如說是爲他們增加了功能,兩個方法都首先執行了父類的方法,在ctor增加了按鈕的佈局添加與指示燈,在scrollToCell中增加了指示燈的動作效果。
這就是指示燈:
同時,擴增了一個方法onTapLevelIcon,作用是委派事件。
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
local LevelsListCell = import( ".LevelsListCell" ) local Levels = import( "..data.Levels" ) local PageControl = import( "..ui.PageControl" ) -- 繼承自PageControl local LevelsList = class ( "LevelsList" , PageControl) LevelsList.INDICATOR_MARGIN = 46 -- 指示燈的間隔 function LevelsList:ctor(rect) --先執行方法定義好的方法 LevelsList.super.ctor(self, rect, PageControl.DIRECTION_HORIZONTAL) -- 1、add cells -- 默認是4行4列,橫的是行,豎的是列 local rows, cols = 4, 4 -- 如果分辨率的高超過1000,而變成5行 if display.height > 1000 then rows = rows + 1 end -- 總頁數 :7頁,也就是7個cell local numPages = math. ceil (Levels.numLevels() / (rows * cols)) local levelIndex = 1 -- 使用 for 循環添加7個cell for pageIndex = 1, numPages do -- 每個cell最後一個關卡的等級 local endLevelIndex = levelIndex + (rows * cols) - 1 -- 如果cell的最後一個關卡等級大於Levels.lua裏設定好的100個等級話的,那麼endLevelIndex就爲100,也就是第7個cell if endLevelIndex > Levels.numLevels() then endLevelIndex = Levels.numLevels() end -- 創建cell local cell = LevelsListCell. new (cc.size(display.width, rect.height), levelIndex, endLevelIndex, rows, cols) cell:addEventListener( "onTapLevelIcon" , function(event) return self:onTapLevelIcon(event) end) self:addCell(cell) --重置數據,爲下個循環添加cell做準備 levelIndex = endLevelIndex + 1 end -- 2、add indicators 添加指示燈 local x = (self:getClippingRect().width - LevelsList.INDICATOR_MARGIN * (numPages - 1)) / 2 local y = self:getClippingRect().y + 20 self.indicator_ = display.newSprite( "#LevelListsCellSelected.png" ) self.indicator_:setPosition(x, y) self.indicator_.firstX_ = x for pageIndex = 1, numPages do local icon = display.newSprite( "#LevelListsCellIndicator.png" ) icon:setPosition(x, y) self:addChild(icon) x = x + LevelsList.INDICATOR_MARGIN end self:addChild(self.indicator_) end -- 重寫scrollToCell方法,添加指示燈的動作效果 function LevelsList:scrollToCell(index, animated, time ) --1、先執行方法定義好的方法 LevelsList.super.scrollToCell(self, index, animated, time ) --2、指示燈動作效果代碼 transition.stopTarget(self.indicator_) local x = self.indicator_.firstX_ + (self:getCurrentIndex() - 1) * LevelsList.INDICATOR_MARGIN if animated then time = time or self.defaultAnimateTime transition.moveTo(self.indicator_, {x = x, time = time / 2}) else self.indicator_:setPositionX(x) end end -- 點中圖標是委派一個事件 function LevelsList:onTapLevelIcon(event) self:dispatchEvent({name = "onTapLevelIcon" , levelIndex = event.levelIndex}) end return LevelsList |
六、使用
回到最初的代碼:
1
2
3
4
|
local rect = cc.rect(display.left, display.bottom + 180, display.width, display.height - 280) self.levelsList = LevelsList. new (rect) self.levelsList:addEventListener( "onTapLevelIcon" , handler(self, self.onTapLevelIcon)) self:addChild(self.levelsList) |
使用很簡單了,只要傳入一個矩形參數就足夠了,其他的東西在LevelsListCell和LevelsList裏都已經擴展好了。
讓我們看一下這句代碼self.levelsList:addEventListener("onTapLevelIcon", handler(self, self.onTapLevelIcon))找到self.onTapLevelIcon:
1
2
3
4
|
function ChooseLevelScene:onTapLevelIcon(event) audio.playSound(GAME_SFX.tapButton) app:playLevel(event.levelIndex) end |
這個方法就把我們之前第四篇所講的一切聯繫上了,進入遊戲進行場景了!
七、再講講dispatchEvent
先說清楚,這個地方完全了看着這個遊戲代碼自我理解,不太能講得明白,大家可以參考這篇文章:《解析Quick-Cocos2d-x中自定義事件》
還是繼續看這句代碼:
1
|
self.levelsList:addEventListener( "onTapLevelIcon" , handler(self, self.onTapLevelIcon)) |
問題來了,事件"onTapLevelIcon"哪裏來的呢?回到levelsList.lua發現:
1
2
3
4
|
-- 點中圖標是委派一個事件 function LevelsList:onTapLevelIcon(event) self:dispatchEvent({name = "onTapLevelIcon" , levelIndex = event.levelIndex}) end |
並且在ctor中發現了使用它的代碼:
1
|
cell:addEventListener( "onTapLevelIcon" , function(event) return self:onTapLevelIcon(event) end) |
意思就是LevelsList裏的onTapLevelIcon(event)函數一定執行,就會觸發名爲"onTapLevelIcon"的Event,同時返回一個參數event={ name = "onTapLevelIcon",levelIndex = event.levelIndex}}。
但在這裏,我們又發現了Cell裏也有一個"onTapLevelIcon"事件,好吧,乖乖回去LevelsListCell
1
2
3
4
5
6
7
|
-- 觸摸敲中button的響應函數 function LevelsListCell:onTap(x, y) local button = self:checkButton(x, y) if button then self:dispatchEvent({name = "onTapLevelIcon" , levelIndex = button.levelIndex}) end end |
而這個onTap(x, y)是在何時被調用的呢?答案就在ScrollView:
1
2
3
4
5
6
|
-- 觸摸結束時,結束點敲中按鈕 function ScrollView:onTouchEndedWithTap(x, y) local cell = self:getCurrentCell() cell:onTouch(event, x, y) cell:onTap(x, y) -- 該函數的啓動將會觸發許多函數!! end |
總結起來就當觸摸結束時,結束點敲中按鈕,將會觸發事件,層層遞進,最終進入遊戲場景!
最後附上帶註釋的源碼:mycoinflip.zip