cocos2dx怎么在按钮实现场景切换
要实现点击按钮切换场景,首先需要有按钮来接收消息。下面我们先从菜单(Menu)的创建开始学习。
1. 菜单及菜单子项的创建
1.1 基本概念
- Menu:用于创建菜单。
- MenuItem:用于创建菜单子项。常见的菜单子项创建类有
MenuItemFont、MenuItemLabel、MenuItemImage、MenuItemSprite等。
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,还有 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));
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 中,可使用宏来替代定义 get、set 方法的操作。
CC_SYNTHESIZE(int, hp, HP); // 定义了一个 protected 变量 hp,定义了两个方法 setHP, getHP 来获取和设置 hp 的值。
CC_SYNTHESIZE(String, strHp, sHP);
CC_SYNTHESIZE_RETAIN(__String *, strname, Name); // 针对于指针变量,使用时可能会有崩溃问题,后续内存管理会详细讲解,使用该宏需修改类的构造和析构函数。
总结
通过学习菜单的创建、触控响应、场景切换和场景传值等知识,现在可以尝试制作一个简单的游戏了。