cocos2d-x 3.1.1 学习笔记[17] 关于函数的那些勾当

对于cocos2d-x经常要用到的方法,不得不好好研究一下,这次的研究真心有收获。

首先定义一个精灵,实现一连串连续的动作。

为了动作能够回调我们的函数,我们必须先声明并实现他们。

    void callBack();
    void callBack_1(Node* node);
    void callBack_2(Node* node,const char* str);

    void Nice::callBack()
    {
        log("Nice::callBack()");
    }
    void Nice::callBack_1(Node* node)
    {
        log("This tag is  %d",node->getTag());
    }
    void Nice::callBack_2(Node* node,const char* str)
    {
        log("This tag is %d, and str is %s",node->getTag(), str);
    }

    //然后就开始创建我们伟大的精灵了。
    sp_area  = Sprite::create("newAlwaysShow.png");//sp_area is a class member ,Sprite* ap_area;
    sp_area->setTag(1314);
    auto sp_another = Sprite::create();
    sp_another->setTag(520);
    addChild(sp_another);
    addChild(sp_area);
    //翻滚吧,可爱的精灵们!
    /*
     CallFunc 创建的函数必须是无参数的
     CallFuncN 创建的函数可以是一个至多个参数
     */
    sp_area->runAction(Sequence::create(MoveTo::create(2, Vec2(200, 200)),
                                   CallFunc::create(CC_CALLBACK_0(Nice::callBack, this)),
                                   CallFuncN::create(CC_CALLBACK_1(Nice::callBack_2, this, "I have tow parameter")),
                                   NULL));
    //这样写完之后,发现runAction里面的东西好平淡(平淡有时候才不是真呢!),于是我就瞎写一通,残忍的把它变成了这个样子。
    sp_area->runAction(Sequence::create(MoveTo::create(2, Vec2(200, 200)),
                                   CallFunc::create(CC_CALLBACK_0(Nice::callBack, this)),
                                   CallFunc::create([&]()->void{log("Done1");log("This tag is %d", sp_area->getTag());}),
                                   CallFunc::create(std::bind(&Nice::callBack, this)),
                                   CallFuncN::create(CC_CALLBACK_1(Nice::callBack_1, this)),//1314
                                   CallFuncN::create(CC_CALLBACK_0(Nice::callBack_1, this, sp_another)),//520
                                   CallFuncN::create([](Node* node){log("this tag is %d", node->getTag());}),//1314
                                   CallFuncN::create(std::bind(&Nice::callBack_1, this, sp_area)),//1314
                                   CallFuncN::create(std::bind(&Nice::callBack_1, this, sp_another)),//520
                                   CallFuncN::create(CC_CALLBACK_1(Nice::callBack_2, this, "I have tow parameter")),
                                   NULL));

好吧,他现在已经面目全非了。其实这么多行也只是用到了两种方法而已,第一种lambda表达式,第二种std::bind()。(尼玛,你在逗我吗?不是还有CC_CALLBACK_0吗?)

额。既然这样就让我们来看下源码吧!

// new callbacks based on C++11
#define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)
#define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)
#define CC_CALLBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)
#define CC_CALLBACK_3(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, ##__VA_ARGS__)

果不其然,宏只是表面,内在还是偷偷的和std::bind勾搭在一起了!

我们来看下这个到处勾搭的宏是怎么定义的~~~

#define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)

#define CC_CALLBACK_0( 方法,目标, 可变参数) std::bind(&取方法的地址,目标, 可变参数)

PS:在定义宏的时候是不能用...来当作前面的...作为可变参数的,必须要使用##__VA_ARGS__这个伟大的第三者来替换掉

可变参数在整个cocos-x中也还是用到很多的。比如创建Sequence::create就是运动了,不然你怎么能在创建一连串的动作的时候传入那么多的参数的说。

那么接下来就来看看源码吧。(又是源码- -)

Sequece::create是分平台实现的(分为win和其他)

