Cocos2d-x的粒子系统是通过加载plist生成的。plist包含两部分内容:粒子系统属性和粒子纹理。然而每次调用create都会对plist进行读取解析,如果重复地使用同一个粒子效果,这样的调用明显是低效冗余的。所以我们要做的是,将粒子系统属性和粒子纹理分别抽出。
(1)将粒子系统属性预加载并全局保存,避免每次进行读取。
(2)粒子纹理可视且可以进行纹理打包,加载粒子纹理就和加载普通的图片一样。
本文通过增加ParticleSystemQuad的接口实现对粒子系统属性和纹理帧的直接载入,来提高粒子系统的加载效率和实现内存纹理的优化。

1.ParticleSystemQuad

首先先看下ParticleSystemQuad,ParticleSystemQuad继承于ParticleSystem,拥有后者的所有特性,并且增加了一些新的特性:
(1)粒子大小支持浮点数
(2)支持缩放
(3)支持选择
(4)支持subrect
(5)支持批渲染
ParticleSystemQuad同时也是其他特效的父类,创建一个粒子系统的函数调用顺序为:

[cpp] view plaincopy
  1. Create→initWithFile→initWithDictionary

在initWithDictionary中对粒子数据和纹理进行了读取和解析(这部分有兴趣的可以直接看源码)。

2.如何优化?

参考initWithDictionary的函参

[cpp] view plaincopy
  1. static bool initWithDictionary(ValueMap& dictionary, const std::string& dirname);

设计如下接口,当然你要传入文件名也可以:

[cpp] view plaincopy
  1. static ParticleSystemQuad * create(ValueMap& valueMap, SpriteFrame *frame);
  2. bool initWithValueMap(ValueMap &valueMap, SpriteFrame* frame);

源码如下:

[cpp] view plaincopy
  1. ParticleSystemQuad * ParticleSystemQuad::create( ValueMap& map, SpriteFrame *frame)
  2. {
  3. ParticleSystemQuad *ret = new ParticleSystemQuad();
  4. if (ret && ret->initWithValueMap(map, frame))
  5. {
  6. ret->autorelease();
  7. return ret;
  8. }
  9. CC_SAFE_DELETE(ret);
  10. return ret;
  11. }
