cocos2dx-v3.5 2048(三):菜单实现

cocos2dx-v3.5 2048(三):菜单实现,第1张

概述前言 本节主要包括菜单栏的绘制以及添加触发事件,菜单栏又分为两级,如下面两张图,当点击set时,出现模式选择的菜单项。这里主要利用到了 MenuItemLabel进行菜单的实现   设计 对于菜单栏的设计,我们主要从以下两个方面进行: 菜单的绘制 触发事件处理 1. 菜单的绘制     本处的菜单实际而言仍旧是label的绘制,然后封装到 MenuItemLabel中,为其添加回调事件,Label 前言


本节主要包括菜单栏的绘制以及添加触发事件,菜单栏又分为两级,如下面两张图,当点击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三个文件

Menubutton: 生成MenuItemLabel项并返回

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

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(三):菜单实现全部内容,希望文章能够帮你解决cocos2dx-v3.5 2048(三):菜单实现所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/web/1056232.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存