基于Cocos2d-x的英雄联盟皮肤选择菜单

最终效果图

英雄联盟皮肤选择


设计说明

实现目标所需要的动作

移动(MoveTo),伸缩(ScaleTo),倾斜(OrbitCamera)

实现目标所需要函数(这是一个数学函数)

x/(x+a)

其中a为常量,用来计算上面三个动作的值

大小

与原版Menu不同,大小不是全屏的,默认是屏幕的(2/3),可以通过setContentSize()函数设置

_index变量

将所有的菜单项平铺构成一个长方形,_index表示目前在中间位置的点,如下图

显示方式

将菜单项距中心的距离(i-_indxe)作为函数变量x,具体内容查看LOLMenu::updatePosition();

操作说明

滑动四分之一菜单宽的距离为一个单位的_index,距离大于0.6小于1.0的部分进1

使用

使用这个菜单只要知道两个函数

1.构造函数

LOLMenu::create()(由CREATE_FUNC创建)

2.添加MenuItem

void addMenuItem(cocos2d::MenuItem *item);

其它函数可以看代码

菜单代码

LOLMenu.h

[cpp]  view plain  copy
  1. #ifndef __LOL__TE_MENU_H__  
  2. #define __LOL__TE_MENU_H__  
  3. #include "cocos2d.h"  
  4. /* 
  5. *模仿英雄联盟的皮肤选择菜单 
  6. *不同点在于,英雄联盟当皮肤过多时,部分皮肤会移出边缘,不显示 
  7. *我会显示所以菜单项,向边缘移动会不断减缓 
  8. */  
  9. class LOLMenu :public cocos2d::Layer{  
  10. public:  
  11.     //构造方法  
  12.     CREATE_FUNC(LOLMenu);  
  13.     //添加菜单项  
  14.     void addMenuItem(cocos2d::MenuItem *item);  
  15.     //更新位置  
  16.     void updatePosition();  
  17.     //更新位置,有动画  
  18.     void updatePositionWithAnimation();  
  19.     //位置矫正  修改位置forward为移动方向  当超过1/3,进1  
  20.     //true 为正向  false 负  
  21.     void rectify(bool forward);  
  22.     //初始化  
  23.     virtual bool init();  
  24.     //重置  显示所引号设置为0  
  25.     void reset();  
  26. private:  
  27.     //设置当前显示索引  
  28.     void setIndex(int index);  
  29.     //设置当前显示菜单项的索引号  
  30.     float getIndex();  
  31.     //返回被选中的item  
  32.     cocos2d::MenuItem * getCurrentItem();  
  33.     //数学计算式width*index/(abs(index)+CALC_A) ,其中CALC_A为常数  
  34.     float calcFunction(float index, float width);  
  35. private:  
  36.     //菜单菜单项的索引号  
  37.     float _index;  
  38.     //上一次菜单项的索引号  
  39.     float _lastIndex;  
  40.     //菜单项集合,_children顺序会变化,新建数组保存顺序  
  41.     cocos2d::Vector<cocos2d::MenuItem *> _items;  
  42.     //监听函数  
  43.     virtual bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);  
  44.     virtual void onTouchEnded(cocos2d::Touch* touch, cocos2d::Event* event);  
  45.     virtual void onTouchMoved(cocos2d::Touch* touch, cocos2d::Event* event);  
  46.     //动画完结调用函数,这个主要是确定哪一个菜单项在前面  
  47.     void actionEndCallBack(float dx);  
  48.     //当前被选择的item  
  49.     cocos2d::MenuItem *_selectedItem;  
  50. };  
  51. #endif  

LOLMenu.cpp

