展会信息港展会大全

基于cocos2dx的伪立体菜单,cocos2dx RotateMenu说明
来源:互联网   发布日期:2015-09-28 15:13:43   浏览:2484次  

导读: 基于cocos2dx的伪立体菜单,cocos2dx RotateMenu说明 最终效果图 下面这个引用自乱斗西游 设计说明 1.菜单项(MenuItem)平均分布在椭圆(类似)上 2...

基于cocos2dx的伪立体菜单,cocos2dx

RotateMenu说明

最终效果图

下面这个引用自乱斗西游

设计说明

1.菜单项(MenuItem)平均分布在椭圆(类似)上

2.椭圆长轴为2/3width,短轴为2/8 height

3.最前面的菜单项Scale=1,opacity=255,最后面Scale=0.5,opacity=129.其它位置根据三角函数变换(updatePosition中实现)

4.默认最前面菜单被选中(selected)

5.单位角度(unitAngle)是2*PI/菜单项的数量

6.滑动一个width,菜单旋转两个单位角度

7.Touch结束会自动调整位置,保证最前面位置有菜单项

8.滑动超过1/3单位角度会向前舍入

9.移动小于1/6单位角度会判定点击菜单

10.默认菜单大小不是全屏,而是屏幕的2/3,通过Node::setContentSize()设置

使用

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

1.构造函数

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

2.添加MenuItem

void addMenuItem(cocos2d::MenuItem *item);

其它函数可以看代码

相关参数的函数设置还未添加

代码

声明

#ifndef __ROTA__TE_MENU_H__

#define __ROTA__TE_MENU_H__

#include "cocos2d.h"

/*

*模仿乱斗西游主界面的旋转菜单

*/

class RotateMenu :public cocos2d::Layer{

public:

//构造方法

CREATE_FUNC(RotateMenu);

//添加菜单项

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 setAngle(float angle);

float getAngle();

//设置单位角度 弧度

void setUnitAngle(float angle);

float getUnitAngle();

//滑动距离转换角度,转换策略为移动半个Menu.width等于_unitAngle

float disToAngle(float dis);

//返回被选中的item

cocos2d::MenuItem * getCurrentItem();

private:

//菜单已经旋转角度 弧度

float _angle;

//菜单项集合,_children顺序会变化,新建数组保存顺序

cocos2d::Vector<cocos2d::MenuItem *> _items;

//单位角度 弧度

float _unitAngle;

//监听函数

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;

//动画运行时间

float animationDuration = 0.3f;

};

#endif

实现

#include "RotateMenu.h"

#include <math.h>

#define PI acos(-1)

USING_NS_CC;

bool RotateMenu::init(){

if (!Layer::init())

return false;

_angle = 0.0;

this->ignoreAnchorPointForPosition(false);

_selectedItem = nullptr;

Size s = Director::getInstance()->getWinSize();

this->setContentSize(s/3*2);

this->setAnchorPoint(Vec2(0.5f, 0.5f));

auto listener = EventListenerTouchOneByOne::create();

listener->onTouchBegan = CC_CALLBACK_2(RotateMenu::onTouchBegan,this);

listener->onTouchMoved = CC_CALLBACK_2(RotateMenu::onTouchMoved, this);

listener->onTouchEnded = CC_CALLBACK_2(RotateMenu::onTouchEnded, this);

getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);

return true;

};

void RotateMenu::addMenuItem(cocos2d::MenuItem *item){

item->setPosition(this->getContentSize() / 2);

this->addChild(item);

_items.pushBack(item);

setUnitAngle(2 * PI / _items.size());

reset();

updatePositionWithAnimation();

return;

}

void RotateMenu::updatePosition(){

auto menuSize = getContentSize();

auto disY = menuSize.height / 8;

auto disX = menuSize.width / 3;

for (int i = 0; i < _items.size(); i++){

float x = menuSize.width / 2 + disX*sin(i*_unitAngle+getAngle());

float y = menuSize.height / 2 - disY*cos(i*_unitAngle + getAngle());

_items.at(i)->setPosition(Vec2(x, y));

_items.at(i)->setZOrder(-(int)y);

//Opacity129~255

_items.at(i)->setOpacity(192 + 63 * cos(i*_unitAngle + getAngle()));

_items.at(i)->setScale(0.75 + 0.25*cos(i*_unitAngle + getAngle()));

}

return;

}

