热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

知易游戏开发教程cocos2dx移植版003

原文地址: http://www.cnblogs.com/cocos2d-x/archive/2012/03/04/2379562.html 从本章开始,我们开始讲解

原文地址: http://www.cnblogs.com/cocos2d-x/archive/2012/03/04/2379562.html


从本章开始,我们开始讲解cocos2d-x库的动作(Action)。游戏的世界是一个动态的世界:无论是主角精灵还是NPC精灵都处于不断的运动当中,甚至是背景中漂流的树叶,随风而动的小草。这些明显的或者不明显的运动构成了我们栩栩如生的游戏世界。

仔细研究游戏中精灵的运动,我们发现:所有这样的运动都可以细分为若干个基本动作和基本动作的组合。通过进一步扩展,我们可以将同一精灵的更多动作和不同精灵之间的不同动作连贯起来,形成关于整个运动世界的连续模拟。

我们给出示例ZYG003,展示cocos2d-x支持的主要动作:

基本动作

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

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


此接口确保所有的精灵都可以执行各种动作。也正是为了服从这个接口的定义,导致后续各种组合动作也都从CCAction派生。

下面的代码是通常调用某个动作的方法:

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



瞬时动作

顾名思义,瞬时动作就是不需要时间,马上就完成的动作。瞬时动作的共同基类是CCActionInstant。

cocos2d-x提供以下瞬时动作:

瞬时动作大都有与之对应的属性设置方法,之所以作为一个动作来实现,是为了可以与其他动作形成一个连续动作。下面来看一下瞬时动作的使用。

放置 - CCPlace

效果类似于setPosition(ccp(x, y))。示例代码如下:

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


隐藏 - CCHide
效果类似于setIsVisible(false)。示例代码如下:

1 void InstantActionLayer::onHide(CCObject* pSender)
2 {
3 flight->runAction(CCHide::action());
4 }

显示 - CCShow
效果类似于setIsVisible(true)。示例代码如下:

1 void InstantActionLayer::onShow(CCObject* pSender)
2 {
3 flight->runAction(CCShow::action());
4 }

可见切换 - CCToggleVisibility
效果类似于setIsVisible(!getIsVisible())。示例代码如下:

1 void InstantActionLayer::onToggle(CCObject* pSender)
2 {
3 flight->runAction(CCToggleVisibility::action());
4 }

水平翻转 - CCFlipX
效果类似于setFlipX(true/false)。示例代码如下:

1 void InstantActionLayer::onFlipX(CCObject* pSender)
2 {
3 flight->runAction(CCFlipX::actionWithFlipX(true));
4 }

垂直翻转 - onFlipY
效果类似于setFlipY(true/false)。示例代码如下:

1 void InstantActionLayer::onFlipY(CCObject* pSender)
2 {
3 flight->runAction(CCFlipY::actionWithFlipY(true));
4 }

