cocos2dx场景A跳转到场景B,然后场景B再向A回传值(委托设计模式实现)。

3 篇文章 0 订阅
2 篇文章 0 订阅

场景B想场景A回传值的方法很多,这里主要是想讲一下c++实现的委托设计模式,主要为理解下一篇cocos2dx里面的SAX解析XML文件作铺垫。

  • 例子:点击“next”进入场景B,然后在场景B中点击updata生成一个随机数,但是不在场景B中显示,然后再点击menCallback返回场景A,会在场景A中出现刚刚生成的随机的数字。如下图:

这里写图片描述
这里写图片描述
这里写图片描述

  • 程序思路:定义一个抽象类作为接口,然后在场景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, NULL);
    menu->setPosition(Vec2::ZERO);
    this->addChild(menu, 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做铺垫。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值