cocos2d动作讲解
从本章开始,我们开始讲解cocos2d-x库的动作(Action)。游戏的世界是一个动态的世界:无论是主角精灵还是NPC精灵都处于不断的运动当中,甚至是背景中漂流的树叶,随风而动的小草。这些明显的或者不明显的运动构成了我们栩栩如生的游戏世界。
仔细研究游戏中精灵的运动,我们发现:所有这样的运动都可以细分为若干个基本动作和基本动作的组合。通过进一步扩展,我们可以将同一精灵的更多动作和不同精灵之间的不同动作连贯起来,形成关于整个运动世界的连续模拟。
我们给出示例ZYG003,展示cocos2d-x支持的主要动作:

基本动作
从技术上来说,基本动作的本质就是改变某个图形对象的属性:位置、角度、大小等。cocos2d-x提供超过20种基本动作供我们使用。根据改变完 成所需的时间,可以分为瞬时动作和延时动作。其中,延时动作的执行速度又可以按照不同的方式来改变(位置、大小、颜色、闪烁……)。
再进一步介绍基本动作之前,我们先来简单明确一下动作是如何与CCNode关联起来的。CCNode有一个成员函数叫runAction,定义为:

/** Executes an action, and returns the action that is executed.
The node becomes the action's target.
@warning Starting from v0.8 actions don't retain their target anymore.
@since v0.7.1
@return An Action pointer
*/
CCAction* runAction(CCAction* action);

此接口确保所有的精灵都可以执行各种动作。也正是为了服从这个接口的定义,导致后续各种组合动作也都从CCAction派生。
下面的代码是通常调用某个动作的方法:

CCSize s = CCDirector::sharedDirector()->getWinSize();
// 创建动作
CCActionInterval *actionTo = CCMoveTo::actionWithDuration(2.0f, ccp(s.width - 40.0f, s.height - 40.0f));
// 使用动作(tamara是一个CCSprite指针)
tamara->runAction(actionTo);

瞬时动作
顾名思义,瞬时动作就是不需要时间,马上就完成的动作。瞬时动作的共同基类是CCActionInstant。
cocos2d-x提供以下瞬时动作:

瞬时动作大都有与之对应的属性设置方法,之所以作为一个动作来实现,是为了可以与其他动作形成一个连续动作。下面来看一下瞬时动作的使用。
放置 - CCPlace
效果类似于setPosition(ccp(x, y))。示例代码如下:

void InstantActionLayer::onPlace(CCObject* pSender)
{
CCSize s = CCDirector::sharedDirector()->getWinSize();
// 理论上使用伪随机数前应该srand一下,但是知易的例子中没有,不知道是不是故意这么设计的。
// 如果使用time(NULL)初始化伪随机数种子,要注意time_t有可能是64位的!
CCPoint p = ccp(CCRANDOM_0_1() * s.width, CCRANDOM_0_1() * s.height);
flight->runAction(CCPlace::actionWithPosition(p));
}

隐藏 - CCHide
效果类似于setIsVisible(false)。示例代码如下:
void InstantActionLayer::onHide(CCObject* pSender)
{
flight->runAction(CCHide::action());
}
显示 - CCShow
效果类似于setIsVisible(true)。示例代码如下:
void InstantActionLayer::onShow(CCObject* pSender)
{
flight->runAction(CCShow::action());
}
可见切换 - CCToggleVisibility
效果类似于setIsVisible(!getIsVisible())。示例代码如下:
void InstantActionLayer::onToggle(CCObject* pSender)
{
flight->runAction(CCToggleVisibility::action());
}
水平翻转 - CCFlipX
效果类似于setFlipX(true/false)。示例代码如下:
void InstantActionLayer::onFlipX(CCObject* pSender)
{
flight->runAction(CCFlipX::actionWithFlipX(true));
}
垂直翻转 - onFlipY
效果类似于setFlipY(true/false)。示例代码如下:
void InstantActionLayer::onFlipY(CCObject* pSender)
{
flight->runAction(CCFlipY::actionWithFlipY(true));
}
还有两个较为特殊的动作(网格重用 - CCReuseGrid|停止网格 - CCStopGrid),我们以后介绍。
延时动作
延时动作就是指动作的完成需要一段时间。因此,几乎所有的延时动作都使用执行时间作为第一个参数,它们有着共同的基类CCActionInterval。
cocos2d-x中常用的延时动作:

这里有一个简单的类命名规则:
CCXxxxTo - 绝对动作,执行的结果与当前的状态关系不密切;
CCXxxxBy - 相对动作,在当前的状态上执行某种动作,执行的结果与当前状态是紧密相关的。
移动到 - CCMoveTo
移动 - CCMoveBy
跳跃到 - CCJumpTo
参数为终点位置、跳跃高度和跳跃次数。
跳跃 - CCJumpBy
贝赛尔曲线 - CCBezierBy
支持三次贝赛尔曲线:P0-起点,P1-起点切线方向,P2-终点切线方向,P3-终点。

首先设置贝塞尔参数,然后执行。
放大到 - CCScaleTo
放大 - CCScaleBy
如果参数为小数,那就是缩小了。
旋转到 - CCRotateTo
旋转 - CCRotateBy
闪烁 - CCBlink
色调变化到 - CCTintTo
色调变换 - CCTintBy
变暗到 - CCFadeTo
由无变亮 - CCFadeIn
由亮变无 - CCFadeOut
组合动作
按照一定的次序将上述基本动作组合起来,形成连贯的一套组合动作。组合动作包括以下几类:

序列 - CCSequence
序列的使用非常简单,该类从CCActionInterval派生,本身就可以被CCNode对象执行。该类的作用就是线性排列若干个动作,然后按先后次序逐个执行。

void CompositionActionLayer::onSequence(CCObject* pSender)
{
CCSize s = CCDirector::sharedDirector()->getWinSize();
// 创建5个动作
CCFiniteTimeAction *action0 = CCPlace::actionWithPosition(ccp(s.width / , ));
CCFiniteTimeAction *action1 = CCMoveTo::actionWithDuration(1.2f, ccp(s.width - 50.0f, s.height - 50.0f));
CCFiniteTimeAction *action2 = CCJumpTo::actionWithDuration(1.2f, ccp(, ), 30.0f, );
CCFiniteTimeAction *action3 = CCBlink::actionWithDuration(1.2f, );
CCFiniteTimeAction *action4 = CCTintBy::actionWithDuration(0.5f, , , );
// 将5个动作组合为一个序列,注意不要忘了用NULL结尾。
flight->runAction(CCSequence::actions(action0, action1, action2, action3, action4, action0, NULL));
}

同步 - CCSpawn
同步的使用非常简单,该类也是从CCActionInterval派生,可以被CCNode对象执行。该类的作用就是同时并列执行若干个动作,但要求动作本身是可以同时执行的,比如:移动式翻转、变色、缩放等。
需要特别注意的是,同步执行最后完成的时间由基本动作中用时最大者决定。

void CompositionActionLayer::onSpawn(CCObject* pSender)
{
CCSize s = CCDirector::sharedDirector()->getWinSize();
flight->setRotation(0.0f);
flight->setPosition(ccp(s.width / , ));
// 创建4个需要并行的动作,确保动作用时可组合。(action1/action2/sequence的执行时间都是2秒)
CCFiniteTimeAction *action1 = CCMoveTo::actionWithDuration(2.0f, ccp(s.width - 50.0f, s.height - 50.0f));
CCFiniteTimeAction *action2 = CCRotateTo::actionWithDuration(2.0f, 180.0f);
CCFiniteTimeAction *action3 = CCScaleTo::actionWithDuration(1.0f, 4.0f);
CCFiniteTimeAction *action4 = CCScaleBy::actionWithDuration(1.0f, 0.5f);
CCFiniteTimeAction *sequence = CCSequence::actions(action3, action4, NULL);
// 创建并执行同步动作。
flight->runAction(CCSpawn::actions(action1, action2, sequence, NULL));
}

重复有限次数 - CCRepeat
CCRepeat用来将某一动作重复有限次数,示例代码如下:

void CompositionActionLayer::onRepeat(CCObject* pSender)
{
CCSize s = CCDirector::sharedDirector()->getWinSize();
flight->setRotation(0.0f);
flight->setPosition(ccp(s.width / , ));
// 创建动作序列
CCFiniteTimeAction *action1 = CCMoveTo::actionWithDuration(2.0f, ccp(s.width - 50.0f, s.height - 50.0f));
CCFiniteTimeAction *action2 = CCJumpBy::actionWithDuration(2.0f, ccp(-, -), 30.0f, );
CCFiniteTimeAction *action3 = CCJumpBy::actionWithDuration(2.0f, ccp(s.width / , ), 20.0f, );
CCFiniteTimeAction *sequence = CCSequence::actions(action1, action2, action3, NULL);
// 重复运行上述动作序列3次
flight->runAction(CCRepeat::actionWithAction(sequence, ));
}