#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
    // WP8 in VS2012 does not support nullptr in variable args lists and variadic templates are also not supported
    typedef FiniteTimeAction* M;
    static Sequence* create(M m1, std::nullptr_t listEnd) { return variadicCreate(m1, NULL); }
    static Sequence* create(M m1, M m2, std::nullptr_t listEnd) { return variadicCreate(m1, m2, NULL); }
    static Sequence* create(M m1, M m2, M m3, std::nullptr_t listEnd) { return variadicCreate(m1, m2, m3, NULL); }
    static Sequence* create(M m1, M m2, M m3, M m4, std::nullptr_t listEnd) { return variadicCreate(m1, m2, m3, m4, NULL); }
    static Sequence* create(M m1, M m2, M m3, M m4, M m5, std::nullptr_t listEnd) { return variadicCreate(m1, m2, m3, m4, m5, NULL); }
    static Sequence* create(M m1, M m2, M m3, M m4, M m5, M m6, std::nullptr_t listEnd) { return variadicCreate(m1, m2, m3, m4, m5, m6, NULL); }
    static Sequence* create(M m1, M m2, M m3, M m4, M m5, M m6, M m7, std::nullptr_t listEnd) { return variadicCreate(m1, m2, m3, m4, m5, m6, m7, NULL); }
    static Sequence* create(M m1, M m2, M m3, M m4, M m5, M m6, M m7, M m8, std::nullptr_t listEnd) { return variadicCreate(m1, m2, m3, m4, m5, m6, m7, m8, NULL); }
    static Sequence* create(M m1, M m2, M m3, M m4, M m5, M m6, M m7, M m8, M m9, std::nullptr_t listEnd) { return variadicCreate(m1, m2, m3, m4, m5, m6, m7, m8, m9, NULL); }
    static Sequence* create(M m1, M m2, M m3, M m4, M m5, M m6, M m7, M m8, M m9, M m10, std::nullptr_t listEnd) { return variadicCreate(m1, m2, m3, m4, m5, m6, m7, m8, m9, m10,  NULL); }

    // On WP8 for variable argument lists longer than 10 items, use the other create functions or variadicCreate with NULL as the last argument
    static Sequence* variadicCreate(FiniteTimeAction* item, ...);
#else
    static Sequence* create(FiniteTimeAction *action1, ...) CC_REQUIRES_NULL_TERMINATION;
#endif

Sequence* Sequence::create(FiniteTimeAction *action1, ...)
{
    va_list params;
    va_start(params, action1);

    Sequence *ret = Sequence::createWithVariableList(action1, params);//传给了createWithVariableList让他来处理

    va_end(params);

    return ret;
}

Sequence* Sequence::createWithVariableList(FiniteTimeAction *action1, va_list args)
{
    FiniteTimeAction *now;
    FiniteTimeAction *prev = action1;
    bool bOneAction = true;

    while (action1)
    {
        now = va_arg(args, FiniteTimeAction*);
        //如果第二个动作存在
        if (now)
        {
            prev = createWithTwoActions(prev, now);
            bOneAction = false;
        }
        //如果第二个动作不存在
        else
        {
            // If only one action is added to Sequence, make up a Sequence by adding a simplest finite time action.
            if (bOneAction)
            {
                prev = createWithTwoActions(prev, ExtraAction::create());
            }
            break;
        }
    }

    return ((Sequence*)prev);
}

我们就按照他的思路来实现一个可变参数的函数

void manyArgument(int num, ...);
    void Nice::manyArgument(int num, ...)
    {
        va_list params;
        //va_start函数的第二个参数要和manyArgument的第一个参数一样
        va_start(params, num);

        int now;
        log("fist is %d", num);
        while (true)
        {
            now = va_arg(params, int);
            if (now != -1)
            {
                log("now is %d", now);
            }
            else
            {
                break;
            }
        }

        va_end(params);
    }
    manyArgument(1, 2, 3, 4, -1);

可以发现多个参数的的时候必须要有一个可以终止的条件(例如最后一个为-1),但是如果在中途就要传入-1怎么办?

这个时候只能把传入的参数改为int*

void manyArgument(int* num, ...);

然后再把最后终止的条件换为!= null,但是这样在传入参数的时候就麻烦(有得必有失)

    void manyArgument(int* num, ...);
    void Nice::manyArgument(int* num, ...)
    {
        va_list params;
        //va_start函数的第二个参数要和manyArgument的第一个参数一样
        va_start(params, num);

        int* now;
        log("fist is %d", *num);
        while (true)
        {
            now = va_arg(params, int*);
            if (now != nullptr)
            {
                log("now is %d", *now);
            }
            else
            {
                break;
            }
        }

        va_end(params);
    }
    int arr[] {3,6,9,12};
    manyArgument(arr, arr+1, arr+2, arr+3, nullptr);

接着试试定义一个可变参数得宏  ##__VA_ARGS__ 就代表着前面传入进来的可变参数

    #define MANYARGUMENT(__num__, ...) manyArgument(__num__, ##__VA_ARGS__)
    MANYARGUMENT(arr, arr+1, arr+2, nullptr);

别忘记我们还有std::placeholders::_1 占位没有玩过呢= =

    auto add_num = std::bind(&Nice::add, this, std::placeholders::_1, std::placeholders::_2, 10);
    log("sum is %d", add_num(1, 1));//12
    log("sum is %d", add_num(1, 1, 2));//12
    log("sum is %d", add_num(1, 1, 2, 4));//12
    //无论怎么改变参数的第三位也是固定死了是10的,神奇的是居然能传入四个参数,明摆着就是只认定前两个参数是有效的,后面的统统无效。

