场景B想场景A回传值的方法很多,这里主要是想讲一下c++实现的委托设计模式,主要为理解下一篇cocos2dx里面的SAX解析XML文件作铺垫。
- 程序思路:定义一个抽象类作为接口,然后在场景B中调用这个接口,但是这个接口的实现是在场景A中实现,从而实现了将场景B中的参数值传回到了场景A中。
- 类图:场景A为LayerA,场景B为LayerB,抽象类(接口)为Delegator。
LayerB中有Delegator指针对象,所以在LayerB中调用_Delegate里面的callback函数,其实就是在调用LayerA中的callback函数,从而实现把B中的参数回传到A中。 代码:
- Delegator类,抽象类只定义.h文件
class Delegator
{
public:
virtual ~Delegator(){};
virtual void callback(void* ctx,const char* str) = 0;
};
其中callback是纯虚函数,必须在子类中实现,就是在LayerA类中实现。这个函数就是将生成的数,按照const char*的格式传回到LayerA。为什么是这个格式?因为cocos2dx用的的字符串格式就是const char*而不是std::string。前面的void*是无类型的指针格式,就是可以存储任何指针类型,这个参数在后面介绍。
- LayerB类的.h文件
#include "cocos2d.h"
#include "Delegator.h"
class LayerB : public cocos2d::Layer
{
Delegator* _Delegate;
public :
static cocos2d::Scene* createScene();
virtual bool init();
void menUpdata(cocos2d::Ref* pSender);
void menCallback(cocos2d::Ref* pSender);
void setDelegator(Delegator* delegator);
CREATE_FUNC(LayerB);
};
static cocos2d::Scene* createScene();
virtual bool init();
这两个函数是cocos2dx场景模板自带的(静态工厂创建模式),不是今天介绍的内容。
void menUpdata(cocos2d::Ref* pSender);
是随机生成数字的函数
Delegator* _Delegate;
void setDelegator(Delegator* delegator);
重点说下这两行代码,因为抽象函数是不能实例化对象的,所以要想创建Delegator类的对象指针,必须有其子类实现了基类里的纯虚函数,这个类就是LayerA,所以要把指向LayerA对象的指针赋值给_Delegate变量,LayerB才能算是“拥有了”Delegator接口。显然,setDelegator()函数的任务就是完成这项任务。
- LayerB的.cpp文件
#include "LayerB.h"
#include "Delegator.h"
USING_NS_CC;
Scene* LayerB::createScene()
{
auto scene = Scene::create();
auto layer = LayerB::create();
scene->addChild(layer);
return scene;
}
bool LayerB::init()
{
if ( !Layer::init() )
{
return false;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
//Updata菜单
auto menUpdata = MenuItemFont::create("Updata",CC_CALLBACK_1(LayerB::menUpdata,this));
menUpdata->setPosition(Vec2(visibleSize.width,visibleSize.height)/2);
//menCallback菜单
auto menCallback = MenuItemFont::create("menCallback",CC_CALLBACK_1(LayerB::menCallback,this));
menCallback->setPosition(Vec2(visibleSize.width/2,visibleSize.height/2 - 100));
auto menu = Menu::create(menUpdata,menCallback,NULL);
menu->setPosition(Vec2::ZERO);
this->addChild(menu,1);
return true;
}
void LayerB::menUpdata(Ref* pSender)
{
int num = CCRANDOM_0_1() * 1000;
__String* str = __String::createWithFormat("Updata %d",num);
//回调A场景
_Delegate->callback(this,str->getCString());
}
第一行:随机生成一个1000以内的数字
第二行:讲生成的数字用__String类提供的方法加上”Updata “字符串, 组合成__String*类型
第三行:调用Delegator接口的方法,即将字符串传回LayerA中,因为该方法是在LayerA中实现的。记得要把__String转换成const char*类型,this就是LayerB当前的对象指针,这个最后再说它,这里它没什么用。
void LayerB::menCallback(Ref* pSender)
{ Director::getInstance()->popScene(); }
退出该场景没什么说的。
void LayerB::setDelegator(Delegator* Delegator)
{
_Delegate = Delegator;
}
这个函数功能在上面介绍过,他的使用是在LayerA中使用,到时候在具体说。
- LayerA类的.h文件
#include "cocos2d.h"
#include "LayerB.h"
#include "Delegator.h"
class LayerA : public cocos2d::Layer,public Delegator
{
public:
static cocos2d::Scene* createScene();
virtual bool init();
//跳转到场景B
void menNextScene(cocos2d::Ref* pSender);
//实现接口
virtual void callback(void* ctx,const char* str);
CREATE_FUNC(LayerA);
};
这里说一点值得注意的是LayerA类是继承了cocos2d::Layer和 Delegator这两个类,这是为什么可以把LayerA类的对象的指针赋值给LayerB对象里面的Delegator*类型的成员变量_Delegate。
- LayerB的.cpp文件
#include "LayerA.h"
USING_NS_CC;
Scene* LayerA::createScene()
{
auto scene = Scene::create();
auto layer = LayerA::create();
scene->addChild(layer);
return scene;
}
bool LayerA::init()
{
if ( !Layer::init() )
{
return false;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
//next菜单
auto muNext = MenuItemFont::create("Next Scene",CC_CALLBACK_1(LayerA::menNextScene,this));
muNext->setPosition(Vec2(visibleSize.width,visibleSize.height)/2);
auto menu = Menu::create(muNext,1);
//场景A显示传回来的的随机数字标签
auto label = Label::createWithTTF("","fonts/Marker Felt.ttf",24);
label->setPosition(Vec2( visibleSize.width/2,visibleSize.height/2 -100 ));
this->addChild(label,1,100);
return true;
}
void LayerA::menNextScene(Ref* pSender)
{
auto sc = Scene::create();
auto layerB = LayerB::create();
layerB->setDelegator(this);
sc->addChild(layerB);
Director::getInstance()->pushScene(sc);
}
第一行:创建一个场景
第二行:创建LayerB的对象指针,即创建LayerB的层
第三行:调用layerB的函数把LayerA层的对象指针(this)赋值给layerB对象里的成员变量_Delegate。因为LayerA的对象的类同时继承了Delegator类和cocos2d::Layer类,所以可以把这个指针赋值给Delegator类的指针变量_Delegate。
void LayerA::callback(void* ctx,const char* str)
{
Label* label = (Label*)this->getChildByTag(100);
if(label){
label->setString(str);
}
}
该函数实现了Delegator抽象类里面的纯虚函数,还记得LayerB中的menUpdata函数调用了它吗?他会把参数传到这里来进行处理。
第一行:获得场景A(this)中Tag为100的标签
第二行:如果存在,就给标签添加str字符串,str就是LayerB中传回来的的参数值。
到此就算实现了,但是还有一个void* ctx参数没有用,并且在LayerB的menUpdata函数里面给他传进来的是this,即LayerB的对象指针。你们如何使用它呢?不能直接用,要转换类型。如下
//这样转换后layer就相当于LayerB的对象指针
LayerB* layer = (LayerB*)ctx;
//这样转换后layer就相当于LayerA的对象指针
LayerA* layer = (LayerA*)ctx;
这样在callback()函数里面就可以调用LayerB的对象指针进行操作了,这里没有用到,但是在cocos2dx继承的SAX方式解析XML文件的时候函数理由有void* ctx这个参数,在解析的时候会用到,写他是为了为解析XML做铺垫。