[cpp]  view plain  copy
  1. #include "LOLMenu.h"  
  2. #include <math.h>  
  3. #define PI acos(-1)  
  4. //菜单的缩小比例 最小的比例是1-MENU_SCALE  
  5. #define MENU_SCALE 0.3  
  6. //菜单的倾斜度 最多为45度  
  7. #define MENU_ASLOPE 60.0  
  8. //calcFunction(x) 为 x/(x+a),其中a为常数  
  9. #define CALC_A 1  
  10. //动画运行时间  
  11. #define ANIMATION_DURATION  0.3f   
  12. //菜单项的大小与屏幕的比例,当然可以通过setContentSize设置  
  13. #define CONTENT_SIZE_SCALE (2.0/3)  
  14. //菜单项长度与菜单长度的比例 滑动一个菜单项长度,菜单项变化一个  
  15. #define ITEM_SIZE_SCALE (1.0/4)  
  16. /* 
  17.     代码里面还有可以设置的参数,这里没有一一例出或给出函数 
  18.     */  
  19. USING_NS_CC;  
  20. bool LOLMenu::init(){  
  21.     if (!Layer::init())  
  22.         return false;  
  23.     _index=0;  
  24.     _lastIndex = 0;  
  25.     this->ignoreAnchorPointForPosition(false);  
  26.     _selectedItem = nullptr;  
  27.     auto size = Director::getInstance()->getWinSize();  
  28.     this->setContentSize(size*CONTENT_SIZE_SCALE);  
  29.     this->setAnchorPoint(Vec2(0.5f, 0.5f));  
  30.     auto listener = EventListenerTouchOneByOne::create();  
  31.     listener->onTouchBegan = CC_CALLBACK_2(LOLMenu::onTouchBegan, this);  
  32.     listener->onTouchMoved = CC_CALLBACK_2(LOLMenu::onTouchMoved, this);  
  33.     listener->onTouchEnded = CC_CALLBACK_2(LOLMenu::onTouchEnded, this);  
  34.     getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);  
  35.     return true;  
  36. };  
  37.   
  38. void LOLMenu::addMenuItem(cocos2d::MenuItem *item){  
  39.     item->setPosition(this->getContentSize() / 2);  
  40.     this->addChild(item);  
  41.     _items.pushBack(item);  
  42.     reset();  
  43.     //如果希望开始没有移动效果,改成updatePosition函数即可  
  44.     updatePositionWithAnimation();  
  45.     return;  
  46. }  
  47. void LOLMenu::updatePosition(){  
  48.     auto menuSize = getContentSize();  
  49.     for (int i = 0; i < _items.size(); i++){  
  50.         //设置位置  
  51.         float x = calcFunction(i - _index, menuSize.width / 2);  
  52.         _items.at(i)->setPosition(Vec2(menuSize.width/2+x, menuSize.height/2));  
  53.         //设置zOrder,即绘制顺序  
  54.         _items.at(i)->setZOrder(-abs((i - _index) * 100));  
  55.         //设置伸缩比例  
  56.         _items.at(i)->setScale(1.0-abs(calcFunction(i - _index, MENU_SCALE)));  
  57.         //设置倾斜,Node没有setCamera函数,将OrbitCamera的运行时间设为0来达到效果  
  58.         auto orbit1 = OrbitCamera::create(0, 1, 0, calcFunction(i - _lastIndex, MENU_ASLOPE), calcFunction(i - _lastIndex, MENU_ASLOPE) - calcFunction(i - _index, MENU_ASLOPE), 0, 0);  
  59.         _items.at(i)->runAction(orbit1);  
  60.     }  
  61.     return;  
  62. }  
  63. void LOLMenu::updatePositionWithAnimation(){  
  64.     //先停止所有可能存在的动作  
  65.     for (int i = 0; i < _items.size(); i++)  
  66.         _items.at(i)->stopAllActions();  
  67.     auto menuSize = getContentSize();  
  68.     for (int i = 0; i < _items.size(); i++){  
  69.         _items.at(i)->setZOrder(-abs((i - _index)*100));  
  70.         float x = calcFunction(i - _index, menuSize.width / 2);  
  71.         auto moveTo = MoveTo::create(ANIMATION_DURATION, Vec2(menuSize.width / 2 + x, menuSize.height / 2));  
  72.         _items.at(i)->runAction(moveTo);  
  73.         auto scaleTo = ScaleTo::create(ANIMATION_DURATION, (1 - abs(calcFunction(i - _index, MENU_SCALE))));  
  74.         _items.at(i)->runAction(scaleTo);  
  75.         auto orbit1 = OrbitCamera::create(ANIMATION_DURATION, 1, 0, calcFunction(i - _lastIndex, MENU_ASLOPE), calcFunction(i - _index, MENU_ASLOPE) - calcFunction(i - _lastIndex, MENU_ASLOPE), 0, 0);  
  76.         _items.at(i)->runAction(orbit1);  
  77.     }  
  78.     scheduleOnce(schedule_selector(LOLMenu::actionEndCallBack), ANIMATION_DURATION);  
  79.     return;  
  80. }  
  81. void LOLMenu::reset(){  
  82.     _lastIndex = 0;  
  83.     _index = 0;  
  84. }  
  85. void LOLMenu::setIndex(int index){  
  86.     _lastIndex = _index;  
  87.     this->_index = index;  
  88. }  
  89. float LOLMenu::getIndex(){  
  90.     return _index;  
  91. }  
  92.   
  93.   
  94.   
  95. MenuItem * LOLMenu::getCurrentItem(){  
  96.     if (_items.size() == 0)  
  97.         return nullptr;  
  98.     return _items.at(_index);  
  99. }  
  100.   
  101.   
  102. bool LOLMenu::onTouchBegan(Touch* touch, Event* event){  
  103.     //先停止所有可能存在的动作  
  104.     for (int i = 0; i < _items.size(); i++)  
  105.         _items.at(i)->stopAllActions();  
  106.     if (_selectedItem)  
  107.         _selectedItem->unselected();  
  108.     auto position = this->convertToNodeSpace(touch->getLocation());  
  109.     auto size = this->getContentSize();  
  110.     auto rect = Rect(0, 0, size.width, size.height);  
  111.     if (rect.containsPoint(position)){  
  112.         return true;  
  113.     }  
  114.     return false;  
  115. }  
  116. void LOLMenu::onTouchEnded(Touch* touch, Event* event){  
  117.     auto size = getContentSize();  
  118.     auto xDelta = touch->getLocation().x - touch->getStartLocation().x;  
  119.     rectify(xDelta>0);  
  120.     if (abs(xDelta)<size.width / 24 && _selectedItem)  
  121.         _selectedItem->activate();  
  122.     updatePositionWithAnimation();  
  123.     return;  
  124. }  
  125. void LOLMenu::onTouchMoved(Touch* touch, Event* event){  
  126.     auto xDelta = touch->getDelta().x;  
  127.     auto size = getContentSize();  
  128.     _lastIndex = _index;  
  129.     _index -= xDelta / (size.width *ITEM_SIZE_SCALE);  
  130.     updatePosition();  
  131.     return;  
  132. }  
  133.   
  134. void LOLMenu::rectify(bool forward){  
  135.     auto index = getIndex();  
  136.     if (index < 0)  
  137.         index = 0;  
  138.     if (index>_items.size() - 1)  
  139.         index = _items.size() - 1;  
  140.     if (forward){  
  141.         index = (int)(index + 0.4);  
  142.     }  
  143.     else  
  144.         index = (int)(index + 0.6);  
  145.     setIndex((int)index);  
  146. }  
  147.   
  148. void LOLMenu::actionEndCallBack(float dx){  
  149.     _selectedItem = getCurrentItem();  
  150.     if (_selectedItem)  
  151.         _selectedItem->selected();  
  152. }  
  153.   
  154. float LOLMenu::calcFunction(float index, float width){  
  155.     return width*index / (abs(index) + CALC_A);  
  156. }  