[cpp] view plaincopy
  1. bool ParticleSystemQuad::initWithValueMap(ValueMap &valueMap, SpriteFrame* frame)
  2. {
  3. std::string dirname = "";
  4. bool ret = false;
  5. unsigned char *buffer = nullptr;
  6. unsigned char *deflated = nullptr;
  7. do
  8. {
  9. int maxParticles = valueMap["maxParticles"].asInt();
  10. // self, not super
  11. if(this->initWithTotalParticles(maxParticles))
  12. {
  13. // Emitter name in particle designer 2.0
  14. _configName = valueMap["configName"].asString();
  15. // angle
  16. _angle = valueMap["angle"].asFloat();
  17. _angleVar = valueMap["angleVariance"].asFloat();
  18. // duration
  19. _duration = valueMap["duration"].asFloat();
  20. // blend function
  21. if (_configName.length()>0)
  22. {
  23. _blendFunc.src = valueMap["blendFuncSource"].asFloat();
  24. }
  25. else
  26. {
  27. _blendFunc.src = valueMap["blendFuncSource"].asInt();
  28. }
  29. _blendFunc.dst = valueMap["blendFuncDestination"].asInt();
  30. // color
  31. _startColor.r = valueMap["startColorRed"].asFloat();
  32. _startColor.g = valueMap["startColorGreen"].asFloat();
  33. _startColor.b = valueMap["startColorBlue"].asFloat();
  34. _startColor.a = valueMap["startColorAlpha"].asFloat();
  35. _startColorVar.r = valueMap["startColorVarianceRed"].asFloat();
  36. _startColorVar.g = valueMap["startColorVarianceGreen"].asFloat();
  37. _startColorVar.b = valueMap["startColorVarianceBlue"].asFloat();
  38. _startColorVar.a = valueMap["startColorVarianceAlpha"].asFloat();
  39. _endColor.r = valueMap["finishColorRed"].asFloat();
  40. _endColor.g = valueMap["finishColorGreen"].asFloat();
  41. _endColor.b = valueMap["finishColorBlue"].asFloat();
  42. _endColor.a = valueMap["finishColorAlpha"].asFloat();
  43. _endColorVar.r = valueMap["finishColorVarianceRed"].asFloat();
  44. _endColorVar.g = valueMap["finishColorVarianceGreen"].asFloat();
  45. _endColorVar.b = valueMap["finishColorVarianceBlue"].asFloat();
  46. _endColorVar.a = valueMap["finishColorVarianceAlpha"].asFloat();
  47. // particle size
  48. _startSize = valueMap["startParticleSize"].asFloat();
  49. _startSizeVar = valueMap["startParticleSizeVariance"].asFloat();
  50. _endSize = valueMap["finishParticleSize"].asFloat();
  51. _endSizeVar = valueMap["finishParticleSizeVariance"].asFloat();
  52. // position
  53. float x = valueMap["sourcePositionx"].asFloat();
  54. float y = valueMap["sourcePositiony"].asFloat();
  55. this->setPosition( Point(x,y) );
  56. _posVar.x = valueMap["sourcePositionVariancex"].asFloat();
  57. _posVar.y = valueMap["sourcePositionVariancey"].asFloat();
  58. // Spinning
  59. _startSpin = valueMap["rotationStart"].asFloat();
  60. _startSpinVar = valueMap["rotationStartVariance"].asFloat();
  61. _endSpin= valueMap["rotationEnd"].asFloat();
  62. _endSpinVar= valueMap["rotationEndVariance"].asFloat();
  63. _emitterMode = (Mode) valueMap["emitterType"].asInt();
  64. // Mode A: Gravity + tangential accel + radial accel
  65. if (_emitterMode == Mode::GRAVITY)
  66. {
  67. // gravity
  68. modeA.gravity.x = valueMap["gravityx"].asFloat();
  69. modeA.gravity.y = valueMap["gravityy"].asFloat();
  70. // speed
  71. modeA.speed = valueMap["speed"].asFloat();
  72. modeA.speedVar = valueMap["speedVariance"].asFloat();
  73. // radial acceleration
  74. modeA.radialAccel = valueMap["radialAcceleration"].asFloat();
  75. modeA.radialAccelVar = valueMap["radialAccelVariance"].asFloat();
  76. // tangential acceleration
  77. modeA.tangentialAccel = valueMap["tangentialAcceleration"].asFloat();
  78. modeA.tangentialAccelVar = valueMap["tangentialAccelVariance"].asFloat();
  79. // rotation is dir
  80. modeA.rotationIsDir = valueMap["rotationIsDir"].asBool();
  81. }
  82. // or Mode B: radius movement
  83. else if (_emitterMode == Mode::RADIUS)
  84. {
  85. if (_configName.length()>0)
  86. {
  87. modeB.startRadius = valueMap["maxRadius"].asInt();
  88. }
  89. else
  90. {
  91. modeB.startRadius = valueMap["maxRadius"].asFloat();
  92. }
  93. modeB.startRadiusVar = valueMap["maxRadiusVariance"].asFloat();
  94. if (_configName.length()>0)
  95. {
  96. modeB.endRadius = valueMap["minRadius"].asInt();
  97. }
  98. else
  99. {
  100. modeB.endRadius = valueMap["minRadius"].asFloat();
  101. }
  102. modeB.endRadiusVar = 0.0f;
  103. if (_configName.length()>0)
  104. {
  105. modeB.rotatePerSecond = valueMap["rotatePerSecond"].asInt();
  106. }
  107. else
  108. {
  109. modeB.rotatePerSecond = valueMap["rotatePerSecond"].asFloat();
  110. }
  111. modeB.rotatePerSecondVar = valueMap["rotatePerSecondVariance"].asFloat();
  112. } else {
  113. CCASSERT( false, "Invalid emitterType in config file");
  114. CC_BREAK_IF(true);
  115. }
  116. // life span
  117. _life = valueMap["particleLifespan"].asFloat();
  118. _lifeVar = valueMap["particleLifespanVariance"].asFloat();
  119. // emission Rate
  120. _emissionRate = _totalParticles / _life;
  121. //don't get the internal texture if a batchNode is used
  122. if (!_batchNode)
  123. {
  124. // Set a compatible default for the alpha transfer
  125. _opacityModifyRGB = false;
  126. if (!_configName.empty())
  127. {
  128. _yCoordFlipped = valueMap["yCoordFlipped"].asInt();
  129. }
  130. }
  131. setDisplayFrame(frame);
  132. ret = true;
  133. }
  134. } while (0);
  135. free(buffer);
  136. free(deflated);
  137. return ret;
  138. }

注意,这里只是提供了通过粒子系统属性和纹理创建粒子系统的接口,并没有实现对粒子属性的全局保存(可以参考 Earth Warriors 3D中ParticleManager的实现 )和图片帧的预加载。

粒子属性的获取:

[cpp] view plaincopy
  1. ValueMap FileUtilsApple::getValueMapFromFile(const std::string& filename);

图片帧的获取(这个获取方式就比较多了。。。):

[cpp] view plaincopy
  1. SpriteFrame* create(const std::string& filename, const Rect& rect);

3.如何使用?

[cpp] view plaincopy
  1. auto plistData = FileUtils::getInstance()->getValueMapFromFile("Particles/emissionPart.plist");
  2. auto emission_frame = SpriteFrame::create("Images/engine.jpg", Rect(0,0,25,32));
  3. auto emitter = ParticleSystemQuad::create(plistData, emission_frame);
  4. _background->addChild(_emitter, 10);

4.源码下载

我也不知道3.0release会不会集成这个功能,这里先发出pull request的链接:https://github.com/cocos2d/cocos2d-x/pull/5979/files

