繼上一次介紹了《神奇的六邊形》的完整遊戲開發流程後(可點選這裡檢視),這次将為大家介紹另外一款魔性遊戲《跳躍的方塊》的完整開發流程。
(點選圖檔可進入遊戲體驗)
因内容太多,為友善大家閱讀,是以分多次來講解。
若要一次性檢視所有文檔,也可點選這裡。
接上回(《跳躍的方塊》Part 9)
(四)排行榜界面
排行榜榜單元素
排行榜的榜單也是一個TableView,是以我們先建立一個榜單元素的控制腳本:RankItem.js。
1 // define a user behaviour
2 var RankItem = qc.defineBehaviour('qc.JumpingBrick.RankItem', qc.Behaviour, function() {
3 // need this behaviour schedule in editor
4 //this.runInEditor = true;
5 }, {
6 positionImg : qc.Serializer.NODE,
7 positionText : qc.Serializer.NODE,
8 nameText : qc.Serializer.NODE,
9 score : qc.Serializer.NODE,
10 head : qc.Serializer.NODE,
11 headBack : qc.Serializer.NODE,
12 scoreBack : qc.Serializer.NODE
13 });
14
15 RankItem._position = [
16 'first.png',
17 'second.png',
18 'third.png'
19 ];
20
21 RankItem._textTint = [
22 0xffb16742,
23 0xff2899a7,
24 0xffa5b471,
25 0xff876712
26 ];
27
28 RankItem._headBack = [
29 'list_head_org.png',
30 'list_head_blu.png',
31 'list_head_green.png',
32 'list_head_yel.png'
33 ];
34
35 RankItem._infoBack = [
36 'list_bak_org.png',
37 'list_bak_blu.png',
38 'list_bak_green.png',
39 'list_bak_yel.png'
40 ];
41
42 // Awake is called when the script instance is being loaded.
43 RankItem.prototype.awake = function() {
44
45 };
46
47 RankItem.prototype.revoke = function() {
48 var self = this;
49 if (self.headKey) {
50 // 清理資源
51 self.game.assets.unload(self.headKey);
52 self.headKey = null;
53 }
54 };
55
56 // Update is called every frame, if the behaviour is enabled.
57 RankItem.prototype.refreshData = function(index, data, cache) {
58 // 更新資訊
59 var self = this;
60 self.headBack.frame = RankItem._headBack[index < 4 ? (index - 1) : 3];
61 self.scoreBack.frame = RankItem._infoBack[index < 4 ? (index - 1) : 3];
62 if (index < 4) {
63 self.positionImg.visible = true;
64 self.positionImg.frame = RankItem._position[index - 1];
65 self.positionText.visible = false;
66 self.nameText.stroke = new qc.Color(RankItem._textTint[index - 1]);
67 self.score.stroke = new qc.Color(RankItem._textTint[index - 1]);
68 }
69 else {
70 self.positionImg.visible = false;
71 self.positionText.visible = true;
72 self.positionText.text = index.toString();
73 self.nameText.stroke = new qc.Color(RankItem._textTint[3]);
74 self.score.stroke = new qc.Color(RankItem._textTint[3]);
75 }
76
77 // 載入頭像
78 // 擷取64 * 64的頭像尺寸
79 if (data.headurl) {
80 if (self.headKey) {
81 // 清理資源
82 self.game.assets.unload(self.headKey);
83 }
84 self.headKey = data.headurl;
85 self.game.assets.loadTexture(self.headKey, data.headurl + '64', function(assets) {
86 self.head.texture = assets;
87 if (cache) {
88 cache.dirty = true;
89 }
90 });
91 }
92 self.nameText.text = data.name;
93 self.score.text = data.score.toString();
94 };
建立榜單預制:sort_score.bin。并和腳本進行關聯:
其中mask使用Pixel模式,使用自己的本身圖檔的透明通道作為子節點的透明通道,設定如下:
排行榜界面
- 管理腳本 使用ViewTable來管理榜單節點,需要提供TableViewAdapter來提供資料。建立一個Announcement.js,用來提供資料并管理界面。内容如下:
1 /**
2 * 排行榜界面
3 */
4 var Announcement = qc.defineBehaviour('qc.JumpingBrick.Announcement', com.qici.extraUI.TableViewAdapter, function() {
5
6 }, {
7 closeButton: qc.Serializer.NODE,
8 showPanel : qc.Serializer.NODE,
9 myDesc : qc.Serializer.NODE,
10 myPosition : qc.Serializer.NODE,
11 myHeadPanel : qc.Serializer.NODE,
12 myHead : qc.Serializer.NODE,
13 myName : qc.Serializer.NODE,
14 myScore : qc.Serializer.NODE
15 });
16
17 Announcement.prototype.awake = function() {
18 var self = this,
19 data = JumpingBrick.data;
20 self.addListener(self.closeButton.onClick, self.returnToGameOver, self);
21 self.addListener(self.gameObject.onClick, self.returnToGameOver, self);
22 self.addListener(self.showPanel.onClick, function() {}, self);
23 self.addListener(data.onRankUpdate, self.receiveRankData, self);
24 };
25
26 /**
27 * 傳回遊戲結算界面
28 */
29 Announcement.prototype.returnToGameOver = function() {
30 var self = this;
31 if (self.headKey) {
32 self.game.assets.unload(self.headKey);
33 }
34 JumpingBrick.uiManager.switchStateTo(qc.JumpingBrick.UIManager.GameOver);
35 };
36
37 // 請求排行榜資料
38 Announcement.prototype.updateRank = function() {
39 var data = JumpingBrick.data;
40 data.queryRank();
41 };
42
43 /**
44 * 收到排行榜資料
45 */
46 Announcement.prototype.receiveRankData = function(data) {
47 var self = this;
48 // 更新自己的資訊
49 var selfData = data.selfRank;
50 if (!selfData) {
51 self.myPosition.text = '請登入遊戲後檢視';
52 self.myHeadPanel.visible = false;
53 self.myName.visible = false;
54 self.myScore.visible = false;
55 self.myDesc.visible = false;
56 }
57 else {
58 self.myPosition.text = selfData.ranking ? selfData.ranking.toString() : '未上榜';
59 self.myHeadPanel.visible = true;
60 self.myDesc.visible = true;
61
62 // 擷取64 * 64的頭像尺寸
63 if (selfData.headurl) {
64 if (self.headKey) {
65 self.game.assets.unload(self.headKey);
66 }
67 self.headKey = selfData.headurl;
68 self.game.assets.loadTexture(self.headKey, selfData.headurl + '64', function(assets) {
69 self.myHead.texture = assets;
70 });
71 }
72 self.myName.text = selfData.name;
73 self.myScore.text = selfData.scorers.toString();
74 }
75
76 var rankTop = data.rankTop;
77 self.rankTop = rankTop;
78
79 self.dispatchDataChange();
80 };
81
82
83 /**
84 * 擷取表格大小,x、y同時隻能有一個為Infinity
85 */
86 Announcement.prototype.getTableSize = function() {
87 return { x: 1, y: this.rankTop ? this.rankTop.length : 0 };
88 };
89
90 /**
91 * 根據在Table中的點傳回對應的單元格
92 * @param {number} x - x軸坐标
93 * @param {number} y - y軸坐标
94 */
95 Announcement.prototype.findCellWithPos = function(x, y) {
96 return {
97 x: Math.floor(x / 540),
98 y: Math.floor(y / 90)
99 };
100 };
101
102 /**
103 * 擷取節點的顯示位置
104 */
105 Announcement.prototype.getCellRect = function(col, row) {
106 return new qc.Rectangle(col * 540, row * 90, 540, 90);
107 };
108
109 /**
110 * 節點處于不可見時,回收節點,
111 * @param {qc.Node} cell - 節點
112 * @param {number} col - 所在列
113 * @param {number} row - 所在行
114 */
115 Announcement.prototype.revokeCell = function(cell, col, row) {
116 cell.getScript('qc.JumpingBrick.RankItem').revoke();
117 };
118
119 /**
120 * 節點處于可見時,建立節點,
121 * @param {qc.Node} cell - 節點
122 * @param {number} col - 所在列
123 * @param {number} row - 所在行
124 */
125 Announcement.prototype.createCell = function(cell, col, row) {
126 if (this.rankTop) {
127 cell.getScript('qc.JumpingBrick.RankItem').refreshData(row + 1, this.rankTop[row]);
128 }
129 };
- 排行榜根節點 排行榜界面是一個固定大小的視窗,如果還是按遊戲的方式以高度為準,可能在有些裝置上就會超出螢幕區域。 是以,為了排行榜,需要再建立一個UIRoot,命名為announcement,Manual Type類型為Expand,建議的寬高還是設計使用的(640, 960)。 如圖所示:
為了适應螢幕旋轉,還是需要為announcement節點添加一個鎖屏的元件。如圖所示:
- 界面展示及腳本關聯 在鎖屏元件下開始拼界面,并将Announcement.js加到announcement節點上。如圖所示:
其中tableView的腳本挂載scrollView節點上,配置如下:
五)界面管理
基本界面都已經做好,将這些界面節點同UIManager關聯起來,設定如圖所示:
這樣界面部分也就都完成了。
結束語
到這裡,所有的遊戲功能開發已經全部完成了。總體的開發思路和時間安排是這樣:
- 從設計方案出發,提煉配置。
- 優先完成主體玩法,盡早進行玩法疊代。
- 再逐漸完善資料處理和界面邏輯。
感謝各位堅持看到最後,《跳躍的方塊》到此就分享完了。若對工程示例或引擎的使用有任何問題,請一定告訴我們,我們會不斷努力,繼續完善。以後還将陸續分享其他好遊戲的開發經驗,望大家繼續關注,謝謝!
其他相關連結
開源免費的HTML5遊戲引擎——青瓷引擎(QICI Engine) 1.0正式版釋出了!
JS開發HTML5遊戲《神奇的六邊形》(一)
青瓷引擎之純JavaScript打造HTML5遊戲第二彈——《跳躍的方塊》Part 1