还有两个较为特殊的动作(网格重用 - 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对象执行。该类的作用就是线性排列若干个动作,然后按先后次序逐个执行。

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



同步 - CCSpawn

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

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



重复有限次数 - CCRepeat

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

1 void CompositionActionLayer::onRepeat(CCObject* pSender)
2 {
3 CCSize s = CCDirector::sharedDirector()->getWinSize();
4 flight->setRotation(0.0f);
5 flight->setPosition(ccp(s.width / 2, 50));
6 // 创建动作序列
7 CCFiniteTimeAction *action1 = CCMoveTo::actionWithDuration(2.0f, ccp(s.width - 50.0f, s.height - 50.0f));
8 CCFiniteTimeAction *action2 = CCJumpBy::actionWithDuration(2.0f, ccp(-400, -200), 30.0f, 5);
9 CCFiniteTimeAction *action3 = CCJumpBy::actionWithDuration(2.0f, ccp(s.width / 2, 0), 20.0f, 3);
10 CCFiniteTimeAction *sequence = CCSequence::actions(action1, action2, action3, NULL);
11 // 重复运行上述动作序列3次
12 flight->runAction(CCRepeat::actionWithAction(sequence, 3));
13 }



反动作 - Reverse

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

1 void CompositionActionLayer::onReverse(CCObject* pSender)
2 {
3 CCSize s = CCDirector::sharedDirector()->getWinSize();
4 flight->setRotation(0.0f);
5 flight->setPosition(ccp(s.width / 2, 50));
6
7 CCFiniteTimeAction *action1 = CCMoveBy::actionWithDuration(2.0f, ccp(190, 220));
8 // 创建某个动作的反动作
9 CCFiniteTimeAction *action2 = action1->reverse();
10
11 flight->runAction(CCRepeat::actionWithAction(CCSequence::actions(action1, action2, NULL), 2));
12 }



动画 - CCAnimate

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

1 void CompositionActionLayer::onAnimation(CCObject* pSender)
2 {
3 CCSpriteBatchNode *mgr = static_cast(this->getChildByTag(4));
4
5 CCAnimation *animation = CCAnimation::animation();
6 animation->setName("flight");
7 animation->setDelay(0.2f);
8 for (int i &#61; 0; i <3; &#43;&#43;i)
9 {
10 // 定义每一帧的内容
11 float x &#61; static_cast<float>(i % 3);
12 animation->addFrameWithTexture(mgr->getTexture(), CCRectMake(x * 32, 0, 31, 30));
13 }
14 // 创建并执行动画效果&#xff0c;而且要重复10次。
15 CCAnimate *action &#61; CCAnimate::actionWithAnimation(animation);
16 flight->runAction(CCRepeat::actionWithAction(action, 10));
17 }



无限重复 - CCRepeatForever

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

1 void CompositionActionLayer::onRepeatForever(CCObject* pSender)
2 {
3 CCSpriteBatchNode *mgr &#61; static_cast(this->getChildByTag(4));
4 // 飞行喷火模拟动画
5 CCAnimation *animation &#61; CCAnimation::animation();
6 animation->setName("flight");
7 animation->setDelay(0.1f);
8 for (int i &#61; 0; i <3; &#43;&#43;i)
9 {
10 float x &#61; static_cast<float>(i % 3);
11 animation->addFrameWithTexture(mgr->getTexture(), CCRectMake(x * 32, 0, 31, 30));
12 }
13 CCAnimate *action &#61; CCAnimate::actionWithAnimation(animation);
14 // 将该动画作为精灵的本征动画&#xff0c;一直运行。
15 flight->runAction(CCRepeatForever::actionWithAction(action));
16
17 CCSize s &#61; CCDirector::sharedDirector()->getWinSize();
18 flight->setRotation(0.0f);
19 flight->setPosition(ccp(100, 50));
20
21 // 创建第二个连续无限期动作序列&#xff0c;叠加两者形成完整效果。
22 ccBezierConfig bezier;
23 bezier.controlPoint_1 &#61; ccp(0, s.height / 2);
24 bezier.controlPoint_2 &#61; ccp(300, -s.height / 2);
25 bezier.endPosition &#61; ccp(300, 100);
26 CCFiniteTimeAction *action1 &#61; CCBezierBy::actionWithDuration(3.0f, bezier);
27 CCFiniteTimeAction *action2 &#61; CCTintBy::actionWithDuration(0.5f, 0, 255, 255);
28 CCFiniteTimeAction *action3 &#61; CCSpawn::actions(action1, CCRepeat::actionWithAction(action2, 4), NULL);
29 CCFiniteTimeAction *action4 &#61; CCSpawn::actions(action1->reverse(), CCRepeat::actionWithAction(action2, 4), NULL);
30 // CCSequence的actions成员函数返回的是CCFiniteTimeAction指针类型&#xff0c;
31 // 而CCRepeatForever的actionWithAction接受的是CCActionInterval指针类型&#xff0c;
32 // 所以这里需要强转一下&#xff0c;转成CCSequence指针类型&#xff0c;
33 // 只要保证序列中有2个或2个以上的动作&#xff0c;这么做是绝对没有问题的。
34 flight->runAction(CCRepeatForever::actionWithAction(static_cast(CCSequence::actions(action3, action4, NULL))));
35 }



速度变化

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

CCEaseIn - 由慢至快&#xff08;速度线性变化&#xff09;
CCEaseOut - 由快至慢
CCEaseInOut - 由慢至快再由快至慢
CCEaseSineIn - 由慢至快&#xff08;速度正弦变化&#xff09;
CCEaseSineOut - 由快至慢
CCEaseSineInOut - 由慢至快再由快至慢
CCEaseExponentialIn - 由慢至极快&#xff08;速度指数级变化&#xff09;
CCEaseExponentialOut - 由极快至慢
CCEaseExponentialInOut - 由慢至极快再由极快至慢
CCSpeed - 人工设定速度&#xff0c;还可通过setSpeed不断调整。

扩展动作

我们已经掌握了各种各样的动作&#xff0c;也可以按照不同的速度要求修改动作执行的时间&#xff0c;cocos2d-x还提供了针对现有动作的扩展&#xff0c;以实现各种灵活的效果。

延时 - CCDelayTime

通过CCDelayTime&#xff0c;我们可以在动作序列中增加一个时间间歇。

1 void ExtendActionLayer::onDelay(CCObject* pSender)
2 {
3 CCFiniteTimeAction *action1 &#61; CCMoveBy::actionWithDuration(1.2f, ccp(200, 200));
4 CCFiniteTimeAction *action2 &#61; action1->reverse();
5 // 实现一个等待间歇
6 flight->runAction(CCSequence::actions(action1, CCDelayTime::actionWithDuration(1.0f), action2, NULL));
7 }



函数调用

在动作序列中间或者末尾调用某个函数&#xff0c;执行任何任务&#xff1a;动作、状态修改等。在cocos2d-x中&#xff0c;调用函数的动作一共有4种。

1.CCCallFunc

仅函数调用&#xff0c;无任何参数。

1 void ExtendActionLayer::onCallBack1()
2 {
3 flight->runAction(CCTintBy::actionWithDuration(0.5f, 255, 0, 255));
4 }
5
6 void ExtendActionLayer::onCallFunc(CCObject* pSender)
7 {
8 CCFiniteTimeAction *action1 &#61; CCMoveBy::actionWithDuration(2.0f, ccp(200, 200));
9 CCFiniteTimeAction *action2 &#61; action1->reverse();
10 CCFiniteTimeAction *actionF &#61; CCCallFunc::actionWithTarget(this, callfunc_selector(ExtendActionLayer::onCallBack1));
11 flight->runAction(CCSequence::actions(action1, actionF, action2, NULL));
12 }



2.CCCallFuncN

调用函数&#xff0c;并将当前对象的指针&#xff08;CCNode指针&#xff09;作为第一个参数传递进去。

1 void ExtendActionLayer::onCallBack2(CCNode* pSender)
2 {
3 // 在这个例子里&#xff0c;pSender就是flight&#xff0c;因为是他执行了那个actionF
4 pSender->runAction(CCTintBy::actionWithDuration(1.0f, 255, 0, 255));
5 }
6
7 void ExtendActionLayer::onCallFuncN(CCObject* pSender)
8 {
9 CCFiniteTimeAction *action1 &#61; CCMoveBy::actionWithDuration(2.0f, ccp(200, 200));
10 CCFiniteTimeAction *action2 &#61; action1->reverse();
11 CCFiniteTimeAction *actionF &#61; CCCallFuncN::actionWithTarget(this, callfuncN_selector(ExtendActionLayer::onCallBack2));
12 flight->runAction(CCSequence::actions(action1, actionF, action2, NULL));
13 }



3.CCCallFuncND

在前一种方式的基础上增加一个数据参数&#xff0c;这是void指针类型。

1 void ExtendActionLayer::onCallBack3(CCNode* pSender, void* pData)
2 {
3 pSender->runAction(CCTintBy::actionWithDuration(static_cast<float>((int)pData), 255, 0, 255));
4 }
5
6 void ExtendActionLayer::onCallFuncND(CCObject* pSender)
7 {
8 CCFiniteTimeAction *action1 &#61; CCMoveBy::actionWithDuration(2.0f, ccp(200, 200));
9 CCFiniteTimeAction *action2 &#61; action1->reverse();
10 // 这里直接将整数常量强转成(void *)类型似乎有欠妥当&#xff0c;但对这些Action的生命周期不太清楚&#xff0c;稍后深入一下。
11 CCFiniteTimeAction *actionF &#61; CCCallFuncND::actionWithTarget(this, callfuncND_selector(ExtendActionLayer::onCallBack3), (void *)2);
12 flight->runAction(CCSequence::actions(action1, actionF, action2, NULL));
13 }



4.CCCallFuncO

调用函数&#xff0c;并传递一个CCObject指针作为参数。这个似乎不太常用&#xff0c;资料比较少&#xff0c;以后再深入。

小结

至此&#xff0c;我们对cocos2d-x支持的动作有了整体了解。动作是我们的好帮手&#xff0c;它让游戏世界充满生机。在后面的章节中&#xff0c;我们会对部分动作以及动作系统继续深入。

示例代码下载&#xff1a;
http://files.cnblogs.com/cocos2d-x/ZYG003.rar


推荐阅读
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • 本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • 本文探讨了C语言中指针的应用与价值,指针在C语言中具有灵活性和可变性,通过指针可以操作系统内存和控制外部I/O端口。文章介绍了指针变量和指针的指向变量的含义和用法,以及判断变量数据类型和指向变量或成员变量的类型的方法。还讨论了指针访问数组元素和下标法数组元素的等价关系,以及指针作为函数参数可以改变主调函数变量的值的特点。此外,文章还提到了指针在动态存储分配、链表创建和相关操作中的应用,以及类成员指针与外部变量的区分方法。通过本文的阐述,读者可以更好地理解和应用C语言中的指针。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • 从零学Java(10)之方法详解,喷打野你真的没我6!
    本文介绍了从零学Java系列中的第10篇文章,详解了Java中的方法。同时讨论了打野过程中喷打野的影响,以及金色打野刀对经济的增加和线上队友经济的影响。指出喷打野会导致线上经济的消减和影响队伍的团结。 ... [详细]
  • 带添加按钮的GridView,item的删除事件
    先上图片效果;gridView无数据时显示添加按钮,有数据时,第一格显示添加按钮,后面显示数据:布局文件:addr_manage.xml<?xmlve ... [详细]
  • 阅读spring5源码DefaultSingletonBeanRegistry类遇到问题发现SpringBean中存在大量回调机制和aware接口,于是特意去了解 ... [详细]
  • 工作经验谈之-让百度地图API调用数据库内容 及详解
    这段时间,所在项目中要用到的一个模块,就是让数据库中的内容在百度地图上展现出来,如经纬度。主要实现以下几点功能:1.读取数据库中的经纬度值在百度上标注出来。2.点击标注弹出对应信息。3 ... [详细]
author-avatar
波罗蜜
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有