展会信息港展会大全

cocos2dx之旋转的button
来源:互联网   发布日期:2015-09-28 10:56:50   浏览:2335次  

导读: 一般游戏的主界面按钮的摆放,都是中心垂直对齐,如果弄得稍微炫一点,就是下面的这种效果,也就是本篇要讲解的内容: 先分析一下功能需求: 1、一共四个按钮,只有点击了最前面的按钮,按...

一般游戏的主界面按钮的摆放,都是中心垂直对齐,如果弄得稍微炫一点,就是下面的这种效果,也就是本篇要讲解的内容:

先分析一下功能需求:

1、一共四个按钮,只有点击了最前面的按钮,按钮的响应事件才能触发,点击了其他按钮,则旋转到最前面。

2、点击了除最前面的按钮外的动画效果,和左右滑动时的动画效果。(大小,透明度,运动轨迹)

3、左右滑动到途中时松手时的动画调整。

4、按钮Z序的调整

5、滑动区域的限制

接下来看看代码怎么写:

定义一个类BtnTurn,来看头文件

#ifndef __BTN_TURN_H__

#define __BTN_TURN_H__

#include cocos2d.h

USING_NS_CC;

enum BtnPos

{

Pos_Bottom = 1,

Pos_Left,

Pos_Top,

Pos_Right,

};

class BtnTurn : public cocos2d::Layer

{

public:

BtnTurn();

~BtnTurn();

virtual bool init();

CREATE_FUNC(BtnTurn)

protected:

virtual bool onTouchBegan(Touch* touch, Event* pEvent);

virtual void onTouchMoved(Touch *pTouch, Event *pEvent);

virtual void onTouchEnded(Touch *pTouch, Event *pEvent);

//点击按钮之后的动画

void runTouchedAmt(Sprite * btn);

//滑动界面的动画

void runSlidedAmt(bool isLeft,float ratio,float judgePosX);

private:

Sprite * m_btn1;

Sprite * m_btn2;

Sprite * m_btn3;

Sprite * m_btn4;

Vec2 m_posBottom;

Vec2 m_posLeft;

Vec2 m_posTop;

Vec2 m_posRight;

Point m_firstPos;

Size m_winSize;

bool m_valid;//先点击有效区域

bool m_invalid;//先点击无效区域

};

#endif

这里最主要的核心代码就是沿椭圆轨迹旋转效果,之前有篇文章讲解了沿椭圆运动的动画,可以像用系统的MoveTo等使用runAction,参考地址:

http://blog.csdn.net/sharing_li/article/details/43268877

本篇将不采用链接中说的方法来实现。

首先,我们定义一些全局数据:

const float RUNTIME = 0.3; //动画运行时间

float A;//椭圆长半径

float Bd;//下椭圆短半径

float Bu;//上椭圆短半径

float Cx;//椭圆中心X坐标

float Cy;//椭圆中心Y坐标

再来看看我们的初始化函数:

m_winSize = Director::getInstance()->getWinSize();

m_posBottom = Vec2(0,0);

m_posLeft = Vec2(-m_winSize.width * 0.24,m_winSize.height * 0.15);

m_posTop = Vec2(0,m_winSize.height * 0.24);

m_posRight = Vec2(m_winSize.width * 0.24,m_winSize.height * 0.15);

A = m_posBottom.x - m_posLeft.x;

Bu = m_posTop.y - m_posLeft.y;

Bd = m_posLeft.y - m_posBottom.y;

Cx = m_posBottom.x;

Cy = m_posLeft.y;

Texture2D * pTt2d = Director::getInstance()->getTextureCache()->addImage(BtnTurn/btn.png);

m_btn1 = Sprite::createWithTexture(pTt2d);

m_btn1->setPosition(m_posBottom);

m_btn1->setTag(Pos_Bottom);

this->addChild(m_btn1,4);

m_btn2 = Sprite::createWithTexture(pTt2d);

m_btn2->setPosition(m_posLeft);

m_btn2->setScale(0.75);

m_btn2->setOpacity(100);

m_btn2->setTag(Pos_Left);

this->addChild(m_btn2,3);

m_btn3 = Sprite::createWithTexture(pTt2d);

m_btn3->setPosition(m_posTop);

m_btn3->setScale(0.5);

m_btn3->setOpacity(50);

m_btn3->setTag(Pos_Top);

this->addChild(m_btn3,2);

m_btn4 = Sprite::createWithTexture(pTt2d);

m_btn4->setPosition(m_posRight);

m_btn4->setScale(0.75);