【玩转cocos2d-x之三十七】粒子系统的加载优化相关推荐

  1. QQ 玩一玩获取用户图像昵称以及CocosCreator动态加载网络图片

    文章目录 1.CocosCreator 加载图片的几种方式 2.QQ 玩一玩通过openId获取用户图像.昵称 3. 源码 QQ 玩一玩获取用户图像.昵称以及CocosCreator加载图片的几种方式 ...

  2. 重温CLR(十七)程序集加载和反射

    本章主要讨论在编译时对一个类型一无所知的情况下,如何在运行时发现类型的信息.创建类型的实例以及访问类型的成员.可利用本章讲述的内容创建动态可扩展应用程序. 反射使用的典型场景一般是由一家公司创建宿主应 ...

  3. SAP UI5 应用开发教程之三十七 - 使用 Chrome 开发者工具 Console 面板进行元素审查试读版

    一套适合 SAP UI5 初学者循序渐进的学习教程 教程目录 SAP UI5 本地开发环境的搭建 SAP UI5 应用开发教程之一:Hello World SAP UI5 应用开发教程之二:SAP U ...

  4. 轻松玩转树莓派Pico之三、Windows+Ubuntu虚拟机模式下VSCode C语言开发环境搭建

    目录 1.VSCode下载与安装 2.VSCode基础插件安装 3.SSH连接与配置 4.SSH免密登录 5.Pico编译 工欲善其事,必先利其器.之前的介绍的Pico流程都是通过命令行编译,没有进行 ...

  5. MFC学习笔记之三(粒子系统+怪物简单AI+碰撞检测)

    到上海找到住的地方之后,干的第一件事,就是抓紧时间学习,为了找到工作努力ing... 备注:以下请参考http://blog.csdn.net/hust_xy/article/details/9374 ...

  6. Cocos2d之Texture2D类详解之将文件加载成Texture2D对象

    一.声明 笔者以cocos2d框架cocos2d-x-3.3rc0版本的源码做分析.本文为笔者原创,允许转载和分享,只要注明文章出处即可. 二.简介 Texture2D类简介 Texture2D类允许 ...

  7. 【Cocos2d-X(2.x) 游戏开发系列之三】最新版本cocos2d-2.0-x-2.0.2使用资源加载策略

    前段时间cocos2dx更新了最新版本cocos2d­2.0­x­2.0.2,也从这个版本开始对于资源加载与管理都改变了策略. 在之前的加载方式都是通过沿用与cocos2d-iphone一样的加载资源 ...

  8. 征途2无法显示服务器列表,解决win10系统玩征途2提示“DriverCommlnit驱动加载失败”的方法...

    征途2是一款众所周知的角色扮演类游戏,它在玩法上延续了征途1的总体风格,但是在画面和音效上比征途1的要提高了很多,其独特的玩法吸引了众多的玩家.但是又部分用户反映,在win10系统上运行征途2的游戏时 ...

  9. JavaScript玩转机器学习:保存并加载 tf.Model

    JavaScript玩转机器学习:保存并加载 tf.Model 保存并加载 tf.Model TensorFlow.js提供了保存和加载模型的功能,这些模型可以是使用LayersAPI创建的或从现有T ...

最新文章

  1. mybatis源码分析之事务管理器
  2. druid+spring配置
  3. 科普篇:贝叶斯网络中的置信度传播
  4. c++类的应用和权限
  5. iframe放大显示,如何让iFrame在点击按钮时全屏显示?
  6. CF#1288A Deadline (函数求最值问题)
  7. rxjs of操作符里subscribeToArray的实现原理示意图及分析
  8. SpringMVC配置视图的直接映射view-controller命名空间
  9. 美国夫妇用数学算法买彩票赢1.74亿元——网友:现在学数学还来得及吗?
  10. Tensorflow快餐教程(9) - 卷积
  11. 【Java】选择结构排坑指南
  12. Java常用接口与类——String类、StringBuffer类、StringBuilder类
  13. vmclone 问题
  14. 零基础学python还是c语言-学习汇编还是学习python,自己刚学完C语言,学习那个好呢?...
  15. 一条语句引发的思考:装箱和拆箱,空指针的类型转换
  16. servlet到底是什么
  17. Python程序员的发展前景
  18. 安徽省二级计算机证书,在哪个网站打印安徽省二级计算机证书?
  19. JAVA7-6 约分最简分式 (15 分)
  20. AI应用第一课:支付宝刷脸登录

热门文章

  1. 字符输出流的续写和换行
  2. MyBatis二级缓存的配置
  3. 手写自定义注解实现思路
  4. 模拟实现单链表(三级)
  5. linux 基本指令
  6. 记不住ASP.NET页面生命周期的苦恼
  7. Linux命令:MySQL系列之十一--MySQL日志管理
  8. 第一个冲刺期的第九天
  9. 精通JavaScript攻击框架:AttackAPI
  10. 水晶报表提示“需要数字字段”