动作应用3
让一个精灵跟随另一个精灵的移动,自定义动作的应用
自定义跟随动作:延时动作
class MyFollow : public ActionInterval
{
public:
static MyFollow* create(float dt, Sprite*sprite,float r) //因为是跟随另一个精灵,必须有目标精灵的参数,参数3是跟随时和目标最近距离
{
MyFollow* ret =new MyFollow;
ret->init(dt, sprite, r);
ret->autorelease();
return ret;
}
~MyFollow()
{
if (_dest)
_dest->release();//把retain的目标精灵release掉
}
Sprite* _dest = nullptr; //存放目标精灵
float _r;
bool init(floatdt, Sprite*sprite, float r)
{
ActionInterval::initWithDuration(dt);
_dest = sprite;
_r = r;
_dest->retain(); // 这个动作引用了sprite
return true;
}
void startWithTarget(Node *target) //因为初始化设置都在init中做完了,所以这里这个函数并没有用
{
ActionInterval::startWithTarget(target);
}
/*runAction */
void update(float )
{
// 判断目标的引用计数器是不是只有1,如果是
// 则表明没有其他人再对它引用,也就是说_dest对象被删掉了
if(_dest->getReferenceCount() == 1)
{
_target->removeFromParent();//如果目标精灵被删,删掉跟随精灵
return;
}
/* 如果target位置不在以_dest为中心的,半径为_r圆圈内的话,那么target要移动到这个范围内
*/
// 取得_dest精灵的中心点位置
Rect rc =_dest->getBoundingBox();
Vec2 center = Vec2(rc.getMidX(),rc.getMidY());
// 跟随精灵的坐标
Vec2 pos =_target->getPosition();
float dist =pos.getDistance(center); //计算距离
if (dist > _r)
{
//具体的移动:
方法1:计算角度移动
float angle = (pos -center).getAngle();
float x = sinf(angle);
float y = cosf(angle);
_target->setPosition(_target->getPosition()+ Vec2(x, y));
方法2:运用了normalize函数,这个函数将会根据当前Vec2求出其sin和cos值并覆盖到当前这个Vec2中
Vec2 d = center - pos;
d.normalize();
_target->setPosition(_target->getPosition()+ d*2); //2个像素单位的移动
}
}
};
应用这个自定义动作:
bool init()
{ Layer::init();
/* 被跟随对象 */
Sprite* sp1 = Sprite::create("Images/blocks.png");addChild(sp1);
sp1->setTag(100);
/* 跟随对象 */
Sprite* sp2 = Sprite::create("Images/close.png");
addChild(sp2);
/* 执行跟随action,时间设置长一点以便拖动 */
sp2->runAction(MyFollow::create(1000, sp1, 64));
/*测试代码 */
sp1->runAction(MoveBy::create(2.0f,Vec2(200, 200)));
/* 添加触摸拖动 */
auto ev = EventListenerTouchOneByOne::create();
ev->onTouchBegan = [](Touch*,Event*){returntrue; };
ev->onTouchMoved = [&](Touch*touch, Event*)
{
Node* sp1 =this->getChildByTag(100);
if (sp1 == NULL)
return;
sp1->setPosition(sp1->getPosition()+ touch->getDelta());
//sp1->removeFromParent();
};
this->_eventDispatcher->addEventListenerWithSceneGraphPriority(ev,this);
return true;
}
总结:
1. normalize函数的学习
2. 自定义延时动作
3. startWithAction和init的工作内容感觉有些重复
4. 关联其他精灵的动作要考虑目标精灵的存活与否。