cocos2dx中多个场景之间如何传值

2015年02月08日 11:03 0 点赞 0 评论 更新于 2025-11-21 16:07

为了让大家清楚地了解在 Cocos2d-x 中多个场景之间如何传值,我们将从菜单的创建讲起,逐步展开整个操作流程。

1. 菜单创建基础

在创建新场景时,我们可以添加对应按钮到主界面,点击按钮即可切换场景查看效果,这与官方提供的 cpptest 的查看方式类似,场景切换是一个简单易用的功能。要实现点击切换场景,需要有按钮接收消息,因此我们先学习菜单(Menu)的相关内容。

1.1 菜单及菜单子项的创建

  • MenuItemFont 创建菜单子项示例
    auto item = MenuItemFont::create("Hello,Menu", CC_CALLBACK_1(MenuScene::Menutest, this));
    
  • "Hello, Menu" 是菜单子项按钮显示的文字。
  • MenuScene::Menutest 是回调函数,其参数为 Menutest(Ref * pSender),参数类型可通过查看 create 定义获取。
  • CC_CALLBACK_1 用于绑定一个函数为回调函数,_1 表示该函数只有一个参数。

  • 创建第一个菜单的完整代码

    // 开头这四句添加到 init() 函数里
    auto item = MenuItemFont::create("Hello,Menu", CC_CALLBACK_1(MenuScene::Menutest, this));
    auto menu = Menu::create();
    menu->addChild(item);
    this->addChild(menu);
    

