滾動數字
本節我們來實現數字滾動的效果。
運行效果如下:
Cocos Creator版本:2.2.0
公衆號後臺回覆"滾動數字",獲取完整項目源碼:
創建節點
在層級管理器中我們創建以下節點:
- esitbox即EditBox控件,用於輸入數字。
- ok_btn即一個按鈕控件,當玩家輸完數字,點擊按鈕後,數字滾動。
- all_layout是一個橫向佈局節點,具體用處之後會介紹。
- number_layout是本節教程的核心,它是一個垂直佈局節點,其中放入值爲0-9以及"."符號的這些Label控件。
number_layout節點:
注:水平和垂直佈局的縮放模式(Resize Mode)都爲CONTAINER。
此時場景編輯器顯示如下:
注:節點的座標大家可以自己擺放,或者打開筆者的項目查看,這裏就不再截圖。
滾動原理
其實數字滾動的原理非常簡單,就是改變number_layout節點的y座標。
我們先給all_layout加上Mask組件,把其餘的數字或"."符號先遮住:
注:若要添加Mask節點,須將節點上的Sprite組件先移除。
那現在筆者把number_layout節點的y座標變大,也就是讓整個節點往上走,顯示出來的就是比5大的數字了:
同理,如果筆者把y座標變小,顯示的就會是比5小的數字。
number_layout代表的就是數字上某一位,如果要表示多位數,那麼我們只用多創建幾個number_layout就行了(自然而然想到應該把number_layout變爲預製)。
編寫腳本
我們創建一個名稱爲Roll.js的腳本,在properties中添加如下屬性:
// Roll.js
properties: {
numLayoutPrefab: cc.Prefab,
allLayoutNode: cc.Node,
editNode: cc.Node,
rollTime: 2,
},
- numLayoutPrefab就是number_layout變成的預製。
- allLayoutNode就是all_layout節點。
- editNode就是editbox節點。
- rollTime爲滾動動作所需時間。
在onLoad方法中我們編寫如下代碼:
// Roll.js
onLoad () {
// 節點池
this.prefabPool = new cc.NodePool();
// 預製數組,方便管理
this.prefabArray = [];
// 獲取每個數字長度,用於獲取y座標
let numLayout = cc.instantiate(this.numLayoutPrefab);
this.eachHeight = numLayout.height / 11;
this.prefabPool.put(numLayout);
},
- 節點池用來提高性能。
- 這裏的prefabArray挺重要的,我們之後會講到它的用法。
- 爲了準確地顯示出數字,我們需要求出number_layout中每個數字的高度(即每個Label控件的高度),這樣就可以求出number_layout目標座標點的y值了。
現在我們實現getNumStr方法來獲取輸入框文本:
// Roll.js
getNumStr () {
// 獲取編輯框中輸入的數字(字符串)
let numStr = this.editNode.getComponent(cc.EditBox).string;
return numStr;
},
接着在okBtn方法中判斷玩家輸入的字符串是否可以轉爲數字(記得給ok_btn按鈕綁上該方法):
// Roll.js
okBtn () {
// 首先獲取數字(字符串)
let numStr = this.getNumStr();
// 再判斷是否可以轉換爲數字
let num = Number(numStr);
if (!isNaN(num)) {
console.log('是數字!');
}
else {
console.log('非數字!');
}
},
當確認玩家輸入的是數字後,我們就可以生成相應位數的數字,並執行滾動效果。
數字的位數可以直接通過numStr的長度來判斷,有多少位我們就生成多少個預製:
// Roll.js
okBtn () {
// 首先獲取數字(字符串)
let numStr = this.getNumStr();
// 再判斷是否可以轉換爲數字
let num = Number(numStr);
if (!isNaN(num)) {
// 根據numStr長度生成相應數量的預製
for(let i=0; i<numStr.length; i++) {
// 將生成的預製放入數組中
this.prefabArray.push(this.getNewPrefab());
}
}
else {
console.log('非數字!');
}
},
我們注意到每個通過getNewPrefab()生成的預製都被放到了prefabArray數組中。其實該數組變量的作用就是爲了更好地管理各個預製(比如後期刪除)。在這裏我們還可以通過該數組控制數字上的各個位數——數組的第一個元素就是數字的最高位。
生成預製的getNewPrefab方法實現如下:
// Roll.js
getNewPrefab () {
// 生成預製
let numLayout = null;
// 根據節點池大小判斷是從預製池中獲取還是新生成一個
if (this.prefabPool.size() > 0)
numLayout = this.prefabPool.get();
else
numLayout = cc.instantiate(this.numLayoutPrefab);
// 添加到總佈局中
this.allLayoutNode.addChild(numLayout);
return numLayout;
},
預製生成後就是執行滾動效果了:
// Roll.js
okBtn () {
...
if (!isNaN(num)) {
// 根據numStr長度生成相應數量的預製
for(let i=0; i<numStr.length; i++) {
// 將生成的預製放入數組中
this.prefabArray.push(this.getNewPrefab());
}
// 執行滾動效果
for(let i=0; i<numStr.length; i++) {
this.roll(numStr[i], this.prefabArray[i])
}
}
else {
console.log('非數字!');
}
},
roll方法實現如下:
// Roll.js
roll (num, prefab) {
// 關鍵是獲取y座標
let y = null;
if (num != '.')
y = (Number(num)-5)*this.eachHeight;
else
y = (10-5)*this.eachHeight;
let moveTo = cc.moveTo(this.rollTime, cc.v2(0, y)).easing(cc.easeCubicActionOut());
prefab.runAction(moveTo);
}
該方法有兩個參數,一個是num,一個是 prefab。前者就是要顯示的數字或"."符號,後者即相應位數上的number_layout預製。
我們首先判斷num值,如果不是"."符號的話,那我們將調用Number()將該字符轉爲數字,減去5(5的y座標爲0),再乘以每個數字的高度;是"."符號的話就用直接用10減去5再乘以數字高度("."符號排在最後個)。這樣我們就得出了目標點的y座標,接着將number_layout移到相應位置就可以了。
最後我們還要對okBtn()進行完善。每次點擊ok按鈕後,我們應當對之前生成的各個預製進行回收:
// Roll.js
okBtn () {
// 刪除節點
this.allLayoutNode.removeAllChildren();
// 恢復座標,回收預製,清空數組
for(let i=0; i<this.prefabArray.length; i++) {
this.prefabArray[i].setPosition(0, 0);
this.prefabPool.put(this.prefabArray[i]);
}
this.prefabArray = [];
...
},
注意要刪除之前的節點,並將prefabArray數組清空,各個預製回收前也要恢復座標(可以自行考慮下爲什麼)。
現在將Roll.js腳本掛到Canvas節點上,拖入相應節點,然後就可以運行項目啦:
那本期教程就到這,希望大家有所收穫!
歡迎關注我的微信公衆號,發現更多有趣內容: