Cocos2d-x 3.2编写常用UI组件(二)滚动计数器NumberScroller

前端之家收集整理的这篇文章主要介绍了Cocos2d-x 3.2编写常用UI组件(二)滚动计数器NumberScroller前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
@H_502_0@前言:

@H_502_0@废话不多说,先看最终效果

@H_502_0@

@H_502_0@正文:

@H_502_0@1、使用说明:

@H_502_0@① 引入头文件 “NumberScroller.h"

@H_502_0@② 用NumberScroller::create(int length,int fontSize) 函数来创建NumberScroller对象

@H_502_0@③ 利用setNumber(int number)函数来设置计时器里面的值(这里只实现了向后滚动,即设置的值要大于等于当前值)

@H_502_0@④ 利用getNumber获得当前计数器显示的值

@H_502_0@⑤ 利用setTime(float time)函数来设置计时器滚动的速度,默认为1

@H_502_0@

@H_502_0@2、实现思路:

@H_502_0@① 根据输入的长度length确定计时器的长度(即多少位)

@H_502_0@② 根据输入的fontSize确定字体大小

@H_502_0@③ 创建length条并排放置的竖着的从01234567890(注意末尾有个零)

@H_502_0@④ 根据设置的数字,不同的竖条移动相应的位置。

@H_502_0@⑤ 利用遮罩层遮罩

@H_502_0@

@H_502_0@3、源码解析:

@H_502_0@对应思路①②

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
bool NumberScroller::init( int length, int fontSize){
if (!Node::init()) return false ;
m_length=length;
m_fontSize=fontSize;
m_visibleNode=Node::create();
//排好length列数字
for ( int i=0;i<length;i++){
NumberColumn*column=NumberColumn::create(fontSize);
m_columns.pushBack(column);
column->setAnchorPoint(Point(0,0));
column->setPosition(i*fontSize,0);
column->setTime(m_time);
m_visibleNode->addChild(column);
}
/*设置遮罩层*/
ClippingNode*cliper=ClippingNode::create();
DrawNode*drawNode=DrawNode::create();
Pointpoints[]={Point(getPosition()),Point(getPositionX(),getPositionY()+m_fontSize),
Point(getPositionX()+m_length*m_fontSize,Point(getPositionX()+m_length*m_fontSize,getPositionY())};
drawNode->drawPolygon(points,4,Color4F(0,1),1));
cliper->setStencil(drawNode);
cliper->addChild(m_visibleNode);
this ->addChild(cliper);
}
@H_502_0@先暂时不用看设置遮罩层部分,前面只是保存长度和字体大小到成员变量中,下面的一个for循环就是用来排好length列数字的。

@H_502_0@其中这里出现了一个NumberColumn类,表示一列数字01234567890。

@H_502_0@具体的初始化函数如下

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
bool NumberColumn::init( int fontSize){
if (!Node::init()) return false ;
m_numbers=Node::create();
this ->addChild(m_numbers);
m_fontSize=fontSize;
this ->scheduleUpdate();
for ( int i=0;i<10;i++){
char str[2];
str[0]=i+ '0' ;
str[1]= '\0' ;
Label*temp=Label::create(str, "" ,fontSize);
temp->setAnchorPoint(Point(0,0));
temp->setPosition(Point(0,i*fontSize));
m_numbers->addChild(temp);
}
char str[2];
str[0]= '0' ;
str[1]= '\0' ;
Label*temp=Label::create(str,fontSize);
temp->setAnchorPoint(Point(0,0));
temp->setPosition(Point(0,10*fontSize));
m_numbers->addChild(temp);
return true ;
}
@H_502_0@NumberColumn的init函数里面,除了保存长度和字体大小和启动update外,接下来就是构造一个01234567890的竖列。

@H_502_0@注意,我们这里把所有Label都放在一个Node里面,这样可使我们更方便的操作.

@H_502_0@最后,回到NumberScroller 初始化完的效果是这样子(无遮罩)的:

@H_502_0@NumberScroller最重要的函数还是setNumber

1
2
3
4
5
6
7
8
9
10
void NumberScroller::setNumber( int number){
if (number>m_cur_num){
m_cur_num=number;
for ( int i=0;i<m_length;i++){
m_columns.at(m_length-i-1)->setNumber(number);
number/=10;
}
}
}
@H_502_0@可以看出都是间接地调用NumberColumn的setNumber方法

1
2
3
4
5
void NumberColumn::setNumber( int number, bool direction){
m_target_num=number;
int delta=m_target_num-m_cur_num;
update_speed=(delta*m_fontSize/m_time);
}
@H_502_0@奇怪啦,NumberColumn也只是简单的把传来的number保存到m_target_num里面,还有计算滚动的速度 也没有实现滚动的动作啊。

@H_502_0@

@H_502_0@奥秘在于NumberColumn启动的update函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void NumberColumn::update( float d){
if (m_cur_num!=m_target_num){
//如果当前显示的数字不等于目标数字,即要开始滚动
float dis=update_speed*d; //每次调用update函数需要滚动的距离等于update_speed乘以d(update_speed在setNumber函数中已经算出)
m_numbers->setPositionY(m_numbers->getPositionY()-dis); //每次使整条向下移动dis距离
update_moveSum+=dis; //update_moveSum用于保存现在到底移动了多少距离
if (update_moveSum>=m_fontSize){
//如果现在已经移动了一个字大小的距离
m_cur_num++; //当前数字+1
m_numbers->setPositionY(-m_cur_num*m_fontSize); //标准对齐
update_moveSum=0; //重置
}
}
}
@H_502_0@update函数便是实现滚动效果的核心,每一行都给了详细的注释。

@H_502_0@

@H_502_0@因为我们这里要实现的是类似于时钟的滚动效果(秒针转1圈时,分针转1/60圈),应用到计时器,个位滚动10次,十位才会转一下,所以对应每一条NumberColum,其对应的m_cur_num是不一样的。

@H_502_0@例如999这个数 ,第一条(百位)对应的m_cur_num应该是9,第二条(十位)对应的m_cur_num应该是99,第三条(个位)对应的m_cur_num应该是999。

@H_502_0@由于setNumber时候计算了速度:

1
2
int delta=m_target_num-m_cur_num;
update_speed=(delta*m_fontSize/m_time);
@H_502_0@间隔越大,速度越快,因此保证了每条NumberColumn均会在m_time时间内完成滚动。

@H_502_0@

@H_502_0@有了上面的介绍,再回过头来再看一次NumberScroller的setNumber函数,是不是恍然大悟呢:

1
2
3
4
5
6
7
8
9
10
void NumberScroller::setNumber( int number){
if (number>m_cur_num){
m_cur_num=number;
for ( int i=0;i<m_length;i++){
m_columns.at(m_length-i-1)->setNumber(number);
number/=10;
}
}
}
@H_502_0@

@H_502_0@完成效果后如下:

@H_502_0@最后,添加遮罩层,只显示当前数字部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
bool NumberScroller::init( int length, int fontSize){
。。。省略了一部分。。。
/*设置遮罩层*/
ClippingNode*cliper=ClippingNode::create();
DrawNode*drawNode=DrawNode::create();
Pointpoints[]={Point(getPosition()),
Point(getPositionX()+m_length*m_fontSize,getPositionY())};
drawNode->drawPolygon(points,1));
cliper->setStencil(drawNode);
cliper->addChild(m_visibleNode);
this ->addChild(cliper);
}
@H_502_0@关于遮罩的基本知识,推荐《【Cocos2d-x 3.2】裁剪节点(ClippingNode)总结

@H_502_0@

@H_502_0@4、附上源码:滚动计数器NumberScroller

原文链接:https://www.f2er.com/cocos2dx/344466.html

猜你在找的Cocos2d-x相关文章