void MenuScene::Menutest(Ref *ref) { // 此处可以添加一个精灵,每点击一次菜单按钮就添加一个精灵到场景中。 }


<a id="heading-2-1-2-另一种菜单创建方式"></a>
### 1.2 另一种菜单创建方式

auto item = MenuItemFont::create("Hello, Menu", CC_CALLBACK_1(MenuScene::Menutest, this)); auto item1 = MenuItemFont::create("Ruck, Menu", CC_CALLBACK_1(MenuScene::Menutest1, this)); auto item2 = MenuItemFont::create("Click, Menu", CC_CALLBACK_1(MenuScene::Menutest2, this)); auto item3 = MenuItemFont::create("KTWork", CC_CALLBACK_1(MenuScene::KTWork, this)); auto item4 = MenuItemFont::create("PushScene", CC_CALLBACK_1(MenuScene::PushScene, this)); auto item5 = MenuItemFont::create("HomeWork", CC_CALLBACK_1(MenuScene::HomeWork, this)); auto item6 = MenuItemFont::create("HomeWork0617", CC_CALLBACK_1(MenuScene::HomeWorkSnow, this)); auto item7 = MenuItemFont::create("KT0618", CC_CALLBACK_1(MenuScene::KT0618, this));

auto menu = Menu::create(item, item1, item2, item3, item4, item5, item6, item7, NULL); // 注意最后一个参数为空 menu->setPosition(Director::getInstance()->getVisibleSize().width / 2, Director::getInstance()->getVisibleSize().height / 2); menu->alignItemsVerticallyWithPadding(40); // 垂直对齐,间隔 40 像素 this->addChild(menu);


<a id="heading-3-1-3-在回调函数中操作菜单子项的属性"></a>
### 1.3 在回调函数中操作菜单子项的属性

void MenuScene::Menutest1(Ref ref) { MenuItemFont item = (MenuItemFont *)ref; // 强制转换回 MenuItemFont 类型 if (item->getColor() == Color3B::RED) { item->setColor(Color3B::GREEN); item->setFontSizeObj(55); item->setFontNameObj("Baskerville-Boldltalic"); item->setString("GreenClick"); } else { item->setColor(Color3B::RED); item->setFontSizeObj(24); item->setFontName("Baskerville-Boldltalic"); item->setString("RedClick"); } }


<a id="heading-4-1-4-其他创建菜单子项的方法"></a>
### 1.4 其他创建菜单子项的方法
除了 `MenuItemFont`,还有 `MenuItemLabel`、`MenuItemImage`、`MenuItemSprite` 等方法。以下以 `MenuItemLabel` 为例:

// futura-48.fnt 在第一篇打飞机源码素材里,这种字体除了 fnt 还有一个 png 文件,需一起使用 auto item2 = MenuItemLabel::create(Label::createWithBMFont("fonts/futura-48.fnt", "Start"), CC_CALLBACK_1(MenuSceneTwo::MenuTest, this));


<a id="heading-5-2--给菜单子项绑定数据"></a>
## 2. 给菜单子项绑定数据
菜单子项 `item` 有两个重要的操作函数:`setUserData` 和 `setUserObject`。

<a id="heading-6-2-1--setUserData-"></a>
### 2.1 `setUserData`
该函数接收 `void*` 类型的参数,可以接收任意类型的数据。但要注意,不要自己 `new` 一些变量来传值,以免造成意外。

<a id="heading-7-2-2--setUserObject-"></a>
### 2.2 `setUserObject`
此函数接收继承自 `Ref` 的子类,最常用的是 Cocos2d-x 本身的 `String` 类。示例代码如下:

auto item1 = MenuItemLabel::create(Label::createWithBMFont("fonts/futura-48.fnt", "Easy"), CC_CALLBACK_1(HomeWorkSnow::Start, this)); item1->setUserObject(String::create("Easy")); auto item2 = MenuItemLabel::create(Label::createWithBMFont("fonts/futura-48.fnt", "Hard"), CC_CALLBACK_1(HomeWorkSnow::Start, this)); item2->setUserObject(String::create("Hard")); auto item3 = MenuItemLabel::create(Label::createWithBMFont("fonts/futura-48.fnt", "Difficult"), CC_CALLBACK_1(HomeWorkSnow::Start, this)); item3->setUserObject(String::create("Difficult")); auto item4 = MenuItemLabel::create(Label::createWithBMFont("fonts/futura-48.fnt", "Hell"), CC_CALLBACK_1(HomeWorkSnow::Start, this)); item4->setUserObject(String::create("Hell"));

auto menu = Menu::create(item1, item2, item3, item4, NULL); addChild(menu); menu->alignItemsVertically();


<a id="heading-8-2-3-获取绑定的数据"></a>
### 2.3 获取绑定的数据
对应的获取数据的函数是 `getUserData` 和 `getUserObject`。在菜单响应回调函数中,操作如下:

void HomeWorkSnow::Start(Ref ref) { MenuItemLabel item = (MenuItemLabel)ref; String str = (String *)item->getUserObject();

auto scene = HomeWorkSnowFight::createScene(); HomeWorkSnowFight layer = (HomeWorkSnowFight)scene->getChildren().at(0);

layer->setData(mode[str->getCString()]); Director::getInstance()->pushScene(TransitionCrossFade::create(1, scene)); }

这里第一步是进行强转,使用什么类型创建的 `item`,在回调里就使用对应的类型强转回来,然后调用 `item` 的 `getUserObject` 获取设置的值。后面三句是场景的正向传值,后面会详细介绍。

<a id="heading-9-3--切换场景"></a>
## 3. 切换场景

<a id="heading-10-3-1-普通场景切换"></a>
### 3.1 普通场景切换
创建一个新场景,并在菜单回调函数中添加以下语句来切换场景:

auto scene = KTWork_SwitchBg::createScene(); Director::getInstance()->replaceScene(scene);

这样就实现了从一个场景切换到另一个场景。在新场景中,我们可以添加想要的精灵,也可以尝试添加之前创建的打飞机场景,点击菜单按钮即可开始游戏。

<a id="heading-11-3-2-切换场景动画"></a>
### 3.2 切换场景动画
如果要使用切换特效动画,修改代码如下:

auto scene = KTWork_SwitchBg::createScene(); Director::getInstance()->replaceScene(TransitionPageTurn::create(1, scene, true));

还有其他特效动画,如 `TransitionShrinkGrow::create(1, scene)`、`TransitionCrossFade::create(1, scene)` 等,可以多尝试不同的特效方法。

<a id="heading-12-3-3--replaceScene--和--pushScene--的区别"></a>
### 3.3 `replaceScene` 和 `pushScene` 的区别
在切换场景时,有 `replaceScene` 和 `pushScene` 两种方式。`replaceScene` 会释放当前场景,而 `pushScene` 会把当前场景压入栈中保存。如果使用 `pushScene` 切换场景,要切换回来,只需在子场景中调用 `popScene` 即可,相当于原来的场景暂停了一会。

<a id="heading-13-4--场景传值"></a>
## 4. 场景传值

<a id="heading-14-4-1-正向传值"></a>
### 4.1 正向传值
在切换场景之前,向下一个场景传递参数,即正向传值。最简单的方法是给下一个场景的类成员变量赋值,从而在主场景控制下一个场景想要展示的属性。示例代码如下:

void MenuScene::PushScene(Ref ref) { this->stopAllActions(); auto scene = KTWork_PushScene::createScene(); KTWork_PushScene tmp = (KTWork_PushScene*)(scene->getChildren().at(0)); Director::getInstance()->pushScene(TransitionShrinkGrow::create(1, scene)); }


<a id="heading-15-4-2-使传递的值生效"></a>
### 4.2 使传递的值生效
注意,在传递参数之前,`KTWork_PushScene` 已经调用过 `init()` 函数初始化完毕。为了使传递的值生效,我们可以使用虚函数 `onEnter()`。`onEnter` 是在切换场景后、展示场景前调用,示例代码如下:

void HomeWork::onEnter() { Layer::onEnter(); // 一定要先调用父类 onEnter 方法 label->setString(StringUtils::format("%s", strHp.getCString())); // 动态修改 Label 展示的值 }


<a id="heading-16-4-3-访问类成员变量的宏"></a>
### 4.3 访问类成员变量的宏
在类中,通常将变量设为私有,通过 `get`、`set` 方法来访问。在 Cocos2d-x 中,有一个宏可以替代我们定义这两个方法的操作。

通过以上步骤,我们详细介绍了在 Cocos2d-x 中创建菜单、切换场景以及场景之间传值的方法,希望能帮助大家更好地掌握相关技术。