m_btn4->setOpacity(100);

m_btn4->setTag(Pos_Right);

this->addChild(m_btn4,3);

auto listenerT = EventListenerTouchOneByOne::create();

listenerT->onTouchBegan = CC_CALLBACK_2(BtnTurn::onTouchBegan,this);

listenerT->onTouchMoved = CC_CALLBACK_2(BtnTurn::onTouchMoved,this);

listenerT->onTouchEnded = CC_CALLBACK_2(BtnTurn::onTouchEnded,this);

listenerT->setSwallowTouches(false);

Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listenerT,this);

return true;

这里,初始化全局变量,和四个按钮的初始位置。可以发现这里的按钮并不是按钮,而是sprite,因为只有显示在最前面的按钮才能响应函数,所以定义成sprite方便处理。我们通过判断点击开始和点击结束,这两个点是否是同一个点来确定是否点击了按钮,然后根据按钮的Zorder来判断是否响应函数。我们还给每个按钮设置了tag值,这个tag值并不是不变的,因为按钮的位置会改变,所以tag的值也会改变,以确保我们通过getChildByTag函数,能够正确获取到相应tag值的按钮,比如getChildByTag(Pos_Top),函数返回的一定是处于最上面位置的那个按钮。

我们来看看onTouchBegan函数:

bool BtnTurn::onTouchBegan(Touch* touch, Event* pEvent)

{

m_firstPos = touch->getLocation();

return true;

}

很简单,就两行代码,获取点击开始的按钮。然后看看onTouchMoved

void BtnTurn::onTouchMoved(Touch *pTouch, Event *pEvent)

{

auto movePos = pTouch->getLocation();

auto judgePos = this->convertToNodeSpace(movePos);

auto box = Rect(-m_winSize.width * 0.5,-m_winSize.height * 0.1,m_winSize.width,m_winSize.height * 0.4);

//优化,不能全屏都可以滑,并判断是先点击有效还是无效区域

if (!box.containsPoint(judgePos))

{

if (!m_valid)

{

m_invalid = true;

}

return ;

}

if (!m_invalid)

{

m_valid = true;

}

else

{

return ;

}

//根据滑动方向来运动

auto ratio = fabsf(movePos.x - m_firstPos.x) * 2 / m_winSize.width;

if (ratio >= 1)

{

return ;

}

this->runSlidedAmt(movePos.x - m_firstPos.x < 0,ratio,fabsf(m_firstPos.x - movePos.x));

}

上面代码中box是可以滑动的有效区域,m_valid和m_invalid是用来判断开始触摸屏幕,是点击了有效区域,还是无效区域。

然后根据滑动的方向,来调用动画实现函数runSlidedAmt:

void BtnTurn::runSlidedAmt(bool isLeft,float ratio,float judgePosX)

{

auto btnTop = this->getChildByTag(Pos_Top);

auto btnLeft = this->getChildByTag(Pos_Left);

auto btnRight = this->getChildByTag(Pos_Right);

auto btnBottom = this->getChildByTag(Pos_Bottom);

auto deltPosDown = m_posRight - m_posBottom;

auto deltPosUp = m_posTop - m_posLeft;

//判断是否需要调换Z顺序

if (judgePosX > m_winSize.width / 4)

{

btnTop->setZOrder(3);

btnLeft->setZOrder(isLeft ? 2 : 4);

btnRight->setZOrder(isLeft ? 4 : 2);

btnBottom->setZOrder(3);

}

auto B1 = isLeft ? Bu : Bd;//判断左边的button沿哪个椭圆运动

auto B2 = isLeft ? Bd : Bu;//判断右边的button沿哪个椭圆运动

int temp = isLeft ? (m_posBottom.x - deltPosDown.x * ratio) : (m_posBottom.x + deltPosDown.x * ratio);

btnBottom->setPosition(Vec2(temp,sin(-acos((temp - Cx)/A)) * Bd + Cy));

btnBottom->setScale(1 - 0.25 * ratio);

btnBottom->setOpacity(255 - 155 * ratio);

temp = isLeft ? (m_posLeft.y + deltPosUp.y * ratio) : (m_posLeft.y - deltPosDown.y * ratio);

btnLeft->setPosition(Vec2(-cos(asin((temp - Cy)/B1)) * A + Cx,temp));

btnLeft->setScale(0.75 - (isLeft ? 0.25 * ratio : -0.25 * ratio));

btnLeft->setOpacity(100 - (isLeft ? 50 * ratio : -155 * ratio));

temp = m_posTop.x + (isLeft ? (deltPosUp.x * ratio) : (-1 * deltPosUp.x * ratio));

btnTop->setPosition(Vec2(temp,sin(acos((temp - Cx)/A)) * Bu + Cy));

btnTop->setScale(0.5 + 0.25 * ratio);

btnTop->setOpacity(50 + 50 * ratio);

temp = m_posRight.y + (isLeft ? (-1 * deltPosDown.y * ratio) : (deltPosUp.y * ratio));

btnRight->setPosition(Vec2(cos(asin((temp - Cy)/B2)) * A + Cx,temp));

btnRight->setScale(0.75 + 0.25 * (isLeft ? ratio : -ratio));

btnRight->setOpacity(100 + (isLeft ? 155 * ratio : -50 * ratio));

}

