cocos2dx怎么在按钮实现场景切换

2015年03月03日 10:43 0 点赞 0 评论 更新于 2025-11-21 16:36

要实现点击按钮切换场景,首先需要有按钮来接收消息。下面我们先从菜单(Menu)的创建开始学习。

1. 菜单及菜单子项的创建

1.1 基本概念

  • Menu:用于创建菜单。
  • MenuItem:用于创建菜单子项。常见的菜单子项创建类有 MenuItemFontMenuItemLabelMenuItemImageMenuItemSprite 等。

1.2 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 表示该函数只有一个参数。

1.3 创建第一个菜单

以下代码需添加到 init() 函数中:

// 1. 创建菜单子项
auto item = MenuItemFont::create("Hello,Menu", CC_CALLBACK_1(MenuScene::Menutest, this));
// 2. 创建菜单
auto menu = Menu::create();
// 3. 将菜单子项添加到菜单中
menu->addChild(item);
// 4. 将菜单添加到当前场景
this->addChild(menu);

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

1.4 另一种创建菜单的方式

可以一次性创建多个菜单子项并添加到菜单中,避免多次调用 menu->addChild(item)

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);
// 垂直对齐,间隔 40 像素
menu->alignItemsVerticallyWithPadding(40);
// 将菜单添加到当前场景
this->addChild(menu);

2. 在回调函数中操作菜单子项的属性

void MenuScene::Menutest1(Ref *ref) {
// 强制转换为 MenuItemFont 类型
MenuItemFont *item = (MenuItemFont *)ref;
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");
}
}

3. 其他创建菜单子项的方法

除了 MenuItemFont,还有 MenuItemLabelMenuItemImageMenuItemSprite 等方法。以下以 MenuItemLabel 为例:

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

4. 给菜单子项绑定数据

4.1 相关操作函数

  • setUserData:接收 void* 参数,可接收任意类型的数据,可用于传递 C++ 的基本类型数据,但不要自己 new 变量传值,以免造成意外。
  • setUserObject:接收继承自 Ref 的子类,常用的如 Cocos2d-x 本身的 String

4.2 示例代码

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();

4.3 获取绑定的数据

void HomeWorkSnow::Start(Ref *ref) {
// 强制转换为 MenuItemLabel 类型
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));
}

5. 切换场景

5.1 基本场景切换

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

5.2 带特效的场景切换

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

还有 TransitionShrinkGrow::create(1, scene)TransitionCrossFade::create(1, scene) 等特效方法,可多尝试不同的特效。

5.3 两种切换方式的区别

  • replaceScene:释放当前场景。
  • pushScene:将当前场景压入栈中保存,切换回来只需在子场景中调用 popScene,相当于原来的场景暂停了一会。

6. 场景传值

6.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));
}

6.2 使传递的值生效

由于在传递参数之前,KTWork_PushScene 已经调用过 init() 函数初始化完毕,可使用虚函数 onEnter() 使传递的值生效。

void HomeWork::onEnter() {
Layer::onEnter(); // 一定要先调用父类 onEnter 方法
label->setString(StringUtils::format("%s", strHp.getCString()));
}

6.3 宏定义简化操作

在 Cocos2d-x 中,可使用宏来替代定义 getset 方法的操作。

CC_SYNTHESIZE(int, hp, HP); // 定义了一个 protected 变量 hp,定义了两个方法 setHP, getHP 来获取和设置 hp 的值。
CC_SYNTHESIZE(String, strHp, sHP);
CC_SYNTHESIZE_RETAIN(__String *, strname, Name); // 针对于指针变量,使用时可能会有崩溃问题,后续内存管理会详细讲解,使用该宏需修改类的构造和析构函数。

总结

通过学习菜单的创建、触控响应、场景切换和场景传值等知识,现在可以尝试制作一个简单的游戏了。

作者信息

boke

boke

共发布了 3994 篇文章