转载自ufolr的博客 原文连接:http://blog.csdn.net/ufolr/article/details/7624851

最近项目中需要一个落叶的效果,本来想用粒子特效来实现,但是几经调试,虽然调出了落叶的效果,但是并不是十分理想,最大的不足就是落叶是平面的,没有立体感,虽然把落叶做小之后却是立体感的感觉会有所缓解,但总不能把树叶无限的缩小吧,而且立体感的缺失在粒子特效中确实是一个始终存在的问题。作为一个最求品质的程序猿,最终还是决定自己设精灵动作来实现。

   在分析了粒子特效实现的原理并在国内外论坛上爬了半天,最后边实验边修改,终于完成了一个可行的仿真感较强的立体的落叶效果,现在就拿出来跟大家分享一下。

原理->树叶飘落动作分析:

树叶下落过程分解为:下落+摆动+叶片自传。

也就是只要将这三个动作实现,并同时执行就可以实现树叶飘落的效果。

下面就拿出代码具体解析实现过程:

老规矩,先上.h的内容,.h就不多解释了:

#ifndef __LEAF_H__
#define __LEAF_H__ #include "cocos2d.h"
USING_NS_CC; class Leaf : public cocos2d::CCLayer
{
public:
virtual bool init(); void resetLeafPos(CCNode* sender);//叶片位置重置函数
void playLeafAnim(CCSprite *spriteLeaf);//下落过程实现函数 LAYER_NODE_FUNC(Leaf);
}; #endif // __LEAF_H__

接下来是具体的实现,为了我们能不断的产生自然、随和的落叶,我们分三步来完成:

1:第一次初始化;2:落叶动作的实现;3:下落动作完成重新设定落叶开始。

上代码,先看看用到的头文件:

#include <iostream>
#include <ctime>
#include <cstdlib> #include"Leaf.h" using namespace std; enum {TAG_LEAF1 = 101, TAG_LEAF2};

初始化树叶精灵的设定:

<span style="font-size: 12px;">bool Leaf::init()
{
CCSprite *spriteLeaf1 = CCSprite::spriteWithFile("img_yezi_1.png");
spriteLeaf1->setRotation(30);//旋转角度
spriteLeaf1->setAnchorPoint(ccp(0.5, 3));//设置精灵锚点
spriteLeaf1->setPosition(ccp(450, 500));//叶子1第一次初始位置
spriteLeaf1->setScale(0.5);//设置叶片大小 this->addChild(spriteLeaf1,100,TAG_LEAF1);
this->playLeafAnim(spriteLeaf1);//调用play函数播实现叶动作 CCSprite *spriteLeaf2 = CCSprite::spriteWithFile("img_yezi_2.png");
spriteLeaf2->setRotation(50);
spriteLeaf2->setAnchorPoint(ccp(0.5, 3));
spriteLeaf2->setPosition(ccp(200, 540));
spriteLeaf2->setScale(0.5); this->addChild(spriteLeaf2,101,TAG_LEAF2);
this->playLeafAnim(spriteLeaf2); return true;
}</span>

将精灵的锚点设定在其高度的3倍的位置,加上旋转动作后,叶片会产生单摆的动作效果。再加上下落的动作,就会有树叶飘落的感觉了。