反动作 - Reverse
反动作就是反向(逆向)执行某个动作,支持针对动作序列的反动作序列。反动作不是一个专门的类,而是CCFiniteTimeAction引入的一个接口。不是所有的类都支持反动作,CCXxxxTo类通常不支持反动作,而CCXxxxBy类通常支持,示例如下:

void CompositionActionLayer::onReverse(CCObject* pSender)
{
CCSize s = CCDirector::sharedDirector()->getWinSize();
flight->setRotation(0.0f);
flight->setPosition(ccp(s.width / , )); CCFiniteTimeAction *action1 = CCMoveBy::actionWithDuration(2.0f, ccp(, ));
// 创建某个动作的反动作
CCFiniteTimeAction *action2 = action1->reverse(); flight->runAction(CCRepeat::actionWithAction(CCSequence::actions(action1, action2, NULL), ));
}

动画 - CCAnimate
动画就是让精灵自身连续执行一段影像,形成模拟运动的效果:行走时的状态,打斗时的状态等。

void CompositionActionLayer::onAnimation(CCObject* pSender)
{
CCSpriteBatchNode *mgr = static_cast<CCSpriteBatchNode *>(this->getChildByTag()); CCAnimation *animation = CCAnimation::animation();
animation->setName("flight");
animation->setDelay(0.2f);
for (int i = ; i < ; ++i)
{
// 定义每一帧的内容
float x = static_cast<float>(i % );
animation->addFrameWithTexture(mgr->getTexture(), CCRectMake(x * , , , ));
}
// 创建并执行动画效果,而且要重复10次。
CCAnimate *action = CCAnimate::actionWithAnimation(animation);
flight->runAction(CCRepeat::actionWithAction(action, ));
}

无限重复 - CCRepeatForever
在CCRepeatForever Class Reference中, 有这样一条警告“Warning: This action can't be Sequenceable because it is not an IntervalAction”,而实际上它的确是派生自CCActionInterval,这真有点儿把我也搞懵了。
仅从其本意来说,该类的作用就是无限期执行某个动作或动作序列,直到被停止。因此无法参与序列和同步,自身也无法反向执行(但是你可以将某一动作反向,然后无限重复执行)。

void CompositionActionLayer::onRepeatForever(CCObject* pSender)
{
CCSpriteBatchNode *mgr = static_cast<CCSpriteBatchNode *>(this->getChildByTag());
// 飞行喷火模拟动画
CCAnimation *animation = CCAnimation::animation();
animation->setName("flight");
animation->setDelay(0.1f);
for (int i = ; i < ; ++i)
{
float x = static_cast<float>(i % );
animation->addFrameWithTexture(mgr->getTexture(), CCRectMake(x * , , , ));
}
CCAnimate *action = CCAnimate::actionWithAnimation(animation);
// 将该动画作为精灵的本征动画,一直运行。
flight->runAction(CCRepeatForever::actionWithAction(action)); CCSize s = CCDirector::sharedDirector()->getWinSize();
flight->setRotation(0.0f);
flight->setPosition(ccp(, )); // 创建第二个连续无限期动作序列,叠加两者形成完整效果。
ccBezierConfig bezier;
bezier.controlPoint_1 = ccp(, s.height / );
bezier.controlPoint_2 = ccp(, -s.height / );
bezier.endPosition = ccp(, );
CCFiniteTimeAction *action1 = CCBezierBy::actionWithDuration(3.0f, bezier);
CCFiniteTimeAction *action2 = CCTintBy::actionWithDuration(0.5f, , , );
CCFiniteTimeAction *action3 = CCSpawn::actions(action1, CCRepeat::actionWithAction(action2, ), NULL);
CCFiniteTimeAction *action4 = CCSpawn::actions(action1->reverse(), CCRepeat::actionWithAction(action2, ), NULL);
// CCSequence的actions成员函数返回的是CCFiniteTimeAction指针类型,
// 而CCRepeatForever的actionWithAction接受的是CCActionInterval指针类型,
// 所以这里需要强转一下,转成CCSequence指针类型,
// 只要保证序列中有2个或2个以上的动作,这么做是绝对没有问题的。
flight->runAction(CCRepeatForever::actionWithAction(static_cast<CCSequence *>(CCSequence::actions(action3, action4, NULL))));
}

速度变化
基本动作和组合动作实现了针对精灵的各种运动和动画效果,但它们的速度通常是恒定不变的。通过CCActionEase类系和CCSpeed类,我们可以很方便地改变精灵执行动作的速度,是由快至慢还是由慢至快。

