1.效果图


cocos2d 绕椭圆移动_数学知识


跟我合作的美工兼策划说要给主角加上主角光环,绕椭圆形移动。cocos2d自带没有,参考网上的写了一个。

2.椭圆数学知识

有关椭圆的数学知识我已经忘光了!网上找了点资料:

cocos2d 绕椭圆移动_#include_02

a是椭圆的长半轴,b是椭圆的短半轴。 o是角度,范围是[0, 2π]。

我们需要知道椭圆上的位置,可以用下面的公式:

cocos2d 绕椭圆移动_数学知识_03



3.直接代码了..


OvalActionInterval.h


#ifndef __JumpGame__OvalInterval__
#define __JumpGame__OvalInterval__

#include "CCActionInterval.h"//包含系统延时类动作头文件

using namespace cocos2d;

// 定义一个结构来包含确定椭圆的参数
typedef struct OvalConfig {
//中心点坐标
Vec2 centerPosition;
//椭圆a长半轴
float a;
//椭圆b短半轴
float b;
//是否逆时针运动
bool moveInAnticlockwise;
//two zOrder
std::pair<int, int> zOrder;
} lOvalConfig;

/**
以椭圆方式移动
*/

class CC_DLL MoveOvalBy : public ActionInterval{
public:
MoveOvalBy();
//用“动作持续时间”和“椭圆控制参数”初始化动作
bool initWithDuration(float t, const OvalConfig& c);
virtual MoveOvalBy* clone() const override;
virtual MoveOvalBy* reverse() const override;
virtual void update(float t);//利用update函数来不断的设定坐标
virtual void startWithTarget(Node *target) override;
public:
//用“动作持续时间”和“椭圆控制参数”创建动作
static MoveOvalBy *create(float t, const OvalConfig& c);

protected:
OvalConfig _config;

//x = a * cos(t) t = [0, 2Pi]
inline float getPositionXAtOval(float t ){//返回X坐标
//参数方程
if(_config.moveInAnticlockwise == false){
return _config.a * cos(6.2831852 * (1 - t));
}else{
return _config.a * cos(6.2831852 * t);
}

}
//y = b * sin(t) t = [0, 2Pi]
inline float getPositionYAtOval(float t ){//返回Y坐标
//参数方程
if(_config.moveInAnticlockwise == false){
return _config.b * sin(6.2831852 * (1 - t));
}else{
return _config.b * sin(6.2831852 * t);
}
}
private:
CC_DISALLOW_COPY_AND_ASSIGN(MoveOvalBy);
};


#endif


OvalActionInterval.cpp


#include "OvalActionInterval.h"

MoveOvalBy::MoveOvalBy(){

}

//
//MoveOvalBy
//
MoveOvalBy* MoveOvalBy::create(float t, const OvalConfig& c){//利用之前定义的椭圆的参数初始化椭圆
MoveOvalBy *action = new MoveOvalBy();
action->initWithDuration(t, c);
action->autorelease();

return action;
}

bool MoveOvalBy::initWithDuration(float t, const OvalConfig& c){
if (ActionInterval::initWithDuration(t)){
_config = c;
return true;
}

return false;
}
void MoveOvalBy::update(float t){
//t [0, 1]
//log("t:%f", t);
if (_target){
float x = getPositionXAtOval(t);//调用之前的坐标计算函数来计算出坐标值
float y = getPositionYAtOval(t);
_target->setPosition(_config.centerPosition + Vec2(x, y));//由于我们画计算出的椭圆你做值是以原点为中心的,所以需要加上我们设定的中心点坐标

if(t <= 0.5){
_target->setLocalZOrder(_config.zOrder.first);
}else{
_target->setLocalZOrder(_config.zOrder.second);
}
}
}

MoveOvalBy* MoveOvalBy::clone() const{
auto action = new MoveOvalBy();
action->initWithDuration(_duration, _config);
action->autorelease();
return action;
}

MoveOvalBy* MoveOvalBy::reverse() const{
OvalConfig newConfig;
newConfig.centerPosition = _config.centerPosition;
newConfig.a = _config.a;
newConfig.b = _config.b;
newConfig.moveInAnticlockwise = !_config.moveInAnticlockwise;
newConfig.zOrder = _config.zOrder;
return MoveOvalBy::create(_duration, newConfig);
}

void MoveOvalBy::startWithTarget(Node *target){
ActionInterval::startWithTarget(target);
}


我这里还加上了zOrder,这样有透视效果。


a等于b的时候就是圆形了。

有时候在游戏中稍微用上点数学知识感觉很爽。
调用如下:


auto size = this->getContentSize();

auto ball = Sprite::createWithSpriteFrameName("defenceBall.png");
this->addChild(ball);
ball->setPosition(Vec2(size.width * 0.5, size.height * 0.5) + Vec2(0, 10));

OvalConfig config;
config.a = 100;
config.b = 20;
config.centerPosition = ball->getPosition();
config.moveInAnticlockwise = true;
config.zOrder = make_pair(-1, 0);
auto moveAction = MoveOvalBy::create(1.0, config);

ball->runAction(RepeatForever::create(moveAction));