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

前言


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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


    本文实践自 RayWenderlich、Ali Hafizji 的文章《How To Create Dynamic Textures with CCRenderTexture in Cocos2D 2.X》,文中使用Cocos2D,我在这里使用Cocos2D-x 2.1.4进行学习和移植。在这篇文章,将会学习到如何创建实时纹理、如何用Gimp创建无缝拼接纹
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@163.com微信公众号:HopToad 欢迎转载,转载标注出处:http://blog.csdn.netotbaron/article/details/424343991.  软件准备 下载地址:http://cn.cocos2d-x.org/download 2.  简介2.1         引用C
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从Cocos2D-x官网上下载,进入网页http://www.cocos2d-x.org/download,点击Cocos2d-x以下的Download  v3.0,保存到自定义的文件夹2:从python官网上下载。进入网页https://www.python.org/downloads/,我当前下载的是3.4.0(当前最新
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发引擎,易学易用,支持多种智能移动平台。官网地址:http://cocos2d-x.org/当前版本:2.0    有很多的学习资料,在这里我只做为自己的笔记记录下来,错误之处还请指出。在VisualStudio2008平台的编译:1.下载当前稳
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《最强大脑》娱乐节目。将2048改造成一款挑战玩家对数字记忆的小游戏。邮箱:appdevzw@163.com微信公众号:HopToadAPK下载地址:http://download.csdn.net/detailotbaron/8446223源码下载地址:http://download.csdn.net/
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试以QtCreatorIDE来进行CMake构建。Cocos2d-x3.X地址:https://github.com/cocos2d/cocos2d-x1.打开QtCreator,菜单栏→"打开文件或项目...",打开cocos2d-x目录下的CMakeLists.txt文件;2.弹出CMake向导,如下图所示:设置
 下载地址:链接:https://pan.baidu.com/s/1IkQsMU6NoERAAQLcCUMcXQ提取码:p1pb下载完成后,解压进入build目录使用vs2013打开工程设置平台工具集,打开设置界面设置: 点击开始编译等待编译结束编译成功在build文件下会出现一个新文件夹Debug.win32,里面就是编译
分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net前言上次用象棋演示了cocos2dx的基本用法,但是对cocos2dx并没有作深入的讨论,这次以超级马里奥的源代码为线索,我们一起来学习超级马里奥的实
1. 圆形音量button事实上作者的本意应该是叫做“电位计button”。可是我觉得它和我们的圆形音量button非常像,所以就这么叫它吧~先看效果:好了,不多解释,本篇到此为止。(旁白: 噗。就这样结束了?)啊才怪~我们来看看代码:[cpp] viewplaincopyprint?CCContro
原文链接:http://www.cnblogs.com/physwf/archive/2013/04/26/3043912.html为了进一步深入学习贯彻Cocos2d,我们将自己写一个场景类,但我们不会走的太远,凡是都要循序渐进,哪怕只前进一点点,那也至少是前进了,总比贪多嚼不烂一头雾水的好。在上一节中我们建
2019独角兽企业重金招聘Python工程师标准>>>cocos2d2.0之后加入了一种九宫格的实现,主要作用是用来拉伸图片,这样的好处在于保留图片四个角不变形的同时,对图片中间部分进行拉伸,来满足一些控件的自适应(PS: 比如包括按钮,对话框,最直观的形象就是ios里的短信气泡了),这就要求图
原文链接:http://www.cnblogs.com/linji/p/3599478.html1.环境和工具准备Win7VS2010/2012,至于2008v2版本之后似乎就不支持了。 2.安装pythonv.2.0版本之前是用vs模板创建工程的,到vs2.2之后就改用python创建了。到python官网下载版本2.7.5的,然后
环境:ubuntu14.04adt-bundle-linux-x86_64android-ndk-r9d-linux-x86_64cocos2d-x-3.0正式版apache-ant1.9.3python2.7(ubuntu自带)加入环境变量exportANDROID_SDK_ROOT=/home/yangming/adt-bundle-linux/sdkexportPATH=${PATH}:/$ANDROID_SDK_ROOTools/export
1开发背景游戏程序设计涉及了学科中的各个方面,鉴于目的在于学习与进步,本游戏《FlappyBird》采用了两个不同的开发方式来开发本款游戏,一类直接采用win32底层API来实现,另一类采用当前火热的cocos2d-x游戏引擎来开发本游戏。2需求分析2.1数据分析本项目要开发的是一款游
原文链接:http://www.cnblogs.com/linji/p/3599912.html//纯色色块控件(锚点默认左下角)CCLayerColor*ccc=CCLayerColor::create(ccc4(255,0,0,128),200,100);//渐变色块控件CCLayerGradient*ccc=CCLayerGradient::create(ccc4(255,0,0,
原文链接:http://www.cnblogs.com/linji/p/3599488.html//载入一张图片CCSprite*leftDoor=CCSprite::create("loading/door.png");leftDoor->setAnchorPoint(ccp(1,0.5));//设置锚点为右边中心点leftDoor->setPosition(ccp(240,160));/
为了答谢广大学员对智捷课堂以及关老师的支持,现购买51CTO学院关老师的Cocos2d-x课程之一可以送智捷课堂编写图书一本(专题可以送3本)。一、Cocos2d-x课程列表:1、Cocos2d-x入门与提高视频教程__Part22、Cocos2d-x数据持久化与网络通信__Part33、Cocos2d-x架构设计与性能优化内存优
Spawn让多个action同时执行。Spawn有多种不同的create方法,最终都调用了createWithTwoActions(FiniteTimeAction*action1,FiniteTimeAction*action2)方法。createWithTwoActions调用initWithTwoActions方法:对两个action变量初始化:_one=action1;_two=action2;如果两个a
需要环境:php,luajit.昨天在cygwin上安装php和luajit环境,这真特么是一个坑。建议不要用虚拟环境安装打包环境,否则可能会出现各种莫名问题。折腾了一下午,最终将环境转向linux。其中,luajit的安装脚本已经在quick-cocos2d-x-develop/bin/中,直接luajit_install.sh即可。我的lin
v3.0相对v2.2来说,最引人注意的。应该是对触摸层级的优化。和lambda回调函数的引入(嗯嗯,不枉我改了那么多类名。话说,每次cocos2dx大更新。总要改掉一堆类名函数名)。这些特性应该有不少人研究了,所以今天说点跟图片有关的东西。v3.0在载入图片方面也有了非常大改变,仅仅只是