cocos2dx原生的menu排版函数实现的非常无完整,像最主要的Item的排序要想做得略微美丽一些就须要我们自己实现。

对于Menu我们能够用两种方法来实现:

1.大神级别。 继承自Control,自己来封装新的Menu类,要求我们可以友好的去抽象定义基类。

2.半仙级别。改动MenuItem的函数或者重写一套对于Item的排序函数。做到自己想要的排版。

3.菜鸟级别。继承自Node,在Node中加入�成员变量Menu,针对不同的UI设置Item的位置和动画。

这里解析一下第三种方法,第一种方法确实是最好的,做到基类重用,可是一些动态的效果跟3一样写,没有一个好的架构就还是老老实有用3吧。

保卫萝卜的菜单分为建塔菜单和升级塔的菜单。比較难的是建造塔的菜单,这个菜单的实现有几个技术难点:

1.依据当前关卡的塔来创建item

2.塔假设超过4种要分两行

3.Menu要依据屏幕位置动态适应position

4.show和hide菜单的时候要实现动画,Item都是放大和缩小后才隐藏的。

(进入关卡前资源一定要实现动态异步载入,仅仅载入本关所须要的素材,还有各种文件的异步载入,详细的參考我的上一篇博客)

先看下效果图吧:

这篇blog我不会贴代码了,仅仅解说一下框架逻辑。

首先定义一个类继承自MenuItem,简单封装一下Menuitem,让我们后面能够推断点击到的item是哪一种塔,由于我们要展示item是否为可点击状态。 假设金币不够的话是不同意建造塔的。

然后创建一个Node。

createMenuItem的时候是依据当前关卡的配置信息来创建的,创建全部Item到成员变量
cocos2d::Vector<cocos2d::MenuItem*> menuItems;中,以便我们后期运行Item动画。

假设超过4种塔,我们就再加入�一个Menu,在Node中加入�两个Menu来控制排版。

定义成员函数void updateItemsPosition(int row, int col),依据当前点击砖块的位置,在Node中动态设置Menu的位置。

最后就是第四步了,实现show和hide动画。

这样就非常easy了,仅仅需动画运行完隐藏就好,例如以下:

void *****::hide()
{
if (!m_pRangeSprite->isVisible())
{
return;
}
ScaleTo *scaleTo = ScaleTo::create(CW_UPTOWERMENU_ANIM_DURATION, 0.0f);
auto callc = CallFunc::create(CC_CALLBACK_0(UpTowerMenu::hideMe, this));
m_pRangeSprite->runAction(CCSequence::create(scaleTo, callc, NULL));
}

到这里就能够做出全然一样的菜单了,这是一种比較简单的方法,类似的升级菜单也是如此。

吐槽一下:

今天TX电话面试了,面试的时候各种抓瞎。

问我多线程渲染啊,函数式编程啊,还有怎么省电。。

当时被问的我就说不会了,没看过源代码,不理解底层。。。

下来一看神马多线程渲染,就是异步载入,底层一个队列来异步载入资源的,源代码也看过了。。。我以为是opengl画图性能多线程。。屏幕分块渲染呢,完蛋了。

还有函数式编程,我说不会没听过。。。尼玛原来是lua闭包,lambda函数,IOSblock。。。。我居然说不会!!!

省电这个就确实不太理解了,可能也是概念上的问题吧,不知道咋整了,这一面感觉好蛋疼。。。求过了!!!!

补:官网首页推荐了,我就贴一下源代码吧!

BuyTowerMenu.h

/*************************************************
Copyright:bro7
Author:ben
Date:2014-07-30
Description:保卫萝卜建造塔菜单动画的实现
PS:锚点也会变小,非0-1,是依照比例来变化的,注意坑。
**************************************************/ #ifndef __BUYTOWERMENU_H__
#define __BUYTOWERMENU_H__ #include "cocos2d.h"
#include "BuyTowerMenuItem.h" class BuyTowerMenu :public cocos2d::Node
{
public:
BuyTowerMenu();
~BuyTowerMenu(); bool init();
CREATE_FUNC(BuyTowerMenu); void hide();
void show(); cocos2d::Vector<cocos2d::MenuItem*> menuItems; private:
void menuCallback(Ref* sender);
void createMenu();
void updateMenu();
}; #endif

