水果转盘旋转特效

做了一个水果转盘,飞禽走兽的旋转特效;效果如下:

水果转盘旋转特效_第1张图片

水果转盘旋转特效_第2张图片

下面说一下实现的思路:使用定时器移动亮块的位置;定时器先让亮块启动,并逐步加速,然后是高速的转动,在慢慢的减速,最后在指定的地方停下来。

一开始是创建一个亮块,然后使用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编辑器的效果图:

水果转盘旋转特效_第3张图片

水果转盘旋转特效_第4张图片

 

//=======================================================================================

cocos2dx精灵做正逆时针圆周运动

这个是在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;
}

 

//=======================================================================================

基于cocos2dx3.2自定义圆周运动

这个运动简单地实现了一下,可以凑合用,但是并没有实现动作的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++;
}

 

 

 

参考:

//=============================================================================

cocos2dx 3.2 学习篇之六(精灵运动,自定义运动轨迹(太极八卦))

 

//=============================================================================

cocos2d-x学习笔记(三)让精灵按照自己设定的运动轨迹行动(曲线移动)。(以椭圆轨迹为例)

 

//=============================================================================

Cocos2d-x教程(16)-自定义动作 圆周运动

 

//=============================================================================

Cocos2d-js做的一个老虎机效果抽奖

 

//=============================================================================

cocos2d-x 手游研发----博彩大转盘

 

cocos 水果机,老Tiger虎机流水灯,博彩大转盘效果

 

你可能感兴趣的:(Cocos2d-x,C++)