您的位置:首页 > 移动开发 > Cocos引擎

Cocos2d-x 动作之创建自定义动作

2013-10-16 17:07 375 查看
为了追踪鱼游动的方向,我们可以编写一个定时器,通过帧的转换来更新鱼的方向,不过这也是一个既烦琐又难以维护的办法。参考引擎的做法,我们不妨进一步抽象出独立的旋转跟踪动作,根据精灵的移动路径设置合适的旋转角度。

CCAction
包含两个重要的方法:
step
update
step
方法会在每一帧动作更新时触发,该方法接受一个表示调用时间间隔的参数
dt
dt
的积累即为动作运行的总时间。引擎利用积累时间来计算动作运行的进度(一个从0到1的实数),并调用
update
方法更新动作。
update
方法是
CCAction
的核心,它由
step
方法调用,接受一个表示动作进度的参数,每一个动作都需要利用进度值改变目标节点的属性或执行其他指令。自定义动作只需要从这两个方法入手即可,我们通常只需要修改
update
方法就可以实现简单的动作。

下面我们编写一个继承于
CCAction
CCRotateAction
动作。如同复合动作与变速动作一样,它会把另一个动作包装起来,在执行被包装动作的同时,设置精灵的方向。为此,我们需要在每一帧记录上一帧精灵的位置,然后再根据精灵两帧的位移确定精灵的方向。由于我们必须在
CCRotateAction
执行的同时运行被包含的目标动作,所以我们需要在
step
方法中调用目标动作的
step
方法。下面我们来看
CCRotateAction
的实现。

“RotateWithAction.h”中的定义如下:
class RotateWithAction : public CCActionInterval
{
public:
CCObject* copyWithZone(CCZone* pZone);
~RotateWithAction();
static RotateWithAction* create(CCActionInterval * action);
virtual void startWithTarget(CCNode* pTarget);
bool initWithAction(CCActionInterval* pAction);
bool isDone();
void step(ccTime dt);

protected:
void RotateWithAction::setInnerAction(CCActionInterval* pAction);

CCNode* pInnerTarget;
CCActionInterval* pInnerAction;

};


“RotateWithAction.cpp”中的实现如下:
RotateWithAction::~RotateWithAction()
{
CC_SAFE_RELEASE(pInnerAction);
}

RotateWithAction* RotateWithAction::create(CCActionInterval* pAction)
{
RotateWithAction* action = new RotateWithAction();
if (action && action->initWithAction(pAction))
{
action->autorelease();
return action;
}
CC_SAFE_DELETE(action);
return NULL;
}

bool RotateWithAction::initWithAction(CCActionInterval* pAction)
{
pAction->retain();
pInnerAction = pAction;
return true;
}

void RotateWithAction::startWithTarget(CCNode* pTarget)
{
pInnerTarget = pTarget;
CCAction::startWithTarget(pTarget);
pInnerAction->startWithTarget(pTarget);
}

bool RotateWithAction::isDone()
{
return pInnerAction->isDone();
}

void RotateWithAction::step(ccTime dt)
{
CCPoint prePos = pInnerTarget->getPosition();
pInnerAction->step(dt);
CCPoint curPos = pInnerTarget->getPosition();

float tan = -(curPos.y - prePos.y) / (curPos.x - prePos.x);
float degree = atan(tan);
degree = degree / 3.14159f * 180;

pInnerTarget->setRotation(degree);
}

void RotateWithAction::setInnerAction(CCActionInterval* pAction)
{
if (pInnerAction != pAction)
{
CC_SAFE_RELEASE(pInnerAction);
pInnerAction = pAction;
CC_SAFE_RETAIN(pInnerAction);
}
}

CCObject* RotateWithAction::copyWithZone(CCZone* pZone)
{
CCZone* pNewZone = NULL;
RotateWithAction* pCopy = NULL;
if(pZone && pZone->m_pCopyObject)
{
pCopy = (RotateWithAction*)(pZone->m_pCopyObject);
}
else
{
pCopy = new RotateWithAction();
pZone = pNewZone = new CCZone(pCopy);
}

CCActionInterval::copyWithZone(pZone);

pCopy->initWithAction(dynamic_cast<CCActionInterval*>
(pInnerAction->copy()->autorelease()));

CC_SAFE_DELETE(pNewZone);
return pCopy;
}


也许有的读者已经有了疑问,
step
方法与
update
方法都可以做到每一帧判断一次方向,为什么选择重载
step
方法而不是
update
方法呢?这是因为引擎在
step
方法中对动作对象的内部成员进行了更新,更新后才会由此方法调用
update
方法来更新目标节点。在方向追踪的动作中,我们除了在每一帧判断方向,还必须同步执行被包装的动作。这就需要我们调用被包装动作的
step
方法,以保证对象能够被完整地更新。

现在,我们已经不需要使用4.6节介绍的
CCSpawn
来实现蹩脚的方向追踪效果了,只要把需要追踪方向的动作传递给
CCRotateAction
,即可得到一个自动改变鱼方向的智能动作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  cocos2d-x
相关文章推荐