BuyTowerMenu.cpp

#include "BuyTowerMenu.h"
#include "GameScene.h"
#include "GlobalData.h" USING_NS_CC;
const float gTileWidth = 80.0f; BuyTowerMenu::BuyTowerMenu()
{
} BuyTowerMenu::~BuyTowerMenu()
{
} bool BuyTowerMenu::init()
{
if (!Node::init())
{
return false;
}
//依据当前关卡的tower信息来创建menu
createMenu();
return true;
} void BuyTowerMenu::createMenu()
{
cocos2d::ValueVector towerTypes = GlobalData::getInstance()->getTowerTypes();
float ratio = GlobalData::getInstance()->getRatio();
for (auto tower : towerTypes)
{
int buildGold = GlobalData::getInstance()->getTowerConfig().at(tower.asString()).asValueMap().at("price").asInt();
auto towerNormalFile = GlobalData::getInstance()->getTowerConfig().at(tower.asString()).asValueMap().at("buy").asString();
auto towerDisabledFile = GlobalData::getInstance()->getTowerConfig().at(tower.asString()).asValueMap().at("buy").asString();
auto spNormal = Sprite::createWithSpriteFrameName(towerNormalFile);
auto spDisable = Sprite::createWithSpriteFrameName(towerNormalFile); auto item = BuyTowerMenuItem::create( spNormal, spNormal, spDisable, CC_CALLBACK_1(BuyTowerMenu::menuCallback, this));
item->setEnabledGold(buildGold);
item->setTowerName(tower.asString());
item->setPosition(0, 0);
menuItems.pushBack(item); }
//alignItemsInColumns 搞不定padding的问题 所以弃用 改为使用两个menu合成一个menu
//使用方法enum->alignItemsInColumns(2, menuItems.size() - 2);
const int num = 4;
if (menuItems.size() <= num)
{
auto menu = Menu::createWithArray(menuItems);
menu->setScale(0.5f);
menu->setPosition(0, 0);
menu->setAnchorPoint(Point(0, 0));
menu->alignItemsHorizontallyWithPadding(0);
this->addChild(menu);
this->setContentSize(Size(gTileWidth * ratio*menuItems.size(), gTileWidth*ratio));
}
else
{
Vector<cocos2d::MenuItem*> tempItems;
for (int i = 0; i < num;i++)
{
tempItems.pushBack(menuItems.at(i));
}
auto menu = Menu::createWithArray(tempItems);
menu->alignItemsHorizontallyWithPadding(0);
menu->setPosition(0, 0);
menu->setScale(0.5f);
menu->setAnchorPoint(Point(0, 0));
this->addChild(menu);
tempItems.clear();
for (int i = num; i < menuItems.size();i++)
{
tempItems.pushBack(menuItems.at(i));
menuItems.at(i)->setPosition(menuItems.at(i - num)->getPosition() + Point(0, -gTileWidth));
}
menu = Menu::createWithArray(tempItems);
menu->setPosition(0, 0);
menu->setAnchorPoint(Point(0, 0));
menu->setScale(0.5f);
this->setContentSize(Size(gTileWidth *ratio* num, gTileWidth *ratio * 2));
this->addChild(menu);
}
} void BuyTowerMenu::menuCallback(Ref* sender)
{
auto item = dynamic_cast<BuyTowerMenuItem*>(sender);
std::string strTowerName = item->getTowerName();
GameScene::getInstance()->buildTower(strTowerName, GameScene::getInstance()->getBuildPostion()); } void BuyTowerMenu::show()
{
//菜单展示的时候运行动画
for (auto item : menuItems)
{
item->runAction(ScaleTo::create(0.1f, 1.0f));
}
this->setVisible(true);
} void BuyTowerMenu::hide()
{
if (!this->isVisible())
{
return;
}
for (auto item : menuItems)
{
item->runAction(ScaleTo::create(0.1f, 0.0f));
}
this->setVisible(false);
GameScene::getInstance()->clearFocusGrid();
} //当金币变化的时候 接收金币变化通知更改菜单展示
void BuyTowerMenu::updateMenu()
{ }

