加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-14 16:29:11 所属栏目:百科 来源:网络整理
导读:场景B想场景A回传值的方法很多,这里主要是想讲一下c++实现的委托设计模式,主要为理解下一篇cocos2dx里面的SAX解析XML文件作铺垫。 例子: 点击“next”进入场景B,然后在场景B中点击updata生成一个随机数,但是不在场景B中显示,然后再点击menCallback返回

场景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,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做铺垫。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读