最终效果图
英雄联盟皮肤选择
设计说明
实现目标所需要的动作
移动(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
voidaddMenuItem(cocos2d::MenuItem*item);
菜单代码
LOLMenu.h
#ifndef __LOL__TE_MENU_H__ #define __LOL__TE_MENU_H__ #include "cocos2d.h" /* *模仿英雄联盟的皮肤选择菜单 *不同点在于,英雄联盟当皮肤过多时,部分皮肤会移出边缘,不显示 *我会显示所以菜单项,向边缘移动会不断减缓 */ class LOLMenu :public cocos2d::Layer{ public: //构造方法 CREATE_FUNC(LOLMenu); //添加菜单项 void addMenuItem(cocos2d::MenuItem *item); //更新位置 void updatePosition(); //更新位置,有动画 void updatePositionWithAnimation(); //位置矫正 修改位置forward为移动方向 当超过1/3,进1 //true 为正向 false 负 void rectify(bool forward); //初始化 virtual bool init(); //重置 显示所引号设置为0 void reset(); private: //设置当前显示索引 void setIndex(int index); //设置当前显示菜单项的索引号 float getIndex(); //返回被选中的item cocos2d::MenuItem * getCurrentItem(); //数学计算式width*index/(abs(index)+CALC_A),其中CALC_A为常数 float calcFunction(float index,float width); private: //菜单菜单项的索引号 float _index; //上一次菜单项的索引号 float _lastIndex; //菜单项集合,_children顺序会变化,新建数组保存顺序 cocos2d::Vector<cocos2d::MenuItem *> _items; //监听函数 virtual bool onTouchBegan(cocos2d::Touch* touch,cocos2d::Event* event); virtual void onTouchEnded(cocos2d::Touch* touch,cocos2d::Event* event); virtual void onTouchMoved(cocos2d::Touch* touch,cocos2d::Event* event); //动画完结调用函数,这个主要是确定哪一个菜单项在前面 void actionEndCallBack(float dx); //当前被选择的item cocos2d::MenuItem *_selectedItem; }; #endif
LOLMenu.cpp
#include "LOLMenu.h" #include <math.h> #define PI acos(-1) //菜单的缩小比例 最小的比例是1-MENU_SCALE #define MENU_SCALE 0.3 //菜单的倾斜度 最多为45度 #define MENU_ASLOPE 60.0 //calcFunction(x) 为 x/(x+a),其中a为常数 #define CALC_A 1 //动画运行时间 #define ANIMATION_DURATION 0.3f //菜单项的大小与屏幕的比例,当然可以通过setContentSize设置 #define CONTENT_SIZE_SCALE (2.0/3) //菜单项长度与菜单长度的比例 滑动一个菜单项长度,菜单项变化一个 #define ITEM_SIZE_SCALE (1.0/4) /* 代码里面还有可以设置的参数,这里没有一一例出或给出函数 */ USING_NS_CC; bool LOLMenu::init(){ if (!Layer::init()) return false; _index=0; _lastIndex = 0; this->ignoreAnchorPointForPosition(false); _selectedItem = nullptr; auto size = Director::getInstance()->getWinSize(); this->setContentSize(size*CONTENT_SIZE_SCALE); this->setAnchorPoint(Vec2(0.5f,0.5f)); auto listener = EventListenerTouchOneByOne::create(); listener->onTouchBegan = CC_CALLBACK_2(LOLMenu::onTouchBegan,this); listener->onTouchMoved = CC_CALLBACK_2(LOLMenu::onTouchMoved,this); listener->onTouchEnded = CC_CALLBACK_2(LOLMenu::onTouchEnded,this); getEventDispatcher()->addEventListenerWithSceneGraPHPriority(listener,this); return true; }; void LOLMenu::addMenuItem(cocos2d::MenuItem *item){ item->setPosition(this->getContentSize() / 2); this->addChild(item); _items.pushBack(item); reset(); //如果希望开始没有移动效果,改成updatePosition函数即可 updatePositionWithAnimation(); return; } void LOLMenu::updatePosition(){ auto menuSize = getContentSize(); for (int i = 0; i < _items.size(); i++){ //设置位置 float x = calcFunction(i - _index,menuSize.width / 2); _items.at(i)->setPosition(Vec2(menuSize.width/2+x,menuSize.height/2)); //设置zOrder,即绘制顺序 _items.at(i)->setZOrder(-abs((i - _index) * 100)); //设置伸缩比例 _items.at(i)->setScale(1.0-abs(calcFunction(i - _index,MENU_SCALE))); //设置倾斜,Node没有setCamera函数,将OrbitCamera的运行时间设为0来达到效果 auto orbit1 = OrbitCamera::create(0,1,calcFunction(i - _lastIndex,MENU_ASLOPE),MENU_ASLOPE) - calcFunction(i - _index,0); _items.at(i)->runAction(orbit1); } return; } void LOLMenu::updatePositionWithAnimation(){ //先停止所有可能存在的动作 for (int i = 0; i < _items.size(); i++) _items.at(i)->stopAllActions(); auto menuSize = getContentSize(); for (int i = 0; i < _items.size(); i++){ _items.at(i)->setZOrder(-abs((i - _index)*100)); float x = calcFunction(i - _index,menuSize.width / 2); auto moveTo = MoveTo::create(ANIMATION_DURATION,Vec2(menuSize.width / 2 + x,menuSize.height / 2)); _items.at(i)->runAction(moveTo); auto scaleTo = ScaleTo::create(ANIMATION_DURATION,(1 - abs(calcFunction(i - _index,MENU_SCALE)))); _items.at(i)->runAction(scaleTo); auto orbit1 = OrbitCamera::create(ANIMATION_DURATION,calcFunction(i - _index,MENU_ASLOPE) - calcFunction(i - _lastIndex,0); _items.at(i)->runAction(orbit1); } scheduleOnce(schedule_selector(LOLMenu::actionEndCallBack),ANIMATION_DURATION); return; } void LOLMenu::reset(){ _lastIndex = 0; _index = 0; } void LOLMenu::setIndex(int index){ _lastIndex = _index; this->_index = index; } float LOLMenu::getIndex(){ return _index; } MenuItem * LOLMenu::getCurrentItem(){ if (_items.size() == 0) return nullptr; return _items.at(_index); } bool LOLMenu::onTouchBegan(Touch* touch,Event* event){ //先停止所有可能存在的动作 for (int i = 0; i < _items.size(); i++) _items.at(i)->stopAllActions(); if (_selectedItem) _selectedItem->unselected(); auto position = this->convertToNodeSpace(touch->getLocation()); auto size = this->getContentSize(); auto rect = Rect(0,size.width,size.height); if (rect.containsPoint(position)){ return true; } return false; } void LOLMenu::onTouchEnded(Touch* touch,Event* event){ auto size = getContentSize(); auto xDelta = touch->getLocation().x - touch->getStartLocation().x; rectify(xDelta>0); if (abs(xDelta)<size.width / 24 && _selectedItem) _selectedItem->activate(); updatePositionWithAnimation(); return; } void LOLMenu::onTouchMoved(Touch* touch,Event* event){ auto xDelta = touch->getDelta().x; auto size = getContentSize(); _lastIndex = _index; _index -= xDelta / (size.width *ITEM_SIZE_SCALE); updatePosition(); return; } void LOLMenu::rectify(bool forward){ auto index = getIndex(); if (index < 0) index = 0; if (index>_items.size() - 1) index = _items.size() - 1; if (forward){ index = (int)(index + 0.4); } else index = (int)(index + 0.6); setIndex((int)index); } void LOLMenu::actionEndCallBack(float dx){ _selectedItem = getCurrentItem(); if (_selectedItem) _selectedItem->selected(); } float LOLMenu::calcFunction(float index,float width){ return width*index / (abs(index) + CALC_A); }
演示代码
LOLMenuDemo.h
#ifndef __LOLMenu_SCENE_H__ #define __LOLMenu_SCENE_H__ #include "cocos2d.h" class LOLMenuDemo : public cocos2d::Layer { public: // there's no 'id' in cpp,so we recommend returning the class instance pointer static cocos2d::Scene* createScene(); // Here's a difference. Method 'init' in cocos2d-x returns bool,instead of returning 'id' in cocos2d-iphone virtual bool init(); // a selector callback void menuCloseCallback(cocos2d::Ref* pSender); void menuItem1Callback(cocos2d::Ref* pSender); void menuItem2Callback(cocos2d::Ref* pSender); void menuItem3Callback(cocos2d::Ref* pSender); void menuItem4Callback(cocos2d::Ref* pSender); void menuItem5Callback(cocos2d::Ref* pSender); void hideAllSprite(); cocos2d::Sprite *sprite[5]; // implement the "static create()" method manually CREATE_FUNC(LOLMenuDemo); }; #endif // __HELLOWORLD_SCENE_H__
LOLMenuDemo.cpp
#include "LOLMenuDemo.h" #include "LOLMenu.h" USING_NS_CC; Scene* LOLMenuDemo::createScene() { // 'scene' is an autorelease object auto scene = Scene::create(); // 'layer' is an autorelease object auto layer = LOLMenuDemo::create(); // add layer as a child to scene scene->addChild(layer); // return the scene return scene; } // on "init" you need to initialize your instance bool LOLMenuDemo::init() { ////////////////////////////// // 1. super init first if (!Layer::init()) { return false; } Size visibleSize = Director::getInstance()->getVisibleSize(); Vec2 origin = Director::getInstance()->getVisibleOrigin(); auto item1 = MenuItemImage::create("4_LOL_MENU/item1_0.png","4_LOL_MENU/item1_0.png",CC_CALLBACK_1(LOLMenuDemo::menuItem1Callback,this)); auto item2 = MenuItemImage::create("4_LOL_MENU/item2_0.png","4_LOL_MENU/item2_0.png",CC_CALLBACK_1(LOLMenuDemo::menuItem2Callback,this)); auto item3 = MenuItemImage::create("4_LOL_MENU/item3_0.png","4_LOL_MENU/item3_0.png",CC_CALLBACK_1(LOLMenuDemo::menuItem3Callback,this)); auto item4 = MenuItemImage::create("4_LOL_MENU/item4_0.png","4_LOL_MENU/item4_0.png",CC_CALLBACK_1(LOLMenuDemo::menuItem4Callback,this)); auto item5 = MenuItemImage::create("4_LOL_MENU/item5_0.png","4_LOL_MENU/item5_0.png",CC_CALLBACK_1(LOLMenuDemo::menuItem5Callback,this)); LOLMenu *menu = LOLMenu::create(); menu->addMenuItem(item1); menu->addMenuItem(item2); menu->addMenuItem(item3); menu->addMenuItem(item4); menu->addMenuItem(item5); menu->setPosition(visibleSize / 2); this->addChild(menu,2); for (int i = 0; i < 5; i++){ char str[100]; sprintf(str,"4_LOL_MENU/item%d.jpg",i + 1); sprite[i] = Sprite::create(str); sprite[i]->setAnchorPoint(Vec2(0.5f,0.5f)); sprite[i]->setPosition(visibleSize / 2); this->addChild(sprite[i]); } hideAllSprite(); return true; } void LOLMenuDemo::menuCloseCallback(Ref* pSender) { #if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert"); return; #endif Director::getInstance()->end(); #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) exit(0); #endif } void LOLMenuDemo::menuItem1Callback(cocos2d::Ref* pSender){ hideAllSprite(); sprite[0]->setVisible(true); } void LOLMenuDemo::menuItem2Callback(cocos2d::Ref* pSender){ hideAllSprite(); sprite[1]->setVisible(true); } void LOLMenuDemo::menuItem3Callback(cocos2d::Ref* pSender){ hideAllSprite(); sprite[2]->setVisible(true); } void LOLMenuDemo::menuItem4Callback(cocos2d::Ref* pSender){ hideAllSprite(); sprite[3]->setVisible(true); } void LOLMenuDemo::menuItem5Callback(cocos2d::Ref* pSender){ hideAllSprite(); sprite[4]->setVisible(true); } void LOLMenuDemo::hideAllSprite(){ for (auto p : sprite){ if (p->isVisible()) p->setVisible(false); } }
可运行的程序(需要安装vs2013或相关dll文件)
有任何问题可以发邮件给我 810278677@qq.com