继上一次介绍了《神奇的六边形》的完整游戏开发流程后(可点击这里查看),这次将为大家介绍另外一款魔性游戏《跳跃的方块》的完整开发流程。
(点击图片可进入游戏体验)
因内容太多,为方便大家阅读,所以分多次来讲解。
若要一次性查看所有文档,也可点击这里。
接上回(《跳跃的方块》Part 9)
(四)排行榜界面
排行榜榜单元素
排行榜的榜单也是一个TableView,所以我们先建立一个榜单元素的控制脚本:RankItem.js。
// define a user behaviour
var RankItem = qc.defineBehaviour('qc.JumpingBrick.RankItem', qc.Behaviour, function() {
// need this behaviour schedule in editor
//this.runInEditor = true;
}, {
positionImg : qc.Serializer.NODE,
positionText : qc.Serializer.NODE,
nameText : qc.Serializer.NODE,
score : qc.Serializer.NODE,
head : qc.Serializer.NODE,
headBack : qc.Serializer.NODE,
scoreBack : qc.Serializer.NODE
}); RankItem._position = [
'first.png',
'second.png',
'third.png'
]; RankItem._textTint = [
0xffb16742,
0xff2899a7,
0xffa5b471,
0xff876712
]; RankItem._headBack = [
'list_head_org.png',
'list_head_blu.png',
'list_head_green.png',
'list_head_yel.png'
]; RankItem._infoBack = [
'list_bak_org.png',
'list_bak_blu.png',
'list_bak_green.png',
'list_bak_yel.png'
]; // Awake is called when the script instance is being loaded.
RankItem.prototype.awake = function() { }; RankItem.prototype.revoke = function() {
var self = this;
if (self.headKey) {
// 清理资源
self.game.assets.unload(self.headKey);
self.headKey = null;
}
}; // Update is called every frame, if the behaviour is enabled.
RankItem.prototype.refreshData = function(index, data, cache) {
// 更新信息
var self = this;
self.headBack.frame = RankItem._headBack[index < 4 ? (index - 1) : 3];
self.scoreBack.frame = RankItem._infoBack[index < 4 ? (index - 1) : 3];
if (index < 4) {
self.positionImg.visible = true;
self.positionImg.frame = RankItem._position[index - 1];
self.positionText.visible = false;
self.nameText.stroke = new qc.Color(RankItem._textTint[index - 1]);
self.score.stroke = new qc.Color(RankItem._textTint[index - 1]);
}
else {
self.positionImg.visible = false;
self.positionText.visible = true;
self.positionText.text = index.toString();
self.nameText.stroke = new qc.Color(RankItem._textTint[3]);
self.score.stroke = new qc.Color(RankItem._textTint[3]);
} // 载入头像
// 获取64 * 64的头像尺寸
if (data.headurl) {
if (self.headKey) {
// 清理资源
self.game.assets.unload(self.headKey);
}
self.headKey = data.headurl;
self.game.assets.loadTexture(self.headKey, data.headurl + '64', function(assets) {
self.head.texture = assets;
if (cache) {
cache.dirty = true;
}
});
}
self.nameText.text = data.name;
self.score.text = data.score.toString();
};
创建榜单预制:sort_score.bin。并和脚本进行关联:
其中mask使用Pixel模式,使用自己的本身图片的透明通道作为子节点的透明通道,设置如下:
排行榜界面
- 管理脚本 使用ViewTable来管理榜单节点,需要提供TableViewAdapter来提供数据。创建一个Announcement.js,用来提供数据并管理界面。内容如下:
/**
* 排行榜界面
*/
var Announcement = qc.defineBehaviour('qc.JumpingBrick.Announcement', com.qici.extraUI.TableViewAdapter, function() { }, {
closeButton: qc.Serializer.NODE,
showPanel : qc.Serializer.NODE,
myDesc : qc.Serializer.NODE,
myPosition : qc.Serializer.NODE,
myHeadPanel : qc.Serializer.NODE,
myHead : qc.Serializer.NODE,
myName : qc.Serializer.NODE,
myScore : qc.Serializer.NODE
}); Announcement.prototype.awake = function() {
var self = this,
data = JumpingBrick.data;
self.addListener(self.closeButton.onClick, self.returnToGameOver, self);
self.addListener(self.gameObject.onClick, self.returnToGameOver, self);
self.addListener(self.showPanel.onClick, function() {}, self);
self.addListener(data.onRankUpdate, self.receiveRankData, self);
}; /**
* 返回游戏结算界面
*/
Announcement.prototype.returnToGameOver = function() {
var self = this;
if (self.headKey) {
self.game.assets.unload(self.headKey);
}
JumpingBrick.uiManager.switchStateTo(qc.JumpingBrick.UIManager.GameOver);
}; // 请求排行榜数据
Announcement.prototype.updateRank = function() {
var data = JumpingBrick.data;
data.queryRank();
}; /**
* 收到排行榜数据
*/
Announcement.prototype.receiveRankData = function(data) {
var self = this;
// 更新自己的信息
var selfData = data.selfRank;
if (!selfData) {
self.myPosition.text = '请登录游戏后查看';
self.myHeadPanel.visible = false;
self.myName.visible = false;
self.myScore.visible = false;
self.myDesc.visible = false;
}
else {
self.myPosition.text = selfData.ranking ? selfData.ranking.toString() : '未上榜';
self.myHeadPanel.visible = true;
self.myDesc.visible = true; // 获取64 * 64的头像尺寸
if (selfData.headurl) {
if (self.headKey) {
self.game.assets.unload(self.headKey);
}
self.headKey = selfData.headurl;
self.game.assets.loadTexture(self.headKey, selfData.headurl + '64', function(assets) {
self.myHead.texture = assets;
});
}
self.myName.text = selfData.name;
self.myScore.text = selfData.scorers.toString();
} var rankTop = data.rankTop;
self.rankTop = rankTop; self.dispatchDataChange();
}; /**
* 获取表格大小,x、y同时只能有一个为Infinity
*/
Announcement.prototype.getTableSize = function() {
return { x: 1, y: this.rankTop ? this.rankTop.length : 0 };
}; /**
* 根据在Table中的点返回对应的单元格
* @param {number} x - x轴坐标
* @param {number} y - y轴坐标
*/
Announcement.prototype.findCellWithPos = function(x, y) {
return {
x: Math.floor(x / 540),
y: Math.floor(y / 90)
};
}; /**
* 获取节点的显示位置
*/
Announcement.prototype.getCellRect = function(col, row) {
return new qc.Rectangle(col * 540, row * 90, 540, 90);
}; /**
* 节点处于不可见时,回收节点,
* @param {qc.Node} cell - 节点
* @param {number} col - 所在列
* @param {number} row - 所在行
*/
Announcement.prototype.revokeCell = function(cell, col, row) {
cell.getScript('qc.JumpingBrick.RankItem').revoke();
}; /**
* 节点处于可见时,创建节点,
* @param {qc.Node} cell - 节点
* @param {number} col - 所在列
* @param {number} row - 所在行
*/
Announcement.prototype.createCell = function(cell, col, row) {
if (this.rankTop) {
cell.getScript('qc.JumpingBrick.RankItem').refreshData(row + 1, this.rankTop[row]);
}
};
- 排行榜根节点 排行榜界面是一个固定大小的窗口,如果还是按游戏的方式以高度为准,可能在有些设备上就会超出屏幕区域。 所以,为了排行榜,需要再建立一个UIRoot,命名为announcement,Manual Type类型为Expand,建议的宽高还是设计使用的(640, 960)。 如图所示:
为了适应屏幕旋转,还是需要为announcement节点添加一个锁屏的组件。如图所示:
- 界面展示及脚本关联 在锁屏组件下开始拼界面,并将Announcement.js加到announcement节点上。如图所示:
其中tableView的脚本挂载scrollView节点上,配置如下:
五)界面管理
基本界面都已经做好,将这些界面节点同UIManager关联起来,设置如图所示:
这样界面部分也就都完成了。
结束语
到这里,所有的游戏功能开发已经全部完成了。总体的开发思路和时间安排是这样:
- 从设计方案出发,提炼配置。
- 优先完成主体玩法,尽早进行玩法迭代。
- 再逐步完善数据处理和界面逻辑。
感谢各位坚持看到最后,《跳跃的方块》到此就分享完了。若对工程示例或引擎的使用有任何问题,请一定告诉我们,我们会不断努力,继续完善。以后还将陆续分享其他好游戏的开发经验,望大家继续关注,谢谢!
其他相关链接