版权声明:本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名elloop(包含链接)
#前言
前段时间写STL系列的文章的感受是,技术这东西你说深就深,说浅也浅。拿一个STL算法来说,对它的描述可以简单到给出几个示例用法,把代码往上一贴,OK搞定。或者也可以写的深入一些,分析一下它的源代码实现,分析一下它的效率、边界条件检测、线程安全性等等方面,再加上组织语言,一两个小时都是不够的。虽说现在我年纪轻轻,但是空闲时间并不多,而技术的东西实在太多,所以要做到详略得当,把握住重点,不能所有的东西都写的面面俱到。对于有价值的技术点,因为时间有限,我可以先写一下它的基础含义,假设它的深度有七层,我先写到一、二层,以后有时间或者碰巧对它有新的领悟的时候,再来继续在这一点上写,重复这个过程直到完成七层。今天开始《C++ STL学习与应用总结》系列的文章更新频率会开始降低,近期开始重点写cocos的东西了。
今天在YouTube上看到一个非常好的VIM视频 ,这几天打算录一个翻版分享出来,提醒自己别忘了。
今晚肚子疼头也疼,先挖个坑,明天来填。这篇文章将写一下cocos中的CallFunc系列“动作”用法和注意事项。
现在是2015年最后一天的最后一个小时了,时间不等人,点滴积累要坚持下去。现在开始填昨天的坑。
CallFunc系列对象是Action的一种,具体来说它是瞬时动作(ActionInstant)的一种,其它的瞬时动作还包括Show, Hide, ToggleVisibility, RemoveSelf, FlipX, FlipY, Place等,这么多的瞬时动作,为什么把CallFunc提取出来呢,它有什么好说的呢?
首先是从使用频率上来看的,CallFunc通常和DelayTime一起组成一个Sequence来实现一种延迟调用的效果,这种动作序列在实际开发中很常用。
其次,是从CallFunc的构造方式上来看,它的create方法接受的参数类型比较有代表性。这个参数是一个std::function类型的对象,std::function可以使用C++中任何的Callable来构造,具体包括函数(函数指针,函数引用)、函数对象、闭包(lambda表达式)等一些可调用的对象,这要归功于C++11带来的便利。3.x版本对C++11新特性和标准库的使用使得它比2.x版本在创建回调(包括CallFunc系列, Menu Callback系列, Scheduler系列)方面灵活了很多。这篇文章说CallFunc,也是因为CallFunc的创建方式能很好体现3.x新的创建回调的灵活方式。
前面写的几篇cocos的文章代码示例代码是自己写的,我觉得有些浪费时间,不如直接拿cocos官方示例代码来说,剩下的时间还是自己写游戏更好,在实战中对技术点的体会也会更深刻。
为了不在编写示例代码上花费更多的时间和精力,今后的总结里我会尽可能的使用cocos官方的示例代码。测试代码所在文件路径是相对于cocos2d-x-3.x/tests/cpp-tests/Classes
这个目录的。
CallFunc的基本用法
对CallFunc的使用主要是掌握怎么调用create()方法来创建它,create()方法的原型如下:
// create参数是一个std::function<void()>类型对象的常引用
static CallFunc * create ( const std :: function < void () >& func );
创建std::function<void()>类型对象的方法太多了,详情请参考这里 .
下面的示例是cocos 3.9版本官方的示例代码:
**ActionsTest/ActionTest.cpp : ActionCallFunction **
void ActionCallFunction :: onEnter ()
{
ActionsDemo :: onEnter ();
// 居中放置三个测试用的精灵
centerSprites ( 3 );
// 动作序列1: 移动2秒 + 两个CallFunc,
// 第一个CallFunc使用bind来构造一个std::function<void()>类型的对象.
// 第二个CallFunc使用lambda来构造一个std::function<void()>类型的对象
// 两个CallFunc的回调函数都是一个用一个不带参数的函数来构造的,
// 第一个bind,把一个不带参数的成员函数ActionCallFunction::callback1, 适配成std::function<void()>.
// 第二个,lambda的定义则直接是一个不带参数的函数, 以引用的方式捕获了外层作用域里的this。
auto action1 = Sequence :: create (
MoveBy :: create ( 2 , Vec2 ( 200 , 0 )),
CallFunc :: create ( std :: bind ( & ActionCallFunction :: callback1 , this ) ),
CallFunc :: create (
// lambda
[ & ](){
auto s = Director :: getInstance () -> getWinSize ();
auto label = Label :: createWithTTF ( "called:lambda callback" , "fonts/Marker Felt.ttf" , 16.0 f );
label -> setPosition ( s . width / 4 * 1 , s . height / 2 - 40 );
this -> addChild ( label );
} ),
nullptr );
// 动作序列2: 缩放两秒 + 淡出两秒 + 回调
// 这里的回调是用bind来构造的,bind把一个接收Node*类型形参的成员函数ActionCallFunction::callback2,
// 适配成一个CallFunc需要的std::function<void()>类型的对象。
// bind把_tamara绑定到形参Node*上面。
auto action2 = Sequence :: create (
ScaleBy :: create ( 2 , 2 ),
FadeOut :: create ( 2 ),
CallFunc :: create ( std :: bind ( & ActionCallFunction :: callback2 , this , _tamara ) ),
nullptr );
// 动作序列3: 缩放3秒 + 淡出2秒 + 回调
// 回调同样是使用bind来创建,这次是把一个接收两个参数:Node*和int的成员函数ActionCallFunction::callback3,
// 适配成一个std::function<void()>类型的对象
auto action3 = Sequence :: create (
RotateBy :: create ( 3 , 360 ),
FadeOut :: create ( 2 ),
CallFunc :: create ( std :: bind ( & ActionCallFunction :: callback3 , this , _kathia , 42 ) ),
nullptr );
_grossini -> runAction ( action1 );
_tamara -> runAction ( action2 );
_kathia -> runAction ( action3 );
}
void ActionCallFunction :: callback1 ()
{
auto s = Director :: getInstance () -> getWinSize ();
auto label = Label :: createWithTTF ( "callback 1 called" , "fonts/Marker Felt.ttf" , 16.0 f );
label -> setPosition ( s . width / 4 * 1 , s . height / 2 );
addChild ( label );
}
void ActionCallFunction :: callback2 ( Node * sender )
{
auto s = Director :: getInstance () -> getWinSize ();
auto label = Label :: createWithTTF ( "callback 2 called" , "fonts/Marker Felt.ttf" , 16.0 f );
label -> setPosition ( s . width / 4 * 2 , s . height / 2 );
addChild ( label );
CCLOG ( "sender is: %p" , sender );
}
void ActionCallFunction :: callback3 ( Node * sender , long data )
{
auto s = Director :: getInstance () -> getWinSize ();
auto label = Label :: createWithTTF ( "callback 3 called" , "fonts/Marker Felt.ttf" , 16.0 f );
label -> setPosition ( s . width / 4 * 3 , s . height / 2 );
addChild ( label );
CCLOG ( "target is: %p, data is: %ld" , sender , data );
}
上面的例子中所有的使用bind来创建回调的地方都可以用这个cocos的一个宏来代替,它就是CC_CALLBACK_0
.
使用CC_CALLBACK_0
来改写上面三个回调的创建:
auto action1 = Sequence :: create (
MoveBy :: create ( 2 , Vec2 ( 200 , 0 )),
//CallFunc::create(std::bind(&ActionCallFunction::callback1, this)), 原来的方式
CallFunc :: create ( CC_CALLBACK_0 ( ActionCallFunction :: callback1 , this )),
CallFunc :: create (
// lambda
[ & ](){
auto s = Director :: getInstance () -> getWinSize ();
auto label = Label :: createWithTTF ( "called:lambda callback" , "fonts/Marker Felt.ttf" , 16.0 f );
label -> setPosition ( s . width / 4 * 1 , s . height / 2 - 40 );
this -> addChild ( label );
} ),
nullptr );
auto action2 = Sequence :: create (
ScaleBy :: create ( 2 , 2 ),
FadeOut :: create ( 2 ),
//CallFunc::create(std::bind(&ActionCallFunction::callback2, this, _tamara)), 原来的方式
CallFunc :: create ( CC_CALLBACK_0 ( ActionCallFunction :: callback2 , this , _tamara )),
nullptr );
auto action3 = Sequence :: create (
RotateBy :: create ( 3 , 360 ),
FadeOut :: create ( 2 ),
//CallFunc::create(std::bind(&ActionCallFunction::callback3, this, _kathia, 42)), 原来的方式
CallFunc :: create ( CC_CALLBACK_0 ( ActionCallFunction :: callback3 , this , _kathia , 42 )),
nullptr );
运行效果如下图所示:
关于CC_CALLBACK_0
的使用请参考【cocos2d-x 3.x 学习与应用总结】4: 理解CC_CALLBACK_0, CC_CALLBACK_1, CC_CALLBACK_2, CC_CALLBACK_3 .
CallFuncN的基本用法
CallFuncN::create的原型:
static CallFuncN * create(const std::function<void(Node*)>& func);
CallFuncN与CallFunc的区别仅仅在于前者的function回调需要一个Node*类型的参数。
void ActionCallFuncN :: onEnter ()
{
ActionsDemo :: onEnter ();
centerSprites ( 1 );
auto action = Sequence :: create (
MoveBy :: create ( 2.0 f , Vec2 ( 150 , 0 )),
CallFuncN :: create ( CC_CALLBACK_1 ( ActionCallFuncN :: callback , this )),
nullptr );
_grossini -> runAction ( action );
// 其实,使用CallFunc也能达到这个效果:
auto actionUseCallfunc = Sequence :: create (
MoveBy :: create ( 2.0 , Vec2 ( 150 , 0 )),
CallFunc :: create (
CC_CALLBACK_0 ( ActionCallFuncN :: callback , this , _grossini )),
nullptr );
_grossini -> runAction ( actionUseCallfunc );
}
void ActionCallFuncN :: callback ( Node * sender )
{
auto a = JumpBy :: create ( 5 , Vec2 ( 0 , 0 ), 100 , 5 );
sender -> runAction ( a );
}
CallFuncND的基本用法
// CallFuncND不再需要了,可以使用std::bind来模拟。
// CallFuncND is no longer needed. It can simulated with std::bind()
void ActionCallFuncND :: onEnter ()
{
// ActionCallFuncND::doRemoveFromParentAndCleanup本来是需要两个参数:(Node*, bool), 使用CC_CALLBACK_1把第二个参数绑定为true,
// 这样就变成了一个仅需要一个Node*参数的函数。
auto action = Sequence :: create (
MoveBy :: create ( 2.0 f , Vec2 ( 200 , 0 )),
CallFuncN :: create ( CC_CALLBACK_1 ( ActionCallFuncND :: doRemoveFromParentAndCleanup , this , true )),
nullptr );
_grossini -> runAction ( action );
}
void ActionCallFuncND :: doRemoveFromParentAndCleanup ( Node * sender , bool cleanup )
{
_grossini -> removeFromParentAndCleanup ( cleanup );
}
在这里也能看到这篇文章:github博客 , CSDN博客 , 欢迎访问