cocos2d-x 3.1.1 學習筆記[17] 關於函數的那些勾當,cocos2d-x3.1.1
對於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;#endifSequence* 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的,神奇的是居然能傳入四個參數,明擺著就是只認定前兩個參數是有效,後面的統統無效。
學到這裡。貌似對這個流程還是比較清楚的嘛。雖然可能還有更多的只是沒有發現,但是我們還有更多的時間沒有用呀!
怎在cocos2d-x 在已有的類裡自訂一個函數?
class CustomBaseSprite : public Sprite{public: void f();};
c/c++/cocos2d-x 有沒有平方與的函數?
double pfh(double a, double b)
{
return a*a+b*b;
}
main()
{
double a,b;
scanf("%lf%lf",&a,&b);
printf("%lf",pfh(a,b));
}
double