这里,我们通过椭圆的非标准方程,根据已知的x坐标或者y坐标,求出对应的y坐标或x坐标。假如椭圆的圆心坐标为(Cx,Cy),那么根据方程:

x = A * cosβ + Cx;y = B * sinβ + Cy;

然后根据数学函数库的反三角函数等,就可以求出相应的值了。这里需要注意的是三角函数和反三角函数的值域。

接着,我们来看看onTouchEnded函数:

void BtnTurn::onTouchEnded(Touch *pTouch, Event *pEvent)

{

if (m_invalid)

{

m_invalid = false;

return;

}

auto endPos = pTouch->getLocation();

auto delX = endPos.x - m_firstPos.x;

auto delY = endPos.y - m_firstPos.y;

//如果是点击操作

if (fabsf(delX) < 0.0001 && fabsf(delY) < 0.0001)

{

endPos = this->convertToNodeSpace(endPos);

auto box1 = m_btn1->getBoundingBox();

auto box2 = m_btn2->getBoundingBox();

auto box3 = m_btn3->getBoundingBox();

auto box4 = m_btn4->getBoundingBox();

if (box1.containsPoint(endPos))

{

if (m_btn1->getZOrder() == 4)

{

log(******************Btn1 CallBack***************);

}

else

{

this->runTouchedAmt(m_btn1);

}

}

else if (box2.containsPoint(endPos))

{

if (m_btn2->getZOrder() == 4)

{

log(******************Btn2 CallBack***************);

}

else

{

this->runTouchedAmt(m_btn2);

}

}

else if (box3.containsPoint(endPos))

{

if (m_btn3->getZOrder() == 4)

{

log(******************Btn3 CallBack***************);

}

else

{

this->runTouchedAmt(m_btn3);

}

}

else if (box4.containsPoint(endPos))

{

if (m_btn4->getZOrder() == 4)

{

log(******************Btn4 CallBack***************);

}

else

{

this->runTouchedAmt(m_btn4);

}

}

}

else//滑动操作

{

auto adjustPos = pTouch->getLocation();

//判断滑动方向

if (adjustPos.x - m_firstPos.x < 0)//向左滑动

{

auto tmpBtn = (Sprite *)this->getChildByTag(Pos_Right);

this->runTouchedAmt(tmpBtn);

}

else if (adjustPos.x - m_firstPos.x > 0)

{

auto tmpBtn = (Sprite *)this->getChildByTag(Pos_Left);

this->runTouchedAmt(tmpBtn);

}

}

m_valid = false;

}

首先判断是否是点击操作,如果是,再来判断点击了哪个button,如果是最前面的button,就响应函数,如果不是则调用动画效果;如果不是点击操作,那就是滑动操作,然后根据滑动方向调用调整动画。我们来看看runTouchedAmt函数:

void BtnTurn::runTouchedAmt(Sprite * btn)