学到这里。貌似对这个流程还是比较清楚的嘛。虽然可能还有更多的只是没有发现,但是我们还有更多的时间没有用呀!

时间: 2024-08-29 13:41:41

cocos2d-x 3.1.1 学习笔记[17] 关于函数的那些勾当的相关文章

cocos2d-x 3.1.1 学习笔记[21]cocos2d-x 创建过程

文章出自于  http://blog.csdn.net/zhouyunxuan RootViewController.h #import <UIKit/UIKit.h> @interface RootViewController : UIViewController { } - (BOOL) prefersStatusBarHidden; @end RootViewController.cpp #import "RootViewController.h" #import &

cocos2d-x 3.1.1 学习笔记[3]Action 动作

这些动画貌似都非常多的样子,就所有都创建一次. 代码例如以下: /* 动画*/ auto sp = Sprite::create("card_bg_big_26.jpg"); Size size = Director::getInstance()->getWinSize(); sp->setScale(0.2); sp->setPosition(Vec2(size.width / 2 + 200, size.height / 2 + 200)); sp->set

[XMPP]iOS聊天软件学习笔记[三]

今天做了好友界面,其实xmpp内部已经写好很多扩展模块,所以使用起来还是很方便的 开发时间:五天(工作时间) 开发工具:xcode6 开发平台:iOS8 XMPP框架:XMPPFramework git clone https://github.com/robbiehanson/XMPPFramework.git 界面设计:使用StoryBoard github地址:https://github.com/hjandyz/XMPP 1.每一个模块创建以后都需要激活,比如自动连接模块 //自动连接模

[XMPP]iOS聊天软件学习笔记[四]

昨天完成了聊天界面,基本功能算告一段落 开发时间:五天(工作时间) 开发工具:xcode6 开发平台:iOS8 XMPP框架:XMPPFramework git clone https://github.com/robbiehanson/XMPPFramework.git 界面设计:使用StoryBoard github地址:https://github.com/hjandyz/XMPP 1.关于socket在后台的运行,iOS8可以直接使用(但是我自由在模拟器成功,真机不知为何不可以),ios

初探swift语言的学习笔记四(类对象,函数)

作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/29606137 转载请注明出处 假设认为文章对你有所帮助,请通过留言或关注微信公众帐号fengsh998来支持我,谢谢! swift扩展了非常多功能和属性,有些也比較奇P.仅仅有慢慢学习,通过经验慢慢总结了. 以下将初步学习一下类的写法. 码工,最大爱好就是看码,而不是文字,太枯燥. // // computer.swift // swiftDemo // // C

Silverlight动画学习笔记(三):缓动函数

(一)定义: 缓动函数:可以将自定义算术公式应用于动画 (二)为什么要用缓动函数: 您可能希望某一对象逼真地弹回或其行为像弹簧一样.您可以使用关键帧动画甚至 From/To/By 动画来大致模拟这些效果,但可能需要执行大量的工作,并且与使用算术公式相比动画的精确性将降低. (三)实例讲解: 1 <UserControl x:Class="AnimationStudy.EasingFunctionAnimation" 2 xmlns="http://schemas.mic

C++学习笔记8,const在函数方面的使用(二)

7.1和7.1.1由于越狱不成熟,半完美越狱后电脑上无法访问系统越狱目录,如var usr 等等. 今天有些意外地发现,可以在电脑上使用手机的越狱目录我手机 i4 7.1.1 联通 半完美越狱,没装Afc2Add,也没装Appsync 附上  --->我的半完美越狱过程 好了,下面直接正题 一.前提,必须安装ifile! 打开ifile,并转到 /var/mobile/media 目录下,然后点击右上角的 [ 编辑 ]如图: 二.点左下角的 + 号创建,如图: 三.点 [ 类型],选择[符号链接

APUE学习笔记——10.9 信号发送函数kill、 raise、alarm、pause

转载注明出处:Windeal学习笔记 kil和raise kill()用来向进程或进程组发送信号 raise()用来向自身进程发送信号. #include <signal.h> int kill(pid_t pid,int signo); int raise(int signo); Both return: 0 if OK,?1 on error kill向进程号为pid的进程发送signo信号 能够看出 以下两行代码是等价的: kill(getpid(), signo); raise(sig

ZMAN的学习笔记之Python篇:函数可变长参数

ZMAN的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 这次来聊聊Python中函数的“可变长参数”,在实际中经常会用到哦~  一.什么是“可变长参数” “可变长参数”就是向一个函数传入不定个数的参数.比如我写一个函数:传入一个学生参加各科目考试的成绩,求平均分,如两个学生分别传入(92, 91, 88)和(88, 95),因为每个学生参加的考试个数不同,因此传入的参数个数也就不同了,遇到这种情况,我们在定义函数的时候,可以使用“可变长参数”. 二.在定义函数时使用“可变长参数