Cocos2dx 3.0 lambda表達式的使用

本篇博客來自star特530,轉載請註明出處http://blog.csdn.net/start530/article/details/19913611

Cocos2dx 3.0 版本後加入了lambda表達式,或者說C++ 11終於引入了lambda表達式,那麼,什麼是lambda表達式呢?

例如調用<algorithm>中的std::sort,ISO C++ 98 的寫法是要先寫一個compare函數:

  1. bool compare(int & a, int & b)  
  2. {  
  3.     return a > b;   // 降序排序  
  4. }  
然後,再這樣調用:

  1. sort(a, a+n, compare);  

然而,用ISO C++ 11 標準新增的Lambda表達式,可以這麼寫:

  1. sort(a, a + n, [](int a, int b){return a > b;}); // 降序排序  
這樣一來,代碼是不是簡潔多了呢?

由於Lambda的類型是唯一的,不能通過類型名來顯式聲明對應的對象,但可以利用auto關鍵字和類型推導

  1. auto f = [](int a, int b){return a > b;});  
和其它語言的一個較明顯的區別是Lambda和C++的類型系統結合使用,如:

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片

  1. auto f = [=](int a, int b){return a > x;}); //x被捕獲複製  
  2. int x = 0, y = 1;  
  3. auto g = [&](int x){return ++y;}); //y被捕獲引用,調用g後會修改y,需要注意y的生存期  
  4. bool(*fp)(intint) = [](int a, int b){return a > b;}); //不捕獲時纔可轉換爲函數指針  

------------------------------------------------------------------------

下面講下在cocos2dx 3.0 應該如何使用lambda:

我先創建一個menu ,如果不使用labmda,menu裏 item 需再寫一個回調函數,如下:

  1. auto closeItem = MenuItemImage::create(  
  2.                                         "CloseNormal.png",  
  3.                                         "CloseSelected.png",  
  4.                                         CC_CALLBACK_1(HelloWorld::menuCloseCallback,this));  
  5.                                           
  6. void HelloWorld::menuCloseCallback(Object* sender)  
  7. {  
  8.     Director::getInstance()->end();  
  9. }  
使用了lambda後,可以這麼使用:

  1. auto closeItem = MenuItemImage::create(  
  2.                                         "CloseNormal.png",  
  3.                                         "CloseSelected.png",  
  4.                                         [](Object* sender)  
  5.                     {  
  6.                         Director::getInstance()->end();//直接在這裏添加按鈕要調用的代碼  
  7.                     });  
這種寫法是不是簡潔很多?當然了,也可以將回調 的代碼單獨取出來,這種寫法的好處是可以多出調用callEnd。如下:

  1. auto callEnd = [](Object* sender)  
  2. {  
  3.     Director::getInstance()->end();//直接在這裏添加按鈕要調用的代碼   
  4. };    
  5. auto closeItem = MenuItemImage::create(  
  6.                                         "CloseNormal.png",  
  7.                                         "CloseSelected.png",  
  8.                     allEnd);      

默認情況下,即捕獲字段爲 [] 時,lambda表達式是不能訪問任何外部變量的,即表達式的函數體內無法訪問當前作用域下的變量。
如果要設定表達式能夠訪問外部變量,可以在 [] 內寫入 & 或者 = 加上變量名,其中 & 表示按引用訪問,= 表示按值訪問,變量之間用逗號分隔,比如 [=factor, &total] 表示按值訪問變量 factor,而按引用訪問 total。

用 & 引用來舉個例子:假設點擊按鈕後,我要創建一個精靈。修改callEnd:

  1. auto callEnd = [](Object* sender)  
  2. {  
  3.     auto sp = Sprite::create("Hello.png");  
  4.     sp->setPosition(Point(100,100));  
  5.     this->addChild(sp,10);//這裏報錯  
  6. };    
上面這種寫法是錯誤的,因爲表達式無法訪問當前作用於的變量。下面繼續改代碼:

  1. auto callEnd = [&](Object* sender)  
  2. {  
  3.     auto sp = Sprite::create("Hello.png");  
  4.     sp->setPosition(Point(100,100));  
  5.     this->addChild(sp,10);//perfect  
  6. };    
這樣就沒問題了。

上面的例子都只是簡單的應用。在cocos2dx用到lambda 的地方還有很多,例如創建一個監聽事件:

  1. // Make sprite1 touchable  
  2. auto sprite1 = Sprite::create();  
  3. auto listener1 = EventListenerTouchOneByOne::create();  
  4. listener1->setSwallowTouches(true);  
  5.   
  6. listener1->onTouchBegan = [](Touch* touch, Event* event){  
  7.     auto target = static_cast<Sprite*>(event->getCurrentTarget());  
  8.     return false;  
  9. };  
  10.   
  11. listener1->onTouchMoved = [](Touch* touch, Event* event){  
  12.     auto target = static_cast<Sprite*>(event->getCurrentTarget());  
  13.     target->setPosition(target->getPosition() + touch->getDelta());  
  14. };  
  15.   
  16. listener1->onTouchEnded = [=](Touch* touch, Event* event){  
  17.     auto target = static_cast<Sprite*>(event->getCurrentTarget());  
  18. };                    
  19.   
  20.  _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1);                                 
  21.       
恩,就這樣子吧。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章