本节我们来实现数字滚动的效果。
运行效果如下:
Cocos Creator版本:2.2.0
公号All Codes后台回复"滚动数字",获取完整代码。
创建节点
在层级管理器中我们创建以下节点: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.jsproperties: {
numLayoutPrefab: cc.Prefab,
allLayoutNode: cc.Node,
editNode: cc.Node,
rollTime: 2,
},numLayoutPrefab就是number_layout变成的预制。
allLayoutNode就是all_layout节点。
editNode就是editbox节点。
rollTime为滚动动作所需时间。
在onLoad方法中我们编写如下代码:
// Roll.jsonLoad () {
// 节点池 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.jsgetNumStr () {
// 获取编辑框中输入的数字(字符串) let numStr = this.editNode.getComponent(cc.EditBox).string;
return numStr;
},
接着在okBtn方法中判断玩家输入的字符串是否可以转为数字(记得给ok_btn按钮绑上该方法):
// Roll.jsokBtn () {
// 首先获取数字(字符串) let numStr = this.getNumStr();
// 再判断是否可以转换为数字 let num = Number(numStr);
if (!isNaN(num)) {
console.log('是数字!');
}
else {
console.log('非数字!');
}
},
当确认玩家输入的是数字后,我们就可以生成相应位数的数字,并执行滚动效果。
数字的位数可以直接通过numStr的长度来判断,有多少位我们就生成多少个预制:
// Roll.jsokBtn () {
// 首先获取数字(字符串) let numStr = this.getNumStr();
// 再判断是否可以转换为数字 let num = Number(numStr);
if (!isNaN(num)) {
// 根据numStr长度生成相应数量的预制 for(let i=0; i
// 将生成的预制放入数组中 this.prefabArray.push(this.getNewPrefab());
}
}
else {
console.log('非数字!');
}
},
我们注意到每个通过getNewPrefab()生成的预制都被放到了prefabArray数组中。其实该数组变量的作用就是为了更好地管理各个预制(比如后期删除)。在这里我们还可以通过该数组控制数字上的各个位数——数组的第一个元素就是数字的最高位。
生成预制的getNewPrefab方法实现如下:
// Roll.jsgetNewPrefab () {
// 生成预制 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.jsokBtn () {
...
if (!isNaN(num)) {
// 根据numStr长度生成相应数量的预制 for(let i=0; i
// 将生成的预制放入数组中 this.prefabArray.push(this.getNewPrefab());
}
// 执行滚动效果 for(let i=0; i
this.roll(numStr[i], this.prefabArray[i])
}
}
else {
console.log('非数字!');
}
},
roll方法实现如下:
// Roll.jsroll (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.jsokBtn () {
// 删除节点 this.allLayoutNode.removeAllChildren();
// 恢复坐标,回收预制,清空数组 for(let i=0; i
this.prefabArray[i].setPosition(0, 0);
this.prefabPool.put(this.prefabArray[i]);
}
this.prefabArray = [];
...
},
注意要删除之前的节点,并将prefabArray数组清空,各个预制回收前也要恢复坐标(可以自行考虑下为什么)。
现在将Roll.js脚本挂到Canvas节点上,拖入相应节点,然后就可以运行项目啦:
那本期教程就到这,希望大家有所收获!