{

auto tag = btn->getTag();

switch (tag)

{

case Pos_Left :

{

btn->runAction(Spawn::create(ScaleTo::create(RUNTIME,1),

Sequence::createWithTwoActions(MoveTo::create(RUNTIME / 2,m_posBottom),

MoveTo::create(RUNTIME / 2,m_posBottom)),

FadeIn::create(RUNTIME),NULL));

btn->setZOrder(4);

auto topBtn = (Sprite *)(this->getChildByTag(Pos_Top));

topBtn->runAction(Spawn::create(ScaleTo::create(RUNTIME,0.75),

MoveTo::create(RUNTIME,m_posLeft),

FadeTo::create(RUNTIME,100),NULL));

topBtn->setZOrder(3);

auto rightBtn = (Sprite *)this->getChildByTag(Pos_Right);

rightBtn->runAction(Spawn::create(ScaleTo::create(RUNTIME,0.5),

MoveTo::create(RUNTIME,m_posTop),

FadeTo::create(RUNTIME,50),NULL));

rightBtn->setZOrder(2);

auto bottomBtn = (Sprite *)this->getChildByTag(Pos_Bottom);

bottomBtn->runAction(Spawn::create(ScaleTo::create(RUNTIME,0.75),

MoveTo::create(RUNTIME,m_posRight),

FadeTo::create(RUNTIME,100),NULL));

bottomBtn->setZOrder(3);

btn->setTag(Pos_Bottom);

topBtn->setTag(Pos_Left);

rightBtn->setTag(Pos_Top);

bottomBtn->setTag(Pos_Right);

}

break;

case Pos_Top :

{

btn->runAction(Spawn::create(ScaleTo::create(RUNTIME,1),

Sequence::createWithTwoActions(MoveTo::create(RUNTIME/2,m_posLeft),MoveTo::create(RUNTIME/2,m_posBottom)),

FadeIn::create(0.2),NULL));

btn->setZOrder(4);

auto rightBtn = (Sprite *)this->getChildByTag(Pos_Right);

rightBtn->runAction(Spawn::create(Sequence::createWithTwoActions(ScaleTo::create(RUNTIME/2,0.5),ScaleTo::create(RUNTIME/2,0.75)),

Sequence::createWithTwoActions(MoveTo::create(RUNTIME/2,m_posTop),MoveTo::create(RUNTIME/2,m_posLeft)),

Sequence::createWithTwoActions(FadeTo::create(RUNTIME/2,50),FadeTo::create(RUNTIME/2,100)),NULL));

rightBtn->setZOrder(3);

auto bottomBtn = (Sprite *)this->getChildByTag(Pos_Bottom);

bottomBtn->runAction(Spawn::create(ScaleTo::create(RUNTIME,0.5),

Sequence::createWithTwoActions(MoveTo::create(RUNTIME/2,m_posRight),MoveTo::create(RUNTIME/2,m_posTop)),

FadeTo::create(RUNTIME,50),NULL));

bottomBtn->setZOrder(2);

auto leftBtn = (Sprite *)this->getChildByTag(Pos_Left);

leftBtn->runAction(Spawn::create(Sequence::createWithTwoActions(ScaleTo::create(RUNTIME/2,1),ScaleTo::create(RUNTIME/2,0.75)),

Sequence::createWithTwoActions(MoveTo::create(RUNTIME/2,m_posBottom),MoveTo::create(RUNTIME/2,m_posRight)),

Sequence::createWithTwoActions(FadeIn::create(RUNTIME/2),FadeTo::create(RUNTIME/2,100)),NULL));

leftBtn->setZOrder(3);

btn->setTag(Pos_Bottom);

leftBtn->setTag(Pos_Right);

rightBtn->setTag(Pos_Left);

bottomBtn->setTag(Pos_Top);

}

break;

case Pos_Right :

{

btn->runAction(Spawn::create(ScaleTo::create(RUNTIME,1),

MoveTo::create(RUNTIME,m_posBottom),

FadeIn::create(RUNTIME),NULL));

btn->setZOrder(4);

auto topBtn = (Sprite *)this->getChildByTag(Pos_Top);

topBtn->runAction(Spawn::create(ScaleTo::create(RUNTIME,0.75),

MoveTo::create(RUNTIME,m_posRight),

FadeTo::create(RUNTIME,100),NULL));

topBtn->setZOrder(3);

auto leftBtn = (Sprite *)this->getChildByTag(Pos_Left);

leftBtn->runAction(Spawn::create(ScaleTo::create(RUNTIME,0.5),

MoveTo::create(RUNTIME,m_posTop),

FadeTo::create(RUNTIME,50),NULL));

leftBtn->setZOrder(2);

auto bottomBtn = (Sprite *)this->getChildByTag(Pos_Bottom);

bottomBtn->runAction(Spawn::create(ScaleTo::create(RUNTIME,0.75),

MoveTo::create(RUNTIME,m_posLeft),

FadeTo::create(RUNTIME,100),NULL));

bottomBtn->setZOrder(3);

btn->setTag(Pos_Bottom);

topBtn->setTag(Pos_Right);

leftBtn->setTag(Pos_Top);

bottomBtn->setTag(Pos_Left);

}

break;

}

}

代码好像有点多,其实也就是分别处理点击了除最前面按钮的动画效果。这里简单起见,没有用椭圆效果,用的moveto函数。

赞助本站

人工智能实验室
AiLab云推荐
展开

热门栏目HotCates

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