复合动作

前面介绍的简单动作显然不足以满足游戏开发的要求,在这些动作的基础上,Cocos2d-x为我们提供了一套动作的复合机制,允许我们组合各种基本动作,产生更为复杂和生动的动作效果。复合动作是一类特殊的动作,因此它也需要使用CCNoderunAction方法执行。而它的特殊之处在于,作为动作容器,复合动作可以把许多动作组合成一个复杂的动作。因此,我们通常会使用一个或多个动作来创建复合动作,再把动作交给节点执行。

复合动作十分灵活,这是由于复合动作本身也是动作,因此也可以作为一个普通的动作嵌套在其他复合动作中。

1. 重复(CCRepeat/CCRepeatForever

有的情况下,动作只需要执行一次即可,但我们还常常遇到一个动作反复执行的情况。对于一些重复的动作,如鱼的摆动、能量槽的转动,我们可以通过CCRepeatCCRepeatForever这两个方式重复执行:

CCRepeat* CCRepeat::create(CCFiniteTimeAction *pAction, unsigned int times);
CCRepeatForever *CCRepeatForever::create(CCActionInterval *pAction);

在上述代码中,pAction参数表示需要重复的动作,第一个方法允许指定动作的重复次数,第二个方法使节点一直重复该动作直到动作被停止。

2. 并列(CCSpawn

指的是使一批动作同时执行。在《捕鱼达人》游戏中,鱼一边沿曲线游动一边摆尾巴,炮弹一边发射一边喷射气体,金币一边旋转一边移动等动作,都可以通过CCSpawn来实现。CCSpawnCCActionInterval派生而来的,它提供了两个工厂方法:

CCSpawn::create(CCFiniteTimeAction *pAction1,...);
CCSpawn::create(CCFiniteTimeAction *pAction1, CCFiniteTimeAction *pAction2);

其中第一个静态方法可以将多个动作同时并列执行,参数表中最后一个动作后需要紧跟NULL表示结束。第二个则只能指定两个动作复合,不需要在最后一个动作后紧跟NULL。此外,执行的动作必须是能够同时执行的、继承自CCFiniteTimeAction的动作。组合后,CCSpawn动作的最终完成时间由其成员中最大执行时间的动作来决定。

3. 序列(CCSequence

除了让动作同时并列执行,我们更常遇到的情况是顺序执行一系列动作。CCSequence提供了一个动作队列,它会顺序执行一系列动作,例如鱼游出屏幕外后需要调用回调函数,捕到鱼后显示金币数量,经过一段时间再让金币数量消失,等等。

CCSequence同样派生自CCActionInterval。与CCSpawn一样,CCSquence也提供了两个工厂方法:

CCSequence::create(CCFiniteTimeAction *pAction1,...);
CCSequence::create(CCFiniteTimeAction *pAction1,CCFiniteTimeAction *pAction2);

它们的作用分别是建立多个和两个动作的顺序执行的动作序列。同样要注意复合动作的使用条件,部分的非延时动作(如CCRepeatForever)并不被支持。

在实现CCSequenceCCSpawn两个组合动作类时,有一个非常有趣的细节:成员变量中并没有定义一个可变长的容器来容纳每一个动作系列,而是定义了m_pOnem_pTwo两个动作成员变量。如果我们创建了两个动作的组合,那么m_pOnem_pTwo就分别是这两个动作本身;当我们创建更多动作的组合时,引擎会把动作分解为两部分来看待,其中后一部分只包含最后一个动作,而前一部分包含它之前的所有动作,引擎把m_pTwo设置为后一部分的动作,把m_pOne设置为其余所有动作的组合。例如,语句sequence = CCSequence::create(action1, action2, action3, action4, NULL);就等价于:

CCSequence s1 = CCSequence::createWithTwoActions(action1, action2);
CCSequence s2 = CCSequence::createWithTwoActions(s1, action3);
sequence  = CCSequence::createWithTwoActions(s2, action4);

CCSpawnCCSequence所采用的机制类似,在此就不再赘述了。采用这种递归的方式,而不是直接使用容器来定义组合动作,实际上为编程带来了极大的便利。维护多个动作的组合是一个复杂的问题,现在我们只需要考虑两个动作组合的情况就可以了。下面是CCSpawn的一个初始化方法,就是利用递归的思想简化了编程的复杂度:

CCFiniteTimeAction* CCSpawn::create(CCArray *arrayOfActions)
{
    CCFiniteTimeAction* prev = (CCFiniteTimeAction*)arrayOfActions->objectAtIndex(0);

    for (unsigned int i = 1; i < arrayOfActions->count(); ++i)
    {
        prev = create(prev, (CCFiniteTimeAction*)arrayOfActions->objectAtIndex(i));
    }

    return prev;
}

众所周知,递归往往会牺牲一些效率,但能换来代码的简洁。在这两个复合动作中,细节处理得十分优雅,所有的操作都只需要针对两个动作实施,多个动作的组合会被自动变换为递归实现:

void CCSpawn::update(float time)
{
    if (m_pOne)
    {
        m_pOne->update(time);
    }
    if (m_pTwo)
    {
        m_pTwo->update(time);
    }
}

CCActionInterval* CCSpawn::reverse(void)
{
    return CCSpawn::create(m_pOne->reverse(), m_pTwo->reverse());
}

4. 延时(CCDelayTime

CCDelayTime是一个“什么都不做”的动作,类似于音乐中的休止符,用来表示动作序列里一段空白期,通过占位的方式将不同的动作段串接在一起。实际上,这与一个定时期实现的延迟没有区别,但相比之下,使用CCDelayTime动作来延时就可以方便地利用动作序列把一套动作连接在一起。CCDelayTime只提供了一个工程方法,如下所示:

CCDelayTime::create(float d);

其中仅包含一个实型参数,表示动作占用的时间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值