<span style="font-size: 12px;">//叶子飘落动作
void Leaf::playLeafAnim(CCSprite *spriteLeaf)
{
int iTag = spriteLeaf->getTag(); CCLog("playtag%d", iTag);
ccTime time, roTime;
float fAngle1, fAngle2;
if (iTag == TAG_LEAF1)
{
CCLog("tag1");
time = 10;//叶子下落的时间
roTime = 2.5;//叶子单向摆动一次时间
fAngle1 = -80;//叶子逆时针摆动角度
fAngle2 = 80;//顺时针摆动角度
}
else
{
CCLog("tag2");
time = 14;
roTime = 3.2;
fAngle1 = -100;
fAngle2 = 100;
}
CCLog("rotime%ffAngle1%ffAngle2%f",roTime, fAngle1,fAngle1);
//随机生成叶子横向偏移值
srand((UINT)GetCurrentTime());
int iRandPos = rand() % 250;
CCLog("Pianyi%d", iRandPos);
//叶子所运动到的位置
CCMoveTo *moveTo = CCMoveTo::actionWithDuration(time, ccp(CCDirector::sharedDirector()->getWinSize().width - iRandPos, 30));
CCCallFuncN *actDone = CCCallFuncN::actionWithTarget(this, callfuncN_selector(Leaf::resetLeafPos));
CCFiniteTimeAction *putdown = CCSequence::actions(moveTo, actDone, NULL);
//叶子旋转动作
CCRotateBy *rotaBy1 = CCRotateBy::actionWithDuration(roTime, fAngle1);
CCRotateBy *rotaBy2 = CCRotateBy::actionWithDuration(roTime, fAngle2); //叶子翻转动作
spriteLeaf->setVertexZ(60);//设置深度抬高60,避免出现使用CCOrbitCamera实现空间翻转时产生错位和遮挡等问题
//CCDirector::sharedDirector()->setDepthTest(false);
//关闭深度测试同样可以避免上述问题,不过,推荐使用深度设置setVertexZ来正确解决,因为有时你可能需要遮挡的效果,关闭深度测试后将造成遮挡效果的缺失
CCOrbitCamera * orbit = CCOrbitCamera::actionWithDuration(8, 1, 0, 0, 360, 45, 0);
//让树叶精灵始终执行三维翻转的动作
CCRepeat *fz3d = CCRepeat::actionWithAction(orbit, -1);//无限循环执行叶片翻转的动作
//CCRepeatForever *fz3d = CCRepeatForever::actionWithAction(orbit);
//由于下面使用CCSpawn同时执行动作,所以不可以使用无限次数类型的动作,而因使用有线次数循环CCRepeat将循环次数设置为-1 //用CCEaseInOut包装落叶摆动的动作,让树叶的进入、出现更自然(淡入淡出效果)
CCEaseInOut *ease1 = CCEaseInOut::actionWithAction(rotaBy1, 3);
CCEaseInOut *ease2 = CCEaseInOut::actionWithAction(rotaBy2, 3);
//摆动动作合成
CCFiniteTimeAction *seq2 = CCSequence::actions(ease1, ease2, NULL);//依次执行顺时针、逆时针摆动
CCRepeat *baidong = CCRepeat::actionWithAction(seq2, -1);//摆动合成 //动作执行->同时执行所有动作
spriteLeaf->runAction(CCSpawn::actions(putdown, baidong, fz3d, NULL)); }</span>

现在叶子飘落的主干就设定完毕了,其实看上去并不复杂,就是三个动作:下落+摆动+翻转,未来使落叶更自然,我们尽可能的在数据可变的范围内使用随机参数,我这里用了系统时间做种子来产生随机数,但是我感觉产生的随机数还是不够理想,如果你有更好的种子,可以告诉我。其实还有很多参数可以在限定范围内使用随机数,由于时间关系我没有逐个去调试,而是直接设定了一个固定值。有时间你可以逐个设定实验,找到最佳的数据范围。

现在为了使我们的落叶能够源源不断的产生,我们还需要让落叶的产生和消亡循环起来:

<span style="font-size: 12px;">//重置叶子的位置
void Leaf::resetLeafPos(CCNode* sender)
{
int iTag = int(sender->getTag());//获得被重置叶片的标签
int iZoder = int(sender->getZOrder());//获取被重置叶片的z轴值
sender->removeFromParentAndCleanup(true);//清除已经落到底点的叶子 char sImg[15] = "img_yezi_1.png";
_snprintf(sImg, sizeof(sImg), "img_yezi_%d.png", iTag % 100); CCPoint pos;
float fAngle;
//随机生成叶子的起始位置
srand((UINT)GetCurrentTime());
int iRand = (rand() % 200);
if (iTag == TAG_LEAF1)
{
pos = ccp(iRand, 600);
fAngle = 30;
}
else
{
pos = ccp(iRand, 570);
fAngle = 50;
}
//重新生成新的叶片,在起点处释放
CCSprite *spriteLeaf = CCSprite::spriteWithFile(sImg);
spriteLeaf->setScale(0.5);
spriteLeaf->setAnchorPoint(ccp(0.5, 3));
spriteLeaf->setRotation(fAngle);
spriteLeaf->setPosition(pos); this->addChild(spriteLeaf, iZoder,iTag);
this->playLeafAnim(spriteLeaf);//重置后的树叶再次执行飘落动作
}</span>

这样3d仿真的落叶的效果就基本实现了,为了节约时间,这里只写了2片叶子的情况,多片叶子的情况可以举一反三,多加几片叶子就行。这里需要注意的是在使用CCOrbitCamera来实现三维空间的翻转时,由于openGL绘图的关系,我们得将精灵的深度设置上浮,以避免openGL绘图时精灵的部分被后面的色彩遮挡。

解决遮挡问题可以直接关闭深度测试CCDirector::sharedDirector()->setDepthTest(false);

也可以设置精灵VertexZ上浮spriteLeaf->setVertexZ(60);

如果你的程序不需要深度测试,你大可以直接关了它,但是你不能确定是的程序是否每个地方都没有用到深度测试,所以,推荐设置VertexZ值来避免你的精灵被遮挡。VertexZ值的大小为你的精灵被挡住部分的像素值。

