做了一个水果转盘,飞禽走兽的旋转特效;效果如下:
下面说一下实现的思路:使用定时器移动亮块的位置;定时器先让亮块启动,并逐步加速,然后是高速的转动,在慢慢的减速,最后在指定的地方停下来。
一开始是创建一个亮块,然后使用MoveTo来实现;但是效果不太好,当速度很快的时候,亮块会漂移到外部的区域,没有按照规定的轨迹来进行移动。
//----1.精灵转动----
int m_iStarIndex;
int m_runTime;
void runPlay();
void runAct(float time);
//----精灵转动----
void LoginScene::runPlay()
{
//1.
m_runTime = 0;
this->schedule(schedule_selector(LoginScene::runAct), 1.0f);
//2.
}
//----1.精灵转动----
void LoginScene::runAct(float time)
{
float t1 = 0.8f; //1--开始启动
float t2 = 0.6f; //1--开始加速
float t3 = 0.2f; //2--快速匀速
float t4 = 0.6f; //3--开始减速
float t5 = 0.8f; //3--慢慢停止
m_runTime++;
log("----m_runTime,%d", m_runTime);
if (m_iStarIndex >= 28 || m_iStarIndex < 0)
{
m_iStarIndex = 0;
}
m_iStarIndex++;
//起始位置
char imgName[10] = { 0 };
sprintf(imgName, "img_run%d", m_iStarIndex);
Sprite* sp = static_cast(nodeRun->getChildByName("sp_run"));
ImageView* iv = static_cast(nodeRun->getChildByName(imgName));
Vec2 vStart = sp->getPosition();
Vec2 vEnd = iv->getPosition();
MoveTo* mt = MoveTo::create(0.5f, vEnd);
sp->runAction(Sequence::create(DelayTime::create(0.01f), mt, NULL));
if (m_runTime == 2)
{
this->unschedule(schedule_selector(LoginScene::runAct));
this->schedule(schedule_selector(LoginScene::runAct), t2);
}
else if (m_runTime == 10)
{
this->unschedule(schedule_selector(LoginScene::runAct));
this->schedule(schedule_selector(LoginScene::runAct), t3);
}
else if (m_runTime == 40)
{
this->unschedule(schedule_selector(LoginScene::runAct));
this->schedule(schedule_selector(LoginScene::runAct), t4);
}
else if (m_runTime == 48)
{
this->unschedule(schedule_selector(LoginScene::runAct));
this->schedule(schedule_selector(LoginScene::runAct), t5);
}
else if (m_runTime > 50 && m_iStarIndex==1)
{
this->unschedule(schedule_selector(LoginScene::runAct));
m_runTime = 0;
}
}
后来发现问题了,换了另一个实现方法:创建好全部的亮块,并先隐藏;通过定时器来控制显示和隐藏。最终通过调整达到了预期的效果。下面是实现的代码。
//----2.精灵转动----
bool m_bCreate;
int m_maxSize;
int m_curID;
int m_runNum;
int m_endID;
void createBox();
void runTurnBox(float time);
void switchBox(int boxID, bool isShow);
void setEndIndex(int idx);
void testRunBox();
void randEndIndex();
//--------------------------------------------------------------
//创建好转动的亮块
void LoginScene::createBox()
{
m_runNum = -1;
m_curID = 0;
m_maxSize = 28;//一圈的总数量
for (int i = 0; i < m_maxSize; i++)
{
char imgName[10] = { 0 };
sprintf(imgName, "img_run%d", i+1);
ImageView* iv = static_cast(nodeRun->getChildByName(imgName));
iv->setZOrder(1);
CCPoint pos = iv->getPosition();
auto* spBox = Sprite::create("logon/run/img_run0.png");
spBox->setTag(300 + i);
spBox->setPosition(pos);
spBox->setVisible(false);
nodeRun->addChild(spBox, 0);
}
Sprite* sp = static_cast(nodeRun->getChildByName("sp_run"));
sp->setVisible(false);
m_bCreate = true;
}
//使用定时器启动亮块运转起来
void LoginScene::runTurnBox(float time)
{
float t1 = 0.8f; //1--开始启动
float t2 = 0.6f; //1--开始加速
float t3 = 0.2f; //2--快速匀速
float t4 = 0.6f; //3--开始减速
float t5 = 0.8f; //3--慢慢停止
if (m_maxSize > 0)
{
if (m_curID > m_maxSize - 1)
m_curID = 0;
switchBox(m_curID, true);
int lastID = m_curID - 1;
if (lastID < 0)
lastID = m_maxSize - 1;
switchBox(lastID, false);
m_curID++;
}
m_runNum++;
//this->unschedule(schedule_selector(LoginScene::runTurnBox));
//CCLOG("--time=%f m_runNum=%d m_curID=%d", time, m_runNum, m_curID);
//if (m_runNum < 30)
//{
// float nexttime = time + m_runNum * 0.01f;
// if (nexttime >= 1.5f)
// {
// nexttime = 1.5f;
// }
// CCLOG("--nexttime=%f", nexttime);
// this->schedule(schedule_selector(LoginScene::runTurnBox), nexttime);
//}
if (m_runNum == 2)//开始运转
{
this->unschedule(schedule_selector(LoginScene::runTurnBox));
this->schedule(schedule_selector(LoginScene::runTurnBox), 0.2f);
}
else if (m_runNum == 5)//加速运转
{
this->unschedule(schedule_selector(LoginScene::runTurnBox));
this->schedule(schedule_selector(LoginScene::runTurnBox), 0.02f);
}
else if (m_runNum == 90)//快速运转
{
this->unschedule(schedule_selector(LoginScene::runTurnBox));
this->schedule(schedule_selector(LoginScene::runTurnBox), 0.1f);
}
else if (m_runNum > 105 && m_runNum < 112)//开始减速
{
if ((m_curID < m_endID && (m_endID - m_curID) <= 7) ||
(m_curID > m_endID) && (m_curID - m_endID) >= 21 )
{
this->unschedule(schedule_selector(LoginScene::runTurnBox));
this->schedule(schedule_selector(LoginScene::runTurnBox), 0.3f);
}
else
{
this->unschedule(schedule_selector(LoginScene::runTurnBox));
this->schedule(schedule_selector(LoginScene::runTurnBox), 0.2f);
}
}
else if (m_runNum >= 112 && m_curID == m_endID)//停止
{
this->unschedule(schedule_selector(LoginScene::runTurnBox));
m_runNum = 0;
m_curID = m_endID;//下一轮开始位置
}
CCLOG("--time=%f m_runNum=%d m_curID=%d m_endID=%d", time, m_runNum, m_curID, m_endID);
}
//控制亮块的显示和隐藏
void LoginScene::switchBox(int boxID, bool isShow)
{
auto* spBox = nodeRun->getChildByTag(300 + boxID);
spBox->setVisible(isShow);
}
//设置结束索引
void LoginScene::setEndIndex(int idx)
{
m_endID = idx;
CCLOG("--m_endID=%d", m_endID);
}
//随机一个结束索引方便测试
void LoginScene::randEndIndex()
{
int _num = 1 + rand() % m_maxSize;
setEndIndex(_num);
}
//点击按钮,触发进行测试
void LoginScene::testRunBox()
{
randEndIndex();
if (!m_bCreate)
{
createBox();
}
this->schedule(schedule_selector(LoginScene::runTurnBox), 0.1f);
}
下面是UI编辑器的效果图:
//=======================================================================================
这个是在cocos2dx示例中看到的,可能会用到,记录下载
void HelloWorld::update(float dt)
{
static float time = 0;
float r = 80;
sprite1->setPosition(Vec2(cosf(time * 2) * r, sinf(time * 2) * r));
sprite2->setPosition(Vec2(sinf(time * 2) * r, cosf(time * 2) * r));
time += dt;
}
//=======================================================================================
这个运动简单地实现了一下,可以凑合用,但是并没有实现动作的clone与reverse,先留一个坑,免得忘记了,以后抽时间完善......
.h文件......
class CircleMoveAction : public cocos2d::ActionInterval
{
public:
bool initWithDuration(float duration, const cocos2d::Point& center,float radius, float angle, float moveTimes);
//
// Overrides
//
virtual CircleMoveAction* clone() const override;
virtual CircleMoveAction* reverse() const override;
virtual void startWithTarget(cocos2d::Node *target) override;
virtual void update(float dt) override;
public:
static CircleMoveAction* create(float duration, const cocos2d::Point& center,float radius, float angle, float moveTimes);
public:
// CircleMoveAction();
// ~CircleMoveAction();
// void updateCircleCenter(Ref *pSender);
// void unUpdateCircleCenter(Ref *pSender);
private:
// CC_SYNTHESIZE(bool, onTouch, OnTouch);
protected:
cocos2d::Point m_circleCenter; //圆心
float m_circleRadius; //半径
float m_radian; //弧度
float m_angle; //旋转角度
int m_moveTimes; //刷新次数
float m_duration; //运动时间
};
.cpp文件...
//CircleMoveAction::CircleMoveAction()
//{
// __NotificationCenter::getInstance()->addObserver(this, callfuncO_selector(CircleMoveAction::updateCircleCenter), "updateEnemy", NULL);
// __NotificationCenter::getInstance()->addObserver(this, callfuncO_selector(CircleMoveAction::unUpdateCircleCenter), "unUpdateEnemy", NULL);
//}
//
//CircleMoveAction::~CircleMoveAction()
//{
// __NotificationCenter::getInstance()->removeObserver(this, "updateEnemy");
// __NotificationCenter::getInstance()->removeObserver(this, "unUpdateEnemy");
//}
//
//void CircleMoveAction::updateCircleCenter(cocos2d::Ref *pSender)
//{
// setOnTouch(true);
//}
//
//void CircleMoveAction::unUpdateCircleCenter(cocos2d::Ref *pSender)
//{
// setOnTouch(false);
//}
CircleMoveAction* CircleMoveAction::create(float duration, const cocos2d::Point& center,float radius, float angle, float moveTimes)
{
CircleMoveAction *pRet = new CircleMoveAction();
if (pRet && pRet->initWithDuration(duration, center, radius, angle, moveTimes))
{
pRet->autorelease();
return pRet;
}
CC_SAFE_DELETE(pRet);
return nullptr;
}
bool CircleMoveAction::initWithDuration(float duration, const cocos2d::Point& center,float radius, float angle, float moveTimes)
{
// log(">>>>>>>>%f", duration);
if (CCActionInterval::initWithDuration(duration*2))
{
this->m_circleCenter = center;
this->m_circleRadius = radius;
this->m_duration = duration;
this->m_angle = angle;
this->m_moveTimes = moveTimes;
/************************************************************************/
/* 计算每次update调用时需要转动的弧度 */
/************************************************************************/
this->m_radian = angle / duration * Director::getInstance()->getAnimationInterval() / (180 / M_PI);
// log(">>>>>>>%f", 1.0f/Director::getInstance()->getAnimationInterval());
return true;
}
return false;
}
void CircleMoveAction::startWithTarget(cocos2d::Node *target)
{
CCActionInterval::startWithTarget(target);
// m_initPos = _target->getPosition();
}
CircleMoveAction* CircleMoveAction::clone() const
{
// no copy constructor
// auto circleAct = new CircleMoveAction();
// circleAct->initWithDuration(m_duration, m_circleCenter, m_circleRadius, m_angle);
// circleAct->autorelease();
// return circleAct;
}
CircleMoveAction* CircleMoveAction::reverse() const
{
// return CircleMoveAction::create(m_duration, m_circleCenter, m_circleRadius, -m_angle);
}
void CircleMoveAction::update(float dt)
{
float radian = m_radian*m_moveTimes;
float x = m_circleRadius*sin(radian);
float y = m_circleRadius*cos(radian);
Point newPoint = Point(m_circleCenter.x+x, m_circleCenter.y+y);
_target->setPosition(newPoint);
m_moveTimes++;
}
参考:
//=============================================================================
//=============================================================================
//=============================================================================
//=============================================================================
//=============================================================================