cocos2dx 3.1从零学习(二)——菜单、场景切换、场景传值
回想一下上一篇的内容,我们已经学会了创建一个新的场景scene,加入sprite和label到层中。掌握了定时事件schedule。
我们能够顺利的写出打飞机的主场景框架。
上一篇的内容我练习了七个新场景。每个场景都展示不同的东西。像背景定时切换、各种字体的随机颜色和位置等。每次要切换一个场景都要改动AppDelegate中的调用代码。很的不方便查看,这一篇我们写场景的切换。每当我们创建一个新的场景的时候仅仅要加入相应button到主界面,点击即能够切换过去查看相应的效果。这个有点类似官方提供的cpptest的查看方式,所以说场景切换是很easy易用的功能。
要点击切换场景,必需要有button能够接收消息。所以首先学习一下菜单(Menu):
Menu创建菜单
MenuItem Create 菜单子项的创建
MenuItemFont是字菜子项。
auto item= MenuItemFont::create("Hello,Menu",CC_CALLBACK_1(MenuScene::Menutest, this));
"Hello, Menu"是菜单子项button的文字。
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); voidMenuScene::Menutest(Ref *ref){
//此处能够加入一个精灵,每点击一次菜单button就加入一个精灵到场景中。 }
还能够这样创建一个菜单,不必每次都调用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,<span style="color:#ff0000;">NULL);//注意最后一个參数为空</span>
menu->setPosition(Director::getInstance()->getVisibleSize().width/ 2,Director::getInstance()->getVisibleSize().height / 2);
menu->alignItemsVerticallyWithPadding(40);//看英文就知道是垂直对齐 间隔40像素
this->addchild(menu);
在回调函数中操作菜单子项的属性:
voidMenuScene::Menutest1(Ref *ref){
MenuItemFont *item =(MenuItemFont *)ref;//全部的类的基类Ref,我们在菜单中是通过MenuItemFont创建的item。所以在回调函数中能够强制转换回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");
}
}
从上面代码能够看到我创建了一个菜单里面有非常多子项,这些子项都是场景切换。
每个新的场景都是一个练习。
见效果图:
关于创建菜单子项还有非常多方法:
MenuItemLabel、MenuItemImage、MenuItemSprite等
以下拿MenuItemLabel举例(futura-48.fnt在我第一篇打飞机源代码的素材里,源代码在一楼,这样的字体除了fnt另一个png文件,是一起的。不能分开。这样的字体创建的菜单就是下图中黄色的效果。)
autoitem2 =MenuItemLabel::create(Label::createWithBMFont("fonts/futura-48.fnt","Start"), CC_CALLBACK_1(MenuSceneTwo::MenuTest, this));
详细的效果图看以下:
这是我的第一个Hello,Menu场景
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGFuYmluZ2Zlbmd5aW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
上面已经介绍了菜单的创建,尝试这去创建一个新场景吧,点击button能够切换不同的背景。
给菜单子项绑定数据
在这里还要学习菜单子项item的两个操作函数。setUserData和setUserObject。
setUserData看定义接收的是void*參数,能够接收随意类型的数据。我们能够用它来传递C++的基本类型数据,可是千万不要自己new一些变量来传值,会造成意外的。
setUserObject接收的是继承自Ref的子类。继承自Ref的子类,最经常使用的就是cocos2dx本身的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();
我们要把set的数据取出来,相应的两个函数是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的getUserObjet获取set的值。
后面三句是场景的正向传值,这个会在本篇最后讲到。提前提一下,就是调用下个场景层对象的成员函数做到传道的。
***********************************************************************************************************************************
切换场景
再创建一个新场景,然后使用以下语句加入到菜单回调函数来切换场景:
auto scene =KTWork_SwitchBg::createScene();
Director::getInstance()->replaceScene(scene);
这样我们就实现了从一个场景切换到还有一个场景。
我们能够在还有一个场景中尽情的加入想要的精灵。你也能够尝试把昨天创建的打飞机的场景加入进来。点击菜单button就能够開始打飞机了。
切换场景动画
假设要使用切换的特效动画,例如以下改动就可以:
auto scene =KTWork_SwitchBg::createScene();
Director::getInstance()->replaceScene(TransitionPageTurn::create(1,scene,true));
还有(TransitionShrinkGrow::create(1,scene)); (TransitionCrossFade::create(1, scene));等
请多尝试几种特效方法Transition******::create()。
假设你想返回主菜单,仅仅须要在子场景中加入一个返回的button就可以,聪明的你肯定能想到怎么返回主菜单。
细心的话会发现切换场景的时候会提示有两个切换方式,一种是replacescene,一种是pushscene。
这两种切换方式的差别在于。前者释放了当前场景,后者把当前场景压入栈中保存。pushscene的场景要切换回来,仅仅需在子场景中调用popscene就可以。
相当于原来的场景暂停了一会。
************************************************************************************************************
场景传值
正向传值
我们在切换场景之前,向下一个场景传递參数。这个是正向传值。
最简单的方法就是给下一个场景的类成员变量赋值。 这样我们就能在主场景控制我们在下一个场景想要展示的属性。
例如以下回调函数,我们返回的场景获取场景中全部的子节点。请右键查看getChildren的返回值。
由于子场景中仅仅有一个节点,所以我们第一个元素肯定是层,也就是
KTWork_PushScene类对象。然后我们能够使用tmp来随意正向传递參数给下个场景。
voidMenuScene::PushScene(Ref *ref){
this->stopAllActions();
auto scene =KTWork_PushScene::createScene();
<span style="color:#ff0000;">KTWork_PushScene * tmp = (KTWork_PushScene*)(scene->getChildren().at(0));</span>
Director::getInstance()->pushScene(TransitionShrinkGrow::create(1,scene));
}
注意:我们在传递參数之前,KTWork_PushScene已经调用过init()函数初始化完成,那我们应该怎么使传递的值生效呢?答案是使用虚函数onEnter()。onEnter是在切换场景后,展示场景前调用。所以我们能够例如以下改动代码:
voidHomeWork::onEnter()
{
<span style="color:#ff0000;"> Layer::onEnter(); //一定要先调用父类onEnter方法</span>
label->setString(StringUtils::format("%s",strHp.getCString()));//这样我们就动态改动了Label展示的值
}
在类中我们通常设变量为私有,通过get、set方法来对其訪问。在cocos2dx中,有一个宏能够替代我们定义这两个方法的操作。
CC_SYNTHESIZE(int, hp, HP);//定义了一个protected变量hp,定义了两个方法setHP,getHP来获取和设置hp的值。
CC_SYNTHESIZE(String, strHp, sHP);
CC_SYNTHESIZE_RETAIN(__String *, strname, Name);//这个针对于指针变量。你如今使用可能会有崩溃的地方,这个在后面的内存管理会具体讲。这个宏定义没有想象的那么简单,提醒一下,要改动类的构造和析构函数。
这两个宏大家一定要自己去看一下是怎样定义的。
通知NotificationCenter
NotificationCenter::getInstance()->addObserver(this, callfuncO_selector(CocosStudio_SkeletonAnimate::onClick), "Ben", NULL);
//收到事件之后要移除观察者以避免内存泄露
NotificationCenter::getInstance()->postNotification("Ben", &CCString("Hello World"));
来看一下addObserver里面的源代码
Ref* obj = nullptr;
CCARRAY_FOREACH(_observers, obj)
{
NotificationObserver* observer = (NotificationObserver*) obj;
if (!observer)
continue; if (observer->getName() == name && observer->getTarget() == target && observer->getSender() == sender)
return true;
}
加入通知的时候会对三个參数进行推断。也就是addObserver的第1、3、4个參数不能一样,否则仅仅会加入一次。
最后一个參数是Ref类型的,能够在回调函数中进行强转。能够对相应的Ref*进行处理,比方Label能够对其进行改动数值等。
最后切记:记得移除观察者(最好在onExit里)
总结:我们学习了菜单,触控响应,切换场景等,如今能够做一个 例如以下的游戏了。
有四种游戏模式。天空会降落雪花。每一种模式雪花大小不同。 鼠标点击能够使雪花小时。游戏结束返回主场景。
效果例如以下:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGFuYmluZ2Zlbmd5aW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGFuYmluZ2Zlbmd5aW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" style="font-size:11pt">
游戏代码我放到一楼去。 这些代码我后期也在优化。
可能有一些知识点还没有涉及到。
大家能够用一下素材。
可能会看到我主场景有飘雪花的特效,一些烟火特效。
这些都是我复制别人的代码实现的。有兴趣的能够自己看一下,非常easy。
cocos2dx 3.1从零学习(二)——菜单、场景切换、场景传值的更多相关文章
- cocos2dx 3.1从零学习(四)——内存管理(错误案例分析)
本篇内容文字比較较多,可是这些都是建立在前面三章写代码特别是传值的时候崩溃的基础上的.可能表达的跟正确的机制有出入,还请指正. 假设有不理解的能够联系我.大家能够讨论一下,共同学习. 首先明白一个事实 ...
- cocos2dx 3.1从零学习(三)——Touch事件(回调,反向传值)
第三讲 Touch 前面两篇我们学习的内容,足够我们做一款简单的小游戏.也能够说,我们已经入门了,能够蹒跚的走路了. 本篇将解说cocos2dx中非常重要的touch回调机制.你肯定记得第一章做定时器 ...
- Vue学习(二)-Vue中组件间传值常用的几种方式
版本说明:vue-cli:3.0 主要分为两类: 1.父子组件间的传值 2.非父子组件间的传值 1.父子组件间传值 父组件向子组件传值 第一种方式: props 父组件嵌套的子组件中,使用v-bind ...
- cocos2dx 3.1从零学习(五)——动画
动画是游戏中最重要的表现部分,本篇仅仅是初步学习大部分动画的用法.没有什么原理性的东西,可是样例有非常多,假设有不熟的地方要练一下. 特别是Spawn和Sequence的组合使用,什么时候使用Spaw ...
- cocos2dx 3.1从零学习(一)——入门篇(一天学会打飞机)
没办法,浏览这么高,为啥没人投票呢?朋友们,我这篇文章參加了csdn博文大赛.喜欢的来点个赞吧!点击:http://vote.blog.csdn.net/Article/Details?article ...
- cocos2dx 3.1从零学习(六)——CocosStudio(VS2013project导入及环境设置)
导入libCocosStudio.libExtensions.libGUI 新建的project例如以下图: 加入现有项目 右键解决方式.例如以下操作: watermark/2/text/aHR0cD ...
- cocos2d-x实战 C++卷 学习笔记--第6章 场景与层
前言: 一个场景(Scene)是由多个层(Layer)组成,而且层的个数要至少是1,不能为0. 场景切换 场景切换相关函数 1)void runWithScene(Scene* scene) 该函 ...
- cocos2dx3.1从零学习(二)菜单、场景切换、场景传值
转:http://www.it165.net/pro/html/201406/16195.html 回顾一下上一篇的内容,我们已经学会了创建一个新的场景scene,添加sprite和label到层中, ...
- 2、JavaScript 基础二 (从零学习JavaScript)
11.强制转换 强制转换主要指使用Number.String和Boolean三个构造函数,手动将各种类型的值,转换成数字.字符串或者布尔值. 1>Number强制转换 参数为原始类型值的转换规 ...
随机推荐
- React-Native 踩坑过程
踩坑过程: 解决方法就是去 SDK Manager 把 23.0.1 的版本下载了 而如果报错信息中含有bintray.com.gradle.org等网址,请***,反复重试,或者去react nat ...
- Thinkpad E450c开启Intel virtual technology
1.重启系统,一直按F12,进入系统设置后,按tab进入App Menu选项卡,选择Setup按回车进入BIOS设置 2.移动到Security选项 3.移动到Virtualization,按ente ...
- 树莓派-基于raspistill实现定时拍照
raspistill 经过上一篇<<树莓派-安装摄像头模块>>之后 raspistill 是树莓派基于摄像头拍照命令 比如我要截取一张宽1024px,高768px,旋转180度 ...
- 利用windbg获取dump的dll文件
根据堆栈对应的地址查找其对应的Module ID,然后将对应的Module保存. !IP2MD 命令从托管函数中获取 MethodDesc 结构地址. !dumpmodule 1caa50 下面的命令 ...
- 导入不同业务数据通过Excel实现
很多公司都用到了老系统移植到新系统,数据自然也需要迁移,这个解决方案之一就是使用Excel文件导入. 结合公司实现,然后简单写了个Demo. (PS:去找朋友本想着花几十分钟弄出来炫耀一波,结果花了三 ...
- android中复制图片
activity_main.xml中的配置 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/androi ...
- Assembly之instruction之Indirect Autoincrement Mode
Assembler Code Content of ROMMOV @R10+,0(R11) MOV @R10+,0(R11) Length: One or two words Operation: ...
- 【技术累积】【点】【java】【18】URLEncode
基础概念 由于以URL的形式传递信息给服务器时,不允许URL中出现一些特殊字符和空格的,所以需要对URL进行编码处理. 原理是: 将要转码的字符转变为16进制: 从右到左,每两位前面加% 哪些字符是需 ...
- react基础篇四
列表 & Keys 渲染多个组件 你可以通过使用{}在JSX内构建一个元素集合 下面,我们使用Javascript中的map()方法遍历numbers数组.对数组中的每个元素返回<li& ...
- Repeater + 分页控件 AspNetPager 研究
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default3.aspx.cs ...