void RotateMenu::updatePositionWithAnimation(){

//先停止所有可能存在的动作

for (int i = 0; i < _items.size(); i++)

_items.at(i)->stopAllActions();

auto menuSize = getContentSize();

auto disY = menuSize.height / 8;

auto disX = menuSize.width / 3;

for (int i = 0; i < _items.size(); i++){

float x = menuSize.width / 2 + disX*sin(i*_unitAngle + getAngle());

float y = menuSize.height / 2 - disY*cos(i*_unitAngle + getAngle());

auto moveTo = MoveTo::create(animationDuration, Vec2(x, y));

_items.at(i)->runAction(moveTo);

//Opacity129~255

auto fadeTo = FadeTo::create(animationDuration, (192 + 63 * cos(i*_unitAngle + getAngle())));

_items.at(i)->runAction(fadeTo);

//缩放比例0.5~1

auto scaleTo = ScaleTo::create(animationDuration, 0.75 + 0.25*cos(i*_unitAngle + getAngle()));

_items.at(i)->runAction(scaleTo);

_items.at(i)->setZOrder(-(int)y);

}

scheduleOnce(schedule_selector(RotateMenu::actionEndCallBack), animationDuration);

return;

}

void RotateMenu::reset(){

_angle = 0;

}

void RotateMenu::setAngle(float angle){

this->_angle = angle;

}

float RotateMenu::getAngle(){

return _angle;

}

void RotateMenu::setUnitAngle(float angle){

_unitAngle = angle;

}

float RotateMenu::getUnitAngle(){

return _unitAngle;

}

float RotateMenu::disToAngle(float dis){

float width = this->getContentSize().width / 2;

return dis / width*getUnitAngle();

}

MenuItem * RotateMenu::getCurrentItem(){

if (_items.size() == 0)

return nullptr;

//这里实际加上了0.1getAngle(),用来防止精度丢失

intindex = (int)((2 * PI - getAngle()) / getUnitAngle()+0.1*getUnitAngle());

index %= _items.size();

return _items.at(index);

}

bool RotateMenu::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, 0, size.width, size.height);

if (rect.containsPoint(position)){

return true;

}

return false;

}

void RotateMenu::onTouchEnded(Touch* touch, Event* event){

auto xDelta = touch->getLocation().x - touch->getStartLocation().x;

rectify(xDelta>0);

if (disToAngle(fabs(xDelta))<getUnitAngle() / 6&&_selectedItem)

_selectedItem->activate();

updatePositionWithAnimation();

return;

}

void RotateMenu::onTouchMoved(Touch* touch, Event* event){

auto angle = disToAngle(touch->getDelta().x);

setAngle(getAngle() + angle);

updatePosition();

return;

}

void RotateMenu::rectify(bool forward){

auto angle = getAngle();

while (angle<0)

angle += PI * 2;

while (angle>PI * 2)

angle -= PI * 2;

if(forward>0)

angle = ((int)((angle + getUnitAngle() / 3*2) / getUnitAngle()))*getUnitAngle();

else

angle = ((int)((angle + getUnitAngle() / 3 ) / getUnitAngle()))*getUnitAngle();

setAngle(angle);

}

void RotateMenu::actionEndCallBack(float dx){

_selectedItem = getCurrentItem();

if(_selectedItem)

_selectedItem->selected();

}

一个糟糕的Demo

声明

#ifndef __HELLOWORLD_SCENE_H__

#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"

class HelloWorld : 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(HelloWorld);

};

#endif // __HELLOWORLD_SCENE_H__

声明

#include "HelloWorldScene.h"

#include "RotateMenu.h"

USING_NS_CC;

typedef struct SceneList{

const char *name;

std::function<cocos2d::Scene*()> callback;

}SceneList;

