• 动作的克隆
    • 动作的倒转

    动作的克隆

    克隆(Clone) 的功能和字面含义一样,如果你对一个节点对象使用了 clone() 方法,你就获得了这个节点对象的拷贝。

    为什么要使用 clone() 方法? 因为当 Action 对象运行时会产生一个内部状态,记录着节点属性的改变。当你想将一个创建的动作,重复使用到不同的节点对象时,如果不用 clone() 方法,就无法确定这个动作的属性到底是怎样的(因为被使用过,产生了内部状态),这会造成难以预料的结果。

    我们来看示例,假如你有一个坐标位置是 (0,0)heroSprite,执行这样一个动作:

    1. MoveBy::create(10, Vec2(400,100));

    你的 heroSprite 就在 10s 的时间中,从 (0,0) 移动到了 (400,100)heroSprite 有了一个新位置 (400,100),更重要的是动作对象也有了节点位置相关的内部状态了。现在假如你有一个坐标位置是 (200,200)emenySprite。你还使用这个相同的动作,emenySprite 就会移动到 (800,200)的坐标位置,并不是你期待的结果。因为第二次将这个动作应用的时候,它已经有内部状态了。使用 clone() 能避免这种情况,克隆获得一个新的动作对象,新的对象没有之前的内部状态。

    从代码中学习用法吧,先看看错误的情况:

    1. // create our Sprites
    2. auto heroSprite = Sprite::create("herosprite.png");
    3. auto enemySprite = Sprite::create("enemysprite.png");
    4. // create an Action
    5. auto moveBy = MoveBy::create(10, Vec2(400,100));
    6. // run it on our hero
    7. heroSprite->runAction(moveBy);
    8. // run it on our enemy
    9. enemySprite->runAction(moveBy); // oops, this will not be unique!
    10. // uses the Actions current internal state as a starting point.

    使用 clone() 的正确情况:

    1. // create our Sprites
    2. auto heroSprite = Sprite::create("herosprite.png");
    3. auto enemySprite = Sprite::create("enemysprite.png");
    4. // create an Action
    5. auto moveBy = MoveBy::create(10, Vec2(400,100));
    6. // run it on our hero
    7. heroSprite->runAction(moveBy);
    8. // run it on our enemy
    9. enemySprite->runAction(moveBy->clone()); // correct! This will be unique

    动作的倒转

    倒转(Reverse) 的功能也和字面意思一样,调用 reverse() 可以让一系列动作按相反的方向执行。reverse() 不是只能简单的让一个 Action 对象反向执行,还能让 SequenceSpawn 倒转。

    倒转使用起来很简单:

    1. // reverse a sequence, spawn or action
    2. mySprite->runAction(mySpawn->reverse());

    思考下面这段代码在执行的时候, 内部发生了什么?

    1. // create a Sprite
    2. auto mySprite = Sprite::create("mysprite.png");
    3. mySprite->setPosition(50, 56);
    4. // create a few Actions
    5. auto moveBy = MoveBy::create(2.0f, Vec2(500,0));
    6. auto scaleBy = ScaleBy::create(2.0f, 2.0f);
    7. auto delay = DelayTime::create(2.0f);
    8. // create a sequence
    9. auto delaySequence = Sequence::create(delay, delay->clone(), delay->clone(),
    10. delay->clone(), nullptr);
    11. auto sequence = Sequence::create(moveBy, delay, scaleBy, delaySequence, nullptr);
    12. // run it
    13. mySprite->runAction(sequence);
    14. // reverse it
    15. mySprite->runAction(sequence->reverse());

    思考起来可能有点困难,我们将执行的每一步列出来,或许能帮助你理解:

    • mySprite 创建
    • mySprite 的坐标位置设置成(50,56)
    • sequence 开始执行
    • sequence 执行第一个动作 moveBy,2s 中 mySprite 移动到了坐标位置(550,56)
    • sequence 执行第二个动作, 暂停 2s
    • sequence 执行第三个动作,scaleBy,2s 中 mySprite 放大了2倍
    • sequence 执行第四个动作,delaySequence,暂停 6s
    • reverse() 被调用,序列倒转,开始反向执行
    • sequence 执行第四个动作,delaySequence,暂停 6s
    • sequence 执行第三个动作,scaleBy,2s 中 mySprite 缩小了2倍 (注意:序列内的动作被倒转)
    • sequence 执行第二个动作, 暂停 2s
    • sequence 执行第一个动作 moveBy,2s 中 mySprite 从坐标位置 (550,56),移动到了 (50, 56)
    • mySprite 回到了最初的位置我们能发现 reverse() 方法使用起来很简单,内部逻辑却一点都不简单。因为 Cocos2d-x 封装了复杂的逻辑,为你留下了简单易用的接口!