~~~~我的生活,我的点点滴滴!!
在介绍CC_CALLBACK_X功能之前,我们需要学习一下c++11 的几个新特性 std::function std::bind,总结了一些,先学习学习 狂点这里
我们假设你已经了解点上面的知识,我们来开始学习cocos2d-x 3.0的回调函数绑定新用法,先由helloWorld里面的关闭按钮引起我们的话题 :
auto closeItem = MenuItemImage::create("0.png", "1.png", CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
closeItem->setPosition(Point(400,50));
auto menu = Menu::create(closeItem, NULL);
menu->setPosition(Point::ZERO);
this->addChild(menu);
是不是和2.x的不同,我们不管2.x是怎么用的,反证3.x这个新用法是非常好用的,我们进入CC_CALLBACK_1里面看看到底是什么货色
// 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,##__VA_ARGS__是可变参数宏,std::placeholders之类为占位符,我们发现CC_CALLBACK_1 _2 _3 分别是1-3个事先不绑定参数,和N个可变参数的绑定(##__VA_ARGS__),而且要注意到其中 不指定回调函数参数 和 指定回调函数参数 的顺序,注意不事先指定的在前,事先指定的在后。
我们先粗俗的这样理解一下,如果要绑定的回调函数不带参数 那就使用 CC_CALLBACK_0 如果带有1个就使用CC_CALLBACK_1,依次类推下去,我们看看他怎么和function结合起来用的,看下MenuItemImage::create的声明
/** creates a menu item with a normal and selected image with a callable object */
static MenuItemImage* create(const std::string&normalImage, const std::string&selectedImage, const ccMenuCallback& callback);
最后一个参数是回调的声明,我们去看看
typedef std::function<void(Ref*)> ccMenuCallback;
所以最后直白点就是下面代码
std::function<void(Ref*)> ccMenuCallback = std::bind(&HelloWorld::menuCloseCallback, this, std::placeholders::_1);
我们会疑问,那个事先未绑定的参数是在什么时候传进去的了。我们调试跟踪,在下面这一段代码里面设置进去
在他的直属父类里面,由触摸结束 onTouchEnded 里调用
void Menu::onTouchEnded(Touch* touch, Event* event)
{
CCASSERT(_state == Menu::State::TRACKING_TOUCH, "[Menu ccTouchEnded] -- invalid state");
this->retain();
if (_selectedItem)
{
_selectedItem->unselected();
_selectedItem->activate();
}
_state = Menu::State::WAITING;
this->release();
}
_selectedItem->activate(); 这个activate()为虚函数,他会调用自己的实现
void MenuItem::activate()
{
if (_enabled)
{
if( _callback )
{
_callback(this);
}
#if CC_ENABLE_SCRIPT_BINDING
if (kScriptTypeNone != _scriptType)
{
BasicScriptData data(this);
ScriptEvent scriptEvent(kMenuClickedEvent,&data);
ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&scriptEvent);
}
#endif
}
}
_callback(this)在这里设置了。我们可以把回调函数里面添加两参数,反正是我自己的定义的,来验证一下。
//我们随便添加三个参数,看看对不对,我们在里面只打印输出一下
void menuCloseCallback(cocos2d::Ref* pSender, int a, int b, int c);
auto closeItem = MenuItemImage::create("0.png", "1.png",
std::bind(&HelloWorld::menuCloseCallback, this, std::placeholders::_1, 3, 4, 5));
closeItem->setPosition(Point(400,50));
auto menu = Menu::create(closeItem, NULL);
menu->setPosition(Point::ZERO);
this->addChild(menu);
输出:
menuClose a = 3, b = 4, c = 5
只要确定把不先绑定的放前面,确定的放后面,就行了。
好了,简简单单的把CC_CALLBACK说完了,以后在补充吧。
接下来讲一下怎么添加一个空白Layer层来实现类似于游戏中“暂停”等功能?
实现起来不难,网上搜搜也有很多方法,其他的方法我这里不说,我只想知道通过添加一个空白层到最上面的方法,下面先看代码:
#include "SwallowTouch.h"
SwallowTouch *SwallowTouch::Create(Color4B &color, float width, float height)
{
SwallowTouch *ret = new SwallowTouch();
if( ret && ret->init(color, width, height) )
{
ret->autorelease();
return ret;
}
CC_SAFE_DELETE(ret);
return nullptr;
}
bool SwallowTouch::init(const Color4B& color, GLfloat width, GLfloat height)
{
if( !LayerColor::initWithColor(color, width, height) )
{
return false;
}
auto listener = EventListenerTouchOneByOne::create();
//设置吞噬Touches
listener->setSwallowTouches(true);
//简单的lambda表达式设置返回值为true,必须返回true,这样才能有效
listener->onTouchBegan = [](Touch* touch, Event* event)
{
return true;
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
return true;
}
继承一个LayerColor,当然可以继承Layer,这里我是为了方便设置颜色来显示是否我的“吞噬层”设置成功与否,然后在init里面添加触摸及触摸吞噬(这里我突然豁然开朗了,以前遇到过一个问题,触摸机制没写在Layer层里面后会产生两次触摸,这里算是明白了),
最后只需要在使用的时候,设置他的zOrder值比当前所有的精灵的zOrder都大就ok了,看下面使用代码:
SwallowTouch *st = SwallowTouch::Create(Color4B(0,0,0,100), 200,300);
st->setPosition(Point(visibleSize.width * 0.5, visibleSize.height * 0.5));
//设置一个很大的zOrder
this->addChild(st, 10000);
这样就实现了屏蔽此层下面所有的触摸了。