SceneList sceneList[] = {

{ "Demo1", [](){return HelloWorld::createScene(); } }

};

const unsigned int sceneCount = sizeof(sceneList) / sizeof(SceneList);

#define LINE_SPACE 40

Scene* HelloWorld::createScene()

{

// 'scene' is an autorelease object

auto scene = Scene::create();

// 'layer' is an autorelease object

auto layer = HelloWorld::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 HelloWorld::init()

{

//////////////////////////////

// 1. super init first

if ( !Layer::init() )

{

return false;

}

Size visibleSize = Director::getInstance()->getVisibleSize();

Vec2 origin = Director::getInstance()->getVisibleOrigin();

/////////////////////////////

// 2. add a menu item with "X" image, which is clicked to quit the program

//you may modify it.

// add a "close" icon to exit the progress. it's an autorelease object

auto closeItem = MenuItemImage::create(

"CloseNormal.png",

"CloseSelected.png",

CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));

closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,

origin.y + closeItem->getContentSize().height/2));

//create menu, it's an autorelease object

/*auto menu = Menu::create(closeItem, NULL);

menu->setPosition(Vec2::ZERO);

this->addChild(menu, 1);*/

auto item1 = MenuItemImage::create("Demo1/item1_1.png", "Demo1/item1_0.png", CC_CALLBACK_1(HelloWorld::menuItem1Callback, this));

auto item2 = MenuItemImage::create("Demo1/item2_1.png", "Demo1/item2_0.png", CC_CALLBACK_1(HelloWorld::menuItem2Callback, this));

auto item3 = MenuItemImage::create("Demo1/item3_1.png", "Demo1/item3_0.png", CC_CALLBACK_1(HelloWorld::menuItem3Callback, this));

auto item4 = MenuItemImage::create("Demo1/item4_1.png", "Demo1/item4_0.png", CC_CALLBACK_1(HelloWorld::menuItem4Callback, this));

auto item5 = MenuItemImage::create("Demo1/item5_1.png", "Demo1/item5_0.png", CC_CALLBACK_1(HelloWorld::menuItem5Callback, this));

RotateMenu *menu = RotateMenu::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[20];

sprintf(str, "Demo1/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();

/////////////////////////////

// 3. add your codes below...

// add a label shows "Hello World"

// create and initialize a label

auto label = LabelTTF::create("Hello World", "Arial", 24);

// position the label on the center of the screen

label->setPosition(Vec2(origin.x + visibleSize.width/2,

origin.y + visibleSize.height - label->getContentSize().height));

// add the label as a child to this layer

this->addChild(label, 1);

return true;

}

void HelloWorld::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 HelloWorld::menuItem1Callback(cocos2d::Ref* pSender){

hideAllSprite();

sprite[0]->setVisible(true);

}

void HelloWorld::menuItem2Callback(cocos2d::Ref* pSender){

hideAllSprite();

sprite[1]->setVisible(true);

}

void HelloWorld::menuItem3Callback(cocos2d::Ref* pSender){

hideAllSprite();

sprite[2]->setVisible(true);

}

void HelloWorld::menuItem4Callback(cocos2d::Ref* pSender){

hideAllSprite();

sprite[3]->setVisible(true);

}

void HelloWorld::menuItem5Callback(cocos2d::Ref* pSender){

hideAllSprite();

sprite[4]->setVisible(true);

}

void HelloWorld::hideAllSprite(){

for (auto p : sprite){

if (p->isVisible())

p->setVisible(false);

}

}

可运行的程序下载地址

作者:CCY

联系方式:810278677@qq.com

http://www.bkjia.com/Androidjc/918531.htmlwww.bkjia.comtruehttp://www.bkjia.com/Androidjc/918531.htmlTechArticle基于cocos2dx的伪立体菜单,cocos2dx RotateMenu 说明 最终效果图 下面这个引用自乱斗西游 设计说明 1.菜单项(MenuItem) 平均分布在 椭圆(类)上...

赞助本站

人工智能实验室

相关热词: android开发 应用开发

AiLab云推荐
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港