演示代码

LOLMenuDemo.h

[cpp]  view plain  copy
  1. #ifndef __LOLMenu_SCENE_H__  
  2. #define __LOLMenu_SCENE_H__  
  3. #include "cocos2d.h"  
  4. class LOLMenuDemo : public cocos2d::Layer  
  5. {  
  6. public:  
  7.     // there's no 'id' in cpp, so we recommend returning the class instance pointer  
  8.     static cocos2d::Scene* createScene();  
  9.     // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone  
  10.     virtual bool init();  
  11.     // a selector callback  
  12.     void menuCloseCallback(cocos2d::Ref* pSender);  
  13.     void menuItem1Callback(cocos2d::Ref* pSender);  
  14.     void menuItem2Callback(cocos2d::Ref* pSender);  
  15.     void menuItem3Callback(cocos2d::Ref* pSender);  
  16.     void menuItem4Callback(cocos2d::Ref* pSender);  
  17.     void menuItem5Callback(cocos2d::Ref* pSender);  
  18.     void hideAllSprite();  
  19.     cocos2d::Sprite *sprite[5];  
  20.     // implement the "static create()" method manually  
  21.     CREATE_FUNC(LOLMenuDemo);  
  22. };  
  23. #endif // __HELLOWORLD_SCENE_H__  

LOLMenuDemo.cpp