适应屏幕位置的代码,由于我是整个项目的代码非常多变量大家可能看不懂,而且像这个函数最好写在Menu类里面,仅仅须要坐标转换一下就OK了,不要像我放到GameScene。

//在砖块坐标gridCol,gridRow的位置展示Menu
void GameScene::showAtGrid(int gridCol, int gridRow)
{
//获取建造塔菜单的大小;
Size contentSize = buyTowerMenu->getContentSize();
if (gridRow >= 0 && gridRow <= 6 && gridCol >= 0 && gridCol <= 11)
{
Grid *tg = m_map[gridCol][gridRow];
Point curGirdPoint = m_GameMap->getPosFromGrids(Point(gridCol, gridRow));
Point pos = Point(curGirdPoint.x + contentSize.width / 2 - TILEWIDTH / 4, curGirdPoint.y + contentSize.height); if (pos.x + contentSize.width / 2 > size.width - TILEHEIGHT / 2)
pos.x = size.width - contentSize.width / 2; if (pos.y + contentSize.height / 2 >= size.height)
{
pos.y = pos.y - contentSize.height - TILEHEIGHT / 2;
}
buyTowerMenu->setPosition(pos);
buyTowerMenu->show();
m_focusgrid = tg;
buildPostion = m_focusgrid->getPosition();
tg->playBlinkArmature();
}
}

