前言


本节主要包括菜单栏的绘制以及添加触发事件,菜单栏又分为两级,如下面两张图,当点击set时,出现模式选择的菜单项。这里主要利用到了 MenuItemLabel进行菜单的实现

设计

对于菜单栏的设计,我们主要从以下两个方面进行:

  • 菜单的绘制

  • 触发事件处理

1. 菜单的绘制

本处的菜单实际而言仍旧是label的绘制,然后封装到 MenuItemLabel中,为其添加回调事件,Label的创建与绘制前一节已经说明,因此此处主要注意的是布局问题,具体可参考后面贴出的代码

autolabel=Label::createWithSystemFont(text,"Airea",26);
//label->setTextColor(Color4B(120,120,255));

autoitem=MenuItemLabel::create(label);
item->setContentSize(size);

对于set界面的绘制中,可以看到一条白色的线段,同样是调用cocos2dx的API进行绘制,主要是DrawNode对象的相关方法

autodraw=DrawNode::create();
this->addChild(draw);
draw->drawLine(Vec2(10,20),Vec2(50,Color4F(0,1));

drawLine(起点, 终点, 颜色) 绘制一条线段, drawCircle(..)绘制圆形。。。。。。


2. 触发事件处理

MenuItem有个回调函数setCallBack()可以直接设定点击后的回调函数,如:

resetmenu->setCallback(CC_CALLBACK_1(GameMenuLayer::resetGameFun,this));

表示当点击resetmenu后,将调用GameMenuLayer::resetGameFun函数,其源码为:

voidGameMenuLayer::resetGameFun(Ref*ref)
{
	GameLayer::getInstance()->restartGame();
	log("resetgame");
}


3. CC_CALLBACK_1

cocos2dx定义的宏,广泛应用于回调函数的处理中,其声明为:

//newcallbacksbasedonC++11
#defineCC_CALLBACK_0(__selector__,__target__,...)std::bind(&__selector__,##__VA_ARGS__)
#defineCC_CALLBACK_1(__selector__,std::placeholders::_1,##__VA_ARGS__)
#defineCC_CALLBACK_2(__selector__,std::placeholders::_2,##__VA_ARGS__)
#defineCC_CALLBACK_3(__selector__,std::placeholders::_3,##__VA_ARGS__)

后面跟随的0,1,2,3分别表示回调函数带0,1,2,3个参数,这里利用了c++11的新特性,使用了std::bind函数

std:: bind函数实现类似函数指针的方法,采用传值传递参数,在对某个函数进行绑定时,可以指定部分参数或全部参数,也可以不指定任何参数,还可以调整各个参数间的顺序。对于未指定的参数,可以使用占位符_1、_2、_3来表示。_1表示绑定后的函数的第1个参数,_2表示绑定后的函数的第2个参数,其他依次类推

bind(callable,arg_list)

其中的callbale表示函数指针,arg_list表示参数列表

#include<iostream>
#include<functional>
usingnamespacestd::placeholders;
usingnamespacestd;
voidnine(inta1,inta2,inta3,inta4,inta5,inta6,inta7,inta8,inta9)
{
cout<<"a1="<<a1<<endl;
cout<<"a2="<<a2<<endl;
cout<<"a3="<<a3<<endl;
cout<<"a4="<<a4<<endl;
cout<<"a5="<<a5<<endl;
cout<<"a6="<<a6<<endl;
cout<<"a7="<<a7<<endl;
cout<<"a8="<<a8<<endl;
cout<<"a9="<<a9<<endl;
}

intmain()

{
	inti=5;
	cout<<"i==5?"<<(i==5)<<endl;
	inti1=1,i2=2,i3=3,i4=4,i5=5,i6=6,i7=7,i8=8,i9=9;
	bind(nine,_9,_8,_7,_6,_5,_4,_3,_2,_1)(i1,i2,i3,i4,i5,i6,i7,i8,i9);
	bind(nie,i1,_1,_1)(i9,i7);
	return0;


}

输出结果为:


实现

菜单栏的实现主要涉及到GameMenuLayer,MenuButton,SetMenu三个文件

  1. MenuButton: 生成MenuItemLabel项并返回

  2. GameMenuLayer: 则包含显示三个主菜单reset,undo,set,并实现对应的回调函数

  3. SetMenu: 则显示set子菜单项目,并实现对应的回调函数(即模式切换)

所有的代码均托管在: ttps://github.com/liuyueyi/2048

MenuButton.cpp

#include"MenuButton.h"

boolMenuButton::init()
{
	if(!Node::init())
		returnfalse;
	else
		returntrue;
}

MenuItem*MenuButton::getMenuItem(conststd::string&text,constSize&size)
{
	autolabel=Label::createWithSystemFont(text,26);
	//label->setTextColor(Color4B(120,255));

	autoitem=MenuItemLabel::create(label);
	item->setContentSize(size);

	returnitem;
}

GameMenuLayer.cpp

#include"GameMenuLayer.h"
#include"MenuButton.h"
#include"GameLayer.h"
#include"GameScene.h"
#include"SetMenu.h"

USING_NS_CC;

GameMenuLayer*GameMenuLayer::_instance=nullptr;
GameMenuLayer*GameMenuLayer::getInstance()
{
	if(_instance==nullptr)
		_instance=create();
	return_instance;
}

boolGameMenuLayer::init()
{
	if(!Layer::init())
		returnfalse;

	this->setContentSize(Size(300,30));
	this->setPosition(Vec2(10,370));

	automenuButton=MenuButton::create();
	autoresetBg=LayerColor::create(Color4B(143,122,101,255),100,30);
	this->addChild(resetBg);
	autoresetmenu=menuButton->getMenuItem("Restart",Size(100,30));
	resetmenu->setPosition(55,17);
	resetmenu->setCallback(CC_CALLBACK_1(GameMenuLayer::resetGameFun,this));
	
	autosetBg=LayerColor::create(Color4B(143,50,30);
	setBg->setPosition(250,0);
	this->addChild(setBg);
	autosetmenu=menuButton->getMenuItem("Set",Size(40,30));
	setmenu->setPosition(275,17);
	setmenu->setCallback(CC_CALLBACK_1(GameMenuLayer::setGameFun,this));
	
	autoundobg=LayerColor::create(Color4B(143,60,30);
	undobg->setPosition(180,0);
	this->addChild(undobg);
	autoundomenu=menuButton->getMenuItem("Undo",Size(60,30));
	undomenu->setPosition(213,17);
	undomenu->setCallback(CC_CALLBACK_1(GameMenuLayer::undoGameFun,this));

	automenu=Menu::create(resetmenu,undomenu,setmenu,NULL);
	//menu->alignItemsHorizontally();
	menu->setPosition(0,0);

	this->addChild(menu);
	returntrue;
}

voidGameMenuLayer::resetGameFun(Ref*ref)
{
	GameLayer::getInstance()->restartGame();
	log("resetgame");
}

voidGameMenuLayer::setGameFun(Ref*ref)
{
	autolayer=static_cast<GameScene*>(this->getParent());
	autosetmenu=layer->getChildByName("setlayer");
	if(setmenu->isVisible())
		setmenu->setVisible(false);
	else
		setmenu->setVisible(true);
	log("startgame");
}

voidGameMenuLayer::undoGameFun(Ref*ref)
{
	GameLayer::getInstance()->undoGame();
	log("backtolaststat");
}

此处对于void GameMenuLayer::setGameFun(Ref* ref) 进行简单说明,这次设计中没有将SetMenu设置为单例模式,添加到父节点的是SetMenu的一个对象,这样的情况下,可以通过getChildByName,getChindByTag函数来获取该对象,然后进行相应的修改

对应的将SetMenu加入场景的代码在GameScene的init函数内:

autosetLayer=SetMenu::create();
	setLayer->setName("setlayer");
	setLayer->setVisible(false);
	this->addChild(setLayer);


SetMenu.cpp

#include"SetMenu.h"
#include"Grid.h"
#include"Gametool.h"
#include"GameLayer.h"
#include"DataConf.h"

boolSetMenu::init()
{
	if(!Layer::init())
		returnfalse;

	this->setContentSize(Size(120,180));
	this->setPosition(Vec2(195,185));

	autobg=LayerColor::create(Color4B(30,30,200),180);
	this->addChild(bg);

	autodraw=DrawNode::create();
	this->addChild(draw);
	//draw->drawLine(Vec2(10,1));

	autoclassic=Label::createWithSystemFont(Grid::G2U("经典模式"),"Arial",25);
	autosoldier=Label::createWithSystemFont(Grid::G2U("小兵模式"),25);
	autocolor=Label::createWithSystemFont(Grid::G2U("纯色模式"),25);
	autosound=Label::createWithSystemFont(Grid::G2U("声音"),25);

	autoitem01=MenuItemLabel::create(classic,CC_CALLBACK_1(SetMenu::classicCallFunc,this));
	item01->setPosition(60,135+22.5f);
	draw->drawLine(Vec2(5,135),Vec2(115,Color4F(1,1,1));
	autoitem02=MenuItemLabel::create(soldier,CC_CALLBACK_1(SetMenu::soldierCallFunc,this));
	item02->setPosition(60,90+22.5f);
	draw->drawLine(Vec2(5,90),1));
	autoitem03=MenuItemLabel::create(color,CC_CALLBACK_1(SetMenu::colorCallFunc,this));
	item03->setPosition(60,45+22.5f);
	draw->drawLine(Vec2(5,45),1));
	autoitem04=MenuItemLabel::create(sound,CC_CALLBACK_1(SetMenu::soundCallFunc,this));
	item04->setPosition(60,22.5f);
	//draw->drawLine(Vec2(5,22.5f),157.5f),1));

	automenu=Menu::create(item01,item02,item03,item04,nullptr);
	//menu->alignItemsvertically();
	menu->setPosition(0,0);
	this->addChild(menu);
	returntrue;
}

voidSetMenu::classicCallFunc(Ref*ref)
{
	changeType(1);
}

voidSetMenu::soldierCallFunc(Ref*ref)
{
	changeType(0);
}

voidSetMenu::colorCallFunc(Ref*ref)
{
	changeType(2);
}

voidSetMenu::soundCallFunc(Ref*ref)
{

}

voidSetMenu::changeType(intnewType)
{
	autotype=Grid::getType();
	if(type==newType)//donotchangethegamemodel
		return;
	//dochange,thensavethegamestatandrestartnewgamemodel
	DataConf::getInstance()->dumpdata(type);
	GameLayer::getInstance()->clearGrids();
	Grid::changeType(newType);
	this->setVisible(false);
}


Label中文显示以及直接添加点击事件

1. 中文显示

Label创建时,直接赋值中文时,会出现问题(不显示内容,或者乱码),主要是编码格式的问题造成的,其解决方法有从xml,json中读取中文,然后传入;或者直接采用下面函数对中文重新编码

char*Grid::G2U(constchar*gb2312)
{
	intlen=MultiBytetoWideChar(CP_ACP,gb2312,-1,NULL,0);
	wchar_t*wstr=newwchar_t[len+1];
	memset(wstr,len+1);
	MultiBytetoWideChar(CP_ACP,wstr,len);
	len=WideCharToMultiByte(CP_UTF8,NULL);
	char*str=newchar[len+1];
	memset(str,len+1);
	WideCharToMultiByte(CP_UTF8,str,len,NULL);
	if(wstr)delete[]wstr;
	returnstr;
}


2. 事件绑定

直接在Label上绑定事件,利用EventListenerTouchOneByOne来实现绑定

autolabel=Label::createWithSystemFont("label",40);
this->addChild(label);
label->setPosition(100,100);
autolistener=EventListenerTouchOneByOne::create();
listener->onTouchBegan=[label](Touch*touch,Event*e){
	log("entered”);
	if(label->getBoundingBox().containsPoint(touch->getLocation()))
		log("trulyclicked");
	returnfalse;
};
Director::getInstance()->getEventdispatcher()->addEventListenerWithSceneGraPHPriority(listener,label);


注意:

  • TouchBegan调用的函数内部的if语句,表示当确切的点击到label时,才会执行相应的代码,也因此需要将具体的逻辑判断写在if语句内

  • 注册listener,除了上面的方法外也可以用_eventdispatcher直接进行,两者效果相同(?)

    • _eventdispatcher->addEventListenerWithSceneGraPHPriority(listener,label);
  • 直接绑定和用MenuItem的区别:具体的原理没有去详细研究,就表观而言,MenuItem点击时,会有明显的标签字体放大的动画效果,而直接绑定触发事件时没有相应动画效果,其次就便捷性而言,MenuItem编程实现更加方便

cocos2dx-v3.5 2048三:菜单实现的更多相关文章

  1. 移动端html5模拟长按事件的实现方法

    这篇文章主要介绍了移动端html5模拟长按事件的实现方法的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. ios – 在applicationWillEnterForeground触发时更改UIView

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  3. UILabel导致应用程序在添加到视图时崩溃(仅限Xcode 6和iOS 8)

    我已将我的项目转换为Xcode6,以便为iOS8构建.但是,特定的UILabel会导致应用程序在添加到视图层次结构时崩溃.这是我收到的唯一错误日志:我无法在项目中的任何位置找到contentInsetsFromFonts方法.此外,我甚至无法在网上任何地方找到它的参考,包括Apple的文档.我没有为这个UIViewController使用NIB,因此UI是在loadView方法中构建的:该应用程序

  4. iOS 7通知中心与标签一样

    您可以试试,也许在将模糊应用到标签之前为模糊添加一点白色.

  5. iOS safari输入插入颜色

    我在iPhone设备上有一个小的CSS问题.我的搜索输入为蓝色,当用户关注它时,插入符号几乎不可见:在所有桌面浏览器中,即使在桌面Safari上,它也具有正确的颜色(白色).知道如何修复此问题并更改iOS设备上的插入颜色吗?

  6. 如何计算iOS 7中的实际字体大小(不是边框)?

    编辑:链接的“重复”问题仅涉及计算文本矩形.我需要在标签缩放之后计算实际字体大小,而不是字符串大小.此方法现已弃用:如何在iOS7中计算UILabel的字体大小,以缩小文字大小以适应?

  7. ios – 为什么在presentmodalviewcontroller调用时,navigationItem.titleView会左对齐?

    我正在使用UILabel作为导航栏的titleView.它工作正常,除了当我呈现模态视图控制器时,titleView从导航栏的中心移动到最左边.我在3.0及以上测试过.这是相关代码:截图:知道为什么会这样吗?

  8. ios – 在XCode中的UI测试期间无法访问自定义视图

    我们必须执行一些时髦的动画,这是我们最好的布局).问题是我无法访问此视图以模拟其上的点击.我可以使用app.staticText[“输入名称…”]访问标签,但是如果我点击它.记录我点击标签的会话将产生app.staticText[“输入名称…”

  9. ios – UITableView以编程方式调用滑动操作

    我有一个UITableView,用户可以向左滑动以显示动作.这一切都按预期工作.当用户点击单元格的某个部分时,我想触发这个.如何以编程方式调用此幻灯片动作?

  10. ios – 在SpriteKit中创建按钮:Swift

    我想在SpriteKit或SKScene中创建一个按钮,将视图发送到另一个视图控制器.我尝试使用“performSeguewithidentifier”,但显然SKScene不支持此功能.如何使用SpriteKit创建一个将视图发送到另一个视图的按钮?这是我尝试用来执行此操作的代码.带有“HomeButton.prepareForSegueWithIdentifier()”的行只是一个例子.它实际

随机推荐

  1. 【cocos2d-x 3.x 学习笔记】对象内存管理

    Cocos2d-x的内存管理cocos2d-x中使用的是上面的引用计数来管理内存,但是又增加了一些自己的特色。cocos2d-x中通过Ref类来实现引用计数,所有需要实现内存自动回收的类都应该继承自Ref类。下面是Ref类的定义:在cocos2d-x中创建对象通常有两种方式:这两中方式的差异可以参见我另一篇博文“对象创建方式讨论”。在cocos2d-x中提倡使用第二种方式,为了避免误用第一种方式,一般将构造函数设为protected或private。参考资料:[1]cocos2d-x高级开发教程2.3节[

  2. 利用cocos2dx 3.2开发消灭星星六如何在cocos2dx中显示中文

    由于编码的不同,在cocos2dx中的Label控件中如果放入中文字,往往会出现乱码。为了方便使用,我把这个从文档中获取中文字的方法放在一个头文件里面Chinese.h这里的tex_vec是cocos2dx提供的一个保存文档内容的一个容器。这里给出ChineseWords,xml的格式再看看ChineseWord的实现Chinese.cpp就这样,以后在需要用到中文字的地方,就先include这个头文件然后调用ChineseWord函数,获取一串中文字符串。

  3. 利用cocos2dx 3.2开发消灭星星七关于星星的算法

    在前面,我们已经在GameLayer中利用随机数初始化了一个StarMatrix,如果还不知道怎么创建星星矩阵请回去看看而且我们也讲了整个游戏的触摸事件的派发了。

  4. cocos2dx3.x 新手打包APK注意事项!

    这个在编译的时候就可以发现了比较好弄这只是我遇到的,其他的以后遇到再补充吧。。。以前被这两个问题坑了好久

  5. 利用cocos2dx 3.2开发消灭星星八游戏的结束判断与数据控制

    如果你看完之前的,那么你基本已经拥有一个消灭星星游戏的雏形。开始把剩下的两两互不相连的星星消去。那么如何判断是GameOver还是进入下一关呢。。其实游戏数据贯穿整个游戏,包括星星消除的时候要加到获得分数上,消去剩下两两不相连的星星的时候的加分政策等,因此如果前面没有做这一块的,最好回去搞一搞。

  6. 利用cocos2dx 3.2开发消灭星星九为游戏添加一些特效

    needClear是一个flag,当游戏判断不能再继续后,这个flag变为true,开始消除剩下的星星clearSumTime是一个累加器ONE_CLEAR_TIME就是每颗星星消除的时间2.连击加分信息一般消除一次星星都会有连击信息和加多少分的信息。其实这些combo标签就是一张图片,也是通过控制其属性或者runAction来实现。源码ComboEffect.hComboEffect.cpp4.消除星星粒子效果消除星星时,为了实现星星爆裂散落的效果,使用了cocos2d提供的粒子特效引擎对于粒子特效不了

  7. 02 Cocos2D-x引擎win7环境搭建及创建项目

    官网有搭建的文章,直接转载记录。环境搭建:本文介绍如何搭建Cocos2d-x3.2版本的开发环境。项目创建:一、通过命令创建项目前面搭建好环境后,怎样创建自己的Cocos2d-x项目呢?先来看看Cocos2d-x3.2的目录吧这就是Cocos2d-x3.2的目录。输入cocosnew项目名–p包名–lcpp–d路径回车就创建成功了例如:成功后,找到这个项目打开proj.win32目录下的Hello.slnF5成功了。

  8. 利用cocos2dx 3.2开发消灭星星十为游戏添加音效项目源码分享

    一个游戏,声音也是非常的重要,其实cocos2dx里面的简单音效引擎的使用是非常简单的。我这里只不过是用一个类对所有的音效进行管理罢了。Audio.hAudio.cpp好了,本系列教程到此结束,第一次写教程如有不对请见谅或指教,谢谢大家。最后附上整个项目的源代码点击打开链接

  9. 03 Helloworld

    程序都有一个入口点,在C++就是main函数了,打开main.cpp,代码如下:123456789101112131415161718#include"main.h"#include"AppDelegate.h"#include"cocos2d.h"USING_NS_CC;intAPIENTRY_tWinMain{UNREFERENCED_ParaMETER;UNREFERENCED_ParaMETER;//createtheapplicationinstanceAppDelegateapp;return

  10. MenuItemImage*图标菜单创建注意事项

    学习cocos2dx,看的是cocos2d-x3.x手游开发实例详解,这本书错误一大把,本着探索求知勇于发现错误改正错误的精神,我跟着书上的例子一起调试,当学习到场景切换这个小节的时候,出了个错误,卡了我好几个小时。

返回
顶部