[cpp]  view plain  copy
  1. #include "LOLMenuDemo.h"  
  2. #include "LOLMenu.h"  
  3.   
  4.   
  5. USING_NS_CC;  
  6.   
  7. Scene* LOLMenuDemo::createScene()  
  8. {  
  9.     // 'scene' is an autorelease object  
  10.     auto scene = Scene::create();  
  11.   
  12.     // 'layer' is an autorelease object  
  13.     auto layer = LOLMenuDemo::create();  
  14.   
  15.     // add layer as a child to scene  
  16.     scene->addChild(layer);  
  17.   
  18.     // return the scene  
  19.     return scene;  
  20. }  
  21.   
  22. // on "init" you need to initialize your instance  
  23. bool LOLMenuDemo::init()  
  24. {  
  25.     //  
  26.     // 1. super init first  
  27.     if (!Layer::init())  
  28.     {  
  29.         return false;  
  30.     }  
  31.   
  32.     Size visibleSize = Director::getInstance()->getVisibleSize();  
  33.     Vec2 origin = Director::getInstance()->getVisibleOrigin();  
  34.   
  35.     auto item1 = MenuItemImage::create("4_LOL_MENU/item1_0.png""4_LOL_MENU/item1_0.png", CC_CALLBACK_1(LOLMenuDemo::menuItem1Callback, this));  
  36.     auto item2 = MenuItemImage::create("4_LOL_MENU/item2_0.png""4_LOL_MENU/item2_0.png", CC_CALLBACK_1(LOLMenuDemo::menuItem2Callback, this));  
  37.     auto item3 = MenuItemImage::create("4_LOL_MENU/item3_0.png""4_LOL_MENU/item3_0.png", CC_CALLBACK_1(LOLMenuDemo::menuItem3Callback, this));  
  38.     auto item4 = MenuItemImage::create("4_LOL_MENU/item4_0.png""4_LOL_MENU/item4_0.png", CC_CALLBACK_1(LOLMenuDemo::menuItem4Callback, this));  
  39.     auto item5 = MenuItemImage::create("4_LOL_MENU/item5_0.png""4_LOL_MENU/item5_0.png", CC_CALLBACK_1(LOLMenuDemo::menuItem5Callback, this));  
  40.   
  41.     LOLMenu *menu = LOLMenu::create();  
  42.   
  43.     menu->addMenuItem(item1);  
  44.     menu->addMenuItem(item2);  
  45.     menu->addMenuItem(item3);  
  46.     menu->addMenuItem(item4);  
  47.     menu->addMenuItem(item5);  
  48.   
  49.     menu->setPosition(visibleSize / 2);  
  50.     this->addChild(menu, 2);  
  51.   
  52.   
  53.     for (int i = 0; i < 5; i++){  
  54.         char str[100];  
  55.         sprintf(str, "4_LOL_MENU/item%d.jpg", i + 1);  
  56.         sprite[i] = Sprite::create(str);  
  57.         sprite[i]->setAnchorPoint(Vec2(0.5f, 0.5f));  
  58.         sprite[i]->setPosition(visibleSize / 2);  
  59.         this->addChild(sprite[i]);  
  60.     }  
  61.     hideAllSprite();  
  62.     return true;  
  63. }  
  64.   
  65.   
  66. void LOLMenuDemo::menuCloseCallback(Ref* pSender)  
  67. {  
  68. #if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)  
  69.     MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.""Alert");  
  70.     return;  
  71. #endif  
  72.   
  73.     Director::getInstance()->end();  
  74.   
  75. #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)  
  76.     exit(0);  
  77. #endif  
  78. }  
  79.   
  80. void LOLMenuDemo::menuItem1Callback(cocos2d::Ref* pSender){  
  81.     hideAllSprite();  
  82.     sprite[0]->setVisible(true);  
  83. }  
  84. void LOLMenuDemo::menuItem2Callback(cocos2d::Ref* pSender){  
  85.     hideAllSprite();  
  86.     sprite[1]->setVisible(true);  
  87. }  
  88. void LOLMenuDemo::menuItem3Callback(cocos2d::Ref* pSender){  
  89.     hideAllSprite();  
  90.     sprite[2]->setVisible(true);  
  91. }  
  92. void LOLMenuDemo::menuItem4Callback(cocos2d::Ref* pSender){  
  93.     hideAllSprite();  
  94.     sprite[3]->setVisible(true);  
  95. }  
  96. void LOLMenuDemo::menuItem5Callback(cocos2d::Ref* pSender){  
  97.     hideAllSprite();  
  98.     sprite[4]->setVisible(true);  
  99. }  
  100.   
  101. void LOLMenuDemo::hideAllSprite(){  
  102.     for (auto p : sprite){  
  103.         if (p->isVisible())  
  104.             p->setVisible(false);  
  105.     }  
  106. }  


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值