Menu的自己定义实现-------保卫萝卜造塔升级塔菜单实现的更多相关文章

  1. 【转】 Pro Android学习笔记(三一):Menu(2):扩展、图片、子菜单

    目录(?)[-] 菜单扩展 菜单项加入图片 子菜单 菜单扩展 如果菜单项很多,超过六个时,就会采用菜单扩展模式.在例子中我加入了10个菜单项,预计能进入菜单扩展模式,但是实际效果如右图所示.效果和li ...

  2. Android 造炫目的圆形菜单 秒秒钟高仿建行圆形菜单

    1.概述 今天打开建行看存款,一看伤心欲绝,再看:我擦,这个圆形菜单挺炫.于是,为了掩盖我悲痛的心情,我决定是实现这个效果.好了,其实还有个原因,记得我初学android那会我做的应用被鄙视了,说我的 ...

  3. 安装Ubuntu 16.04时出现:没有定义根文件系统,请到分区菜单修改

    在安装Ubuntu 16.04时,尤其是选项空闲硬盘新建分区安装时,容易出现这种情况,这个是由于没有配置挂载点导致的,解决方法如下: 在挂在点输入“/”. 原理: Linux和Windows的文件系统 ...

  4. WINDOWS资源编译器出错信息

    ACCELERATORS语句的type域应包含ASCⅡ值或VIRTKEY值.        BEGIN expected in table        BEGIN关键字应紧跟在ACCELERATOR ...

  5. 【转载】IDEA:放置型塔防备忘录

    下周开始做原型了,我需要再次细细的整理一遍设计思路,确保每一个设计都能为了我所追求的玩家体验添砖加瓦,而不是互相打架.同时本文还能提供最原始的VISION,待到将来开发万一陷入泥淖,翻出此文来可以起到 ...

  6. Menu创建菜单

    菜单是用户界面中最常见的元素之一,使用非常频繁,在Android中,菜单被分为如下三种,选项菜单(OptionsMenu).上下文菜单(ContextMenu)和子菜单(SubMenu),今天这讲是O ...

  7. 几年前做家教写的C教程(之四专讲了指针与汉诺塔问题)

    C语言学习宝典(4) 指针:可以有效的表示复杂的数据结构,能动态的分配动态空间,方便的使用字符串,有效的使用数组,能直接处理内存单元 不掌握指针就没有掌握C语言的精华 地址:系统为每一个变量分配一个内 ...

  8. android工程中menu的使用总结

    android的Menu使用 转自:thinkYeah的博客 1.普通的Menu 先来看看最简单的Menu怎样实现. 在主Activity中覆盖onCreateOptionsMenu(Menu men ...

  9. 仿知乎程序 fragment的切换以及toolbar在不同页面下显示的menu不同

           我们在看知乎的时候,你会发现,首页,发现,关注,收藏,草稿这五项,你在点击之后进入到相应页面之后,侧滑菜单还在,你左侧滑一下,这个侧滑菜单还在,而提问,左滑屏幕,这个页面就没有,有点像返 ...

随机推荐

  1. mac 下安装和卸载 mysql

    这里有一篇文章写得很详细: http://www.cnblogs.com/macro-cheng/archive/2011/10/25/mysql-001.html 关于卸载,我也百度了下.找了好几个 ...

  2. QT在ui文件上建立信号操机制会不会对后期维护产生影响 - love4Mario的专栏 - 博客频道 - CSDN.NETQT在ui文件上建立信号操机制会不会对后期维护产生影响 - love4Mario的专栏 - 博客频道 - CSDN.NET

    QT在ui文件上建立信号操机制会不会对后期维护产生影响 - love4Mario的专栏 - 博客频道 - CSDN.NET QT在ui文件上建立信号操机制会不会对后期维护产生影响 分类: 学习心得 2 ...

  3. Buffer Cache(缓冲区缓存)篇:缓存区块大小

    缓冲区缓存(Buffer Cache) Buffer Cache是SGA的一部分,保存最近从磁盘读取的或修改的(dml修改或添加)数据块.Buffer Cache的目的就是减少磁盘I/O,提高速度. ...

  4. GDAL1.9.1 IN VS2008 C#中的编译及使用

    下载gdal1.9.1到官网:http://www.gdal.org/ GDAL库的简洁.高效深受开发人员的喜爱,很多开源的GIS软件甚至是商业GIS软件都使用了这个库.GDAL使用C++,在Visu ...

  5. 利用Linux命令行进行文本按行去重并按重复次数排序

    最近杂事太多,正事进展缓慢.Fighting! linux命令行提供了非常强大的文本处理功能,组合利用linux命令能实现好多强大的功能.本文这里举例说明如何利用Linux命令行进行文本按行去重并按重 ...

  6. javascript技术难点之this、new、apply和call详解

    讲解this指针的原理是个很复杂的问题,如果我们从javascript里this的实现机制来说明this,很多朋友可能会越来越糊涂,因此本篇打算换一个思路从应用的角度来讲解this指针,从这个角度理解 ...

  7. 行列转换小结 Pivot ,Unpivot (转,改)

    行专列 Pivot 1)SQL 2000版本 静态 SELECT ID , SUM(CASE Code WHEN 'Item1' THEN Value END) AS Item1 , SUM(CASE ...

  8. 融合python2和python3

    很多情况下你可能会想要开发一个程序能同时在python2和python3中运行. 想象一下你开发了一个模块,成百上千的人都在使用它,但不是所有的用户都同时使用python 2和3.这种情况下你有两个选 ...

  9. Laravel 5.1 ACL权限控制 四 之middleware

    1.创建Middleware php artisan make:middleware MustBeAnAdmin 2.实现 MustBeAnAdmin.php中的handle方法,判断登录的用户是否为 ...

  10. zookeeper 安装

    Zookeeper安装 一.   下载zookeeper http://www.apache.org/dist/zookeeper/stable/ 二.   解压zookeeper.tar >& ...