<转>cocos2d-x学习笔记(五)仿真树叶飘落效果的实现(精灵旋转、翻转、钟摆运动等综合运用)的更多相关文章

  1. cocos2d-x 仿真树叶飘落效果的实现

    转自:http://blog.csdn.net/ufolr/article/details/7624851 最近项目中需要一个落叶的效果,本来想用粒子特效来实现,但是几经调试,虽然调出了落叶的效果,但 ...

  2. C#可扩展编程之MEF学习笔记(五):MEF高级进阶

    好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...

  3. (转)Qt Model/View 学习笔记 (五)——View 类

    Qt Model/View 学习笔记 (五) View 类 概念 在model/view架构中,view从model中获得数据项然后显示给用户.数据显示的方式不必与model提供的表示方式相同,可以与 ...

  4. java之jvm学习笔记五(实践写自己的类装载器)

    java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类 ...

  5. Learning ROS for Robotics Programming Second Edition学习笔记(五) indigo computer vision

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

  6. Typescript 学习笔记五:类

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

  7. ES6学习笔记<五> Module的操作——import、export、as

    import export 这两个家伙对应的就是es6自己的 module功能. 我们之前写的Javascript一直都没有模块化的体系,无法将一个庞大的js工程拆分成一个个功能相对独立但相互依赖的小 ...

  8. muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor

    目录 muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor Connector 系统函数connect 处理非阻塞connect的步骤: Connetor时序图 Accep ...

  9. python3.4学习笔记(五) IDLE显示行号问题,插件安装和其他开发工具介绍

    python3.4学习笔记(五) IDLE显示行号问题,插件安装和其他开发工具介绍 IDLE默认不能显示行号,使用ALT+G 跳到对应行号,在右下角有显示光标所在行.列.pycharm免费社区版.Su ...

随机推荐

  1. codevs 2216 行星序列 线段树+延迟标记(BZOJ 1798)

    2216 行星序列  时间限制: 2 s  空间限制: 256000 KB     题目描述 Description “神州“载人飞船的发射成功让小可可非常激动,他立志长大后要成为一名宇航员假期一始, ...

  2. Android-----------广告图片轮播控件

    Banner广告图片轮播控件,支持无限循环和多种主题,可以灵活设置轮播样式.动画.轮播和切换时间.位置.图片加载框架等! 很多Android APP中都有广告栏,我也用过很多次了,特来写一篇博文. 先 ...

  3. 10个有趣的Javascript和CSS库

    Tailwind CSS Tailwind是用于构建自定义用户界面的实用CSS框架. 每个Tailwind小应用都有多种尺寸,这使得创建响应式界面变得非常简单. 您可以自定义颜色,边框尺寸,字体,阴影 ...

  4. Android之扫描二维码和根据输入信息生成名片二维码

    开发中常常遇到二维码扫码操作,前段时间做项目要实现该功能,于是网上查找资料实现了,现在把他做出来给各位分享一下,主要包含了二维码扫描和生成二维码名片. 先来看看效果图:   生成的二维码,打开微信扫一 ...

  5. error processing package oracle-java8-installer问题解决

    ubuntu通过ppa源安装jdk时遇到如下问题: download failedOracle JDK 8 is NOT installed.dpkg: error processing packag ...

  6. UVA-536 Tree Recovery (二叉树遍历)

    题目大意:给出对一棵二叉树先序遍历和中序遍历的顺序,找出后序遍历的顺序. 题目分析:无非就是对字符串的输出顺序做个变化,递归就行了. 代码如下: # include<iostream> # ...

  7. 个人知识管理系统Version1.0开发记录(04)

    demo model 我们采用mvc软件架构模式,方便以后用Struts2框架技术优化.重构.封装.这次主要设计一些常用的方法工具,即数据访问逻辑.工具:eclipse.oracle.sqldevel ...

  8. JQuery鼠标移到小图显示大图效果的方法

    JQuery鼠标移到小图显示大图效果的方法 本文实例讲述了JQuery鼠标移到小图显示大图效果的方法.分享给大家供大家参考.具体分析如下: 这里的显示大图功能类似上一篇<JQuery实现超链接鼠 ...

  9. css之grid layout代码解释

    .wrapper { display: grid; grid-template-columns: repeat(3, 1fr);/*grid-template-columns CSS属性定义了网格列的 ...

  10. 如何优化tomcat配置优化

    tomcat默认参数是为开发环境制定,而非适合生产环境,尤其是内存和线程的配置,默认都很低,容易成为性能瓶颈. tomcat内存优化 linux修改TOMCAT_HOME/bin/catalina.s ...