CCEaseIn - 由慢至快(速度线性变化)
CCEaseOut - 由快至慢
CCEaseInOut - 由慢至快再由快至慢
CCEaseSineIn - 由慢至快(速度正弦变化)
CCEaseSineOut - 由快至慢
CCEaseSineInOut - 由慢至快再由快至慢
CCEaseExponentialIn - 由慢至极快(速度指数级变化)
CCEaseExponentialOut - 由极快至慢
CCEaseExponentialInOut - 由慢至极快再由极快至慢
CCSpeed - 人工设定速度,还可通过setSpeed不断调整。
扩展动作
我们已经掌握了各种各样的动作,也可以按照不同的速度要求修改动作执行的时间,cocos2d-x还提供了针对现有动作的扩展,以实现各种灵活的效果。

延时 - CCDelayTime
通过CCDelayTime,我们可以在动作序列中增加一个时间间歇。

void ExtendActionLayer::onDelay(CCObject* pSender)
{
CCFiniteTimeAction *action1 = CCMoveBy::actionWithDuration(1.2f, ccp(, ));
CCFiniteTimeAction *action2 = action1->reverse();
// 实现一个等待间歇
flight->runAction(CCSequence::actions(action1, CCDelayTime::actionWithDuration(1.0f), action2, NULL));
}

函数调用
在动作序列中间或者末尾调用某个函数,执行任何任务:动作、状态修改等。在cocos2d-x中,调用函数的动作一共有4种。
1.CCCallFunc
仅函数调用,无任何参数。

void ExtendActionLayer::onCallBack1()
{
flight->runAction(CCTintBy::actionWithDuration(0.5f, , , ));
} void ExtendActionLayer::onCallFunc(CCObject* pSender)
{
CCFiniteTimeAction *action1 = CCMoveBy::actionWithDuration(2.0f, ccp(, ));
CCFiniteTimeAction *action2 = action1->reverse();
CCFiniteTimeAction *actionF = CCCallFunc::actionWithTarget(this, callfunc_selector(ExtendActionLayer::onCallBack1));
flight->runAction(CCSequence::actions(action1, actionF, action2, NULL));
}

2.CCCallFuncN
调用函数,并将当前对象的指针(CCNode指针)作为第一个参数传递进去。

void ExtendActionLayer::onCallBack2(CCNode* pSender)
{
// 在这个例子里,pSender就是flight,因为是他执行了那个actionF
pSender->runAction(CCTintBy::actionWithDuration(1.0f, , , ));
} void ExtendActionLayer::onCallFuncN(CCObject* pSender)
{
CCFiniteTimeAction *action1 = CCMoveBy::actionWithDuration(2.0f, ccp(, ));
CCFiniteTimeAction *action2 = action1->reverse();
CCFiniteTimeAction *actionF = CCCallFuncN::actionWithTarget(this, callfuncN_selector(ExtendActionLayer::onCallBack2));
flight->runAction(CCSequence::actions(action1, actionF, action2, NULL));
}

3.CCCallFuncND
在前一种方式的基础上增加一个数据参数,这是void指针类型。

void ExtendActionLayer::onCallBack3(CCNode* pSender, void* pData)
{
pSender->runAction(CCTintBy::actionWithDuration(static_cast<float>((int)pData), , , ));
} void ExtendActionLayer::onCallFuncND(CCObject* pSender)
{
CCFiniteTimeAction *action1 = CCMoveBy::actionWithDuration(2.0f, ccp(, ));
CCFiniteTimeAction *action2 = action1->reverse();
// 这里直接将整数常量强转成(void *)类型似乎有欠妥当,但对这些Action的生命周期不太清楚,稍后深入一下。
CCFiniteTimeAction *actionF = CCCallFuncND::actionWithTarget(this, callfuncND_selector(ExtendActionLayer::onCallBack3), (void *));
flight->runAction(CCSequence::actions(action1, actionF, action2, NULL));
}

4.CCCallFuncO
调用函数,并传递一个CCObject指针作为参数。这个似乎不太常用,资料比较少,以后再深入。
小结
至此,我们对cocos2d-x支持的动作有了整体了解。动作是我们的好帮手,它让游戏世界充满生机。在后面的章节中,我们会对部分动作以及动作系统继续深入。
cocos2d动作讲解的更多相关文章
- cocos2d动作
1.动作的基类是CCAction,通过继承它可以实现很多不同的动作,主要分为三大类: (1)CCFiniteTimeAction(有限次动作执行类) (2)CCSpeed(节点执行速度类) (3)CC ...
- Cocos2d-x视频教程
目录 1. 我的技术专栏 2. 相关推荐 3. 下载链接 4. cocos2d-xx Lua+JS+C++教学视频 5. 杨丰盛Cocos2D-X游戏课程 6. [Cocos2d-x]塔防游戏开发实战 ...
- Cocos2d-x 3.x游戏开发之旅
Cocos2d-x 3.x游戏开发之旅 钟迪龙 著 ISBN 978-7-121-24276-2 2014年10月出版 定价:79.00元 516页 16开 内容提要 <Cocos2d-x ...
- cocos2D v3.x中动作回调函数的变化
cocos2D v3.x版本中的动作的回调函数不能再带任何参数并且不能返回任何值. 官方给出的传递参数的办法是: 选择器(selector)不能带有任何形参,选择器需要的参数必须通过ivar或prop ...
- [一位菜鸟的COCOS-2D编程之路]COCOS2D中得动作,特效和动画
一,CCActionManager 管理所有节点动作的对象 来看看打飞机里面的一个onEnter 方法 - (void)onEnter { [super onEnter]; //一定要注意添加此方法, ...
- 【Cocos2d-X开发学习笔记】第12期:动作类CCAction的详细讲解
一般对于游戏中的精灵而言,它们不仅仅是存在于场景中,而且是动态展现的,例如,精灵移动的动态效果.动 画效果.跳动效果.闪烁和旋转动态效果等.每一种效果都可以看成是精灵的一个动作. 一.动作类(CCAc ...
- cocos2d中box2d讲解一
在游戏中我们经常要加入物理碰撞等和物理有关的内容,在游戏中加入物理引擎可以使我们的游戏更加真实,为玩家展示一个更真实的世界,cocos2d-x支持两个物理引擎Box2d和Chipmunk,本文介绍bo ...
- 小尝试一下 cocos2d
好奇 cocos2d 到底是怎样一个框架,正好有个项目需要一个游戏框架,所以稍微了解了一下.小结一下了解到的情况. 基本概念 首先呢,因为 cocos2d 是基于 pyglet 做的,你完全可以直接用 ...
- 实例讲解 SQL 注入攻击
这是一篇讲解SQL注入的实例文章,一步一步跟着作者脚步探索如何注入成功,展现了一次完整的渗透流程,值得一读.翻译水平有限,见谅! 一位客户让我们针对只有他们企业员工和顾客能使用的企业内网进行渗透测试. ...
随机推荐
- Android真机连接手机Target显示unknown cmd命令下adb devices 显示offline
主要原因是adb版本的问题: 1.找到adb.exe路径 比如:G:\BaiduYunDownload\Android\android-sdk\platform-tools,将该路径放到环境便利-- ...
- 从内存溢出看Java 环境中的内存结构(转)
作为有个java程序员,我想大家对下面出现的这几个场景并不陌生,倍感亲切,深恶痛绝,抓心挠肝,一定会回过头来问为什么为什么为什么会这样,嘿嘿,让我们看一下我们日常在开发过程中接触内存溢出的异常: Ex ...
- alt+shift+j,添加日期、作者等
在preference->Java->codestyle->codetemplates->commnets->type 可以编辑如: /** * @author ${us ...
- JavaBean--删除操作
删除命令:removeAttribute(Javabean名称) 前面调用用pageContext,request,session,application, 如request.removeAttrib ...
- win7 系统保留分区 BCDedit
系统保留分区简介编辑 “系统保留”分区示意图 Windows Vista/7出于安全考虑,在新装Windows Vista/7系统过程中,如果利用光盘的分区工具给硬盘分区时,系统默认的将一部分(100 ...
- Android .mk文件语法解析
下面是MTK-AndroidFM模块Android .mk代码内容: ifeq ($(MTK_FM_SUPPORT),yes) LOCAL_PATH:= $(call my-dir) include ...
- 生日蛋糕(DFS)
题意: Description 7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体. 设从下往上数第i(1 <= i <= M)层蛋糕 ...
- 转:C#生成唯一值的方法汇总
这篇文章主要介绍了C#生成唯一值的方法汇总,有需要的朋友可以参考一下 生成唯一值的方法很多,下面就不同环境下生成的唯一标识方法一一介绍,作为工作中的一次总结,有兴趣的可以自行测试: 一.在 .NET ...
- 笔记整理--HTTP Header 详解
HTTP Header 详解 2013/09/21 | 分类: IT技术 | 0 条评论 | 标签: HTTP 分享到:36 原文出处: zcmhi HTTP(HyperTextTransferPro ...
- Swift中的异常处理
swift中的异常处理 如果在调用系统某一个方法时,该方法最后有一个throws.说明该方法会抛出异常.如果一个方法会抛出异常,那么需要对该异常进行处理 *在swift中提供三种处理异常的方式 方式一 ...