跳至主要内容

[外文翻译] 在unity3d上建立运行重新着色和衰退的粒子系统

粒子系统是极好的系统,适应于各种各样的特效在游戏中,包括火焰,爆炸,烟雾,水,灯光,行星模拟,还有很多,unity伴随着一个建立在粒子系统上的library可以用来实施这些特效在你的或者3d游戏上,而且在unity上实施这个粒子系统有着额外的灵活性和允许你创造更神奇的特效,有时候你有些情况需要要求一些专用化,这些是不可以被建立的。此外,最近我尝试实现实现一个粒子效果让粒子分散开来像爆炸一样,然后停留在一个地方,最后缓慢的淡出不断循环。当粒子不断发散随着它们的生命周期可以熟练的用过build-in editor,等待它们的是终止。
这里可以看到一个粒子系统是我创建的,它使用build-in particle editor unity中:
 
 
暂停粒子系统
根据你们所看到的,它开始于一个随机放射方向的粒子系统,然后停止,,这个暂停特效比直着向前扩展要好,而且可以实现通过贴上一个代码在粒子系统中让它暂停然后继续
 
public class ParticleScript : MonoBehaviour {

    public float timeToPause = 2.0f;
   
    private ParticleSystem system;
    private float time;
   
    void Awake() {
        system = GetComponent();
    }
   
    void Update() {
        time += Time.deltaTime;
       
        if (!system.isPaused && time > timeToPause) {
            system.Pause();
        }
    }
}
我们开始通过定义一个public float 叫做timeToPause 表示多长时间这个粒子应该持续播放在暂停之前,在Update中,我们update timeTime.deltaTime和暂停这个粒子系统用pause()在粒子系统本身上
这些都很简单并且好用,但是我们仍然需要修改粒子的颜色在暂停的视乎,这个主意是一旦粒子系统被暂停,他就开始衰退直到它消失不可见。

重新着色粒子
我们将要做的是重新着色每一个单独的粒子,因为他们可能有同样的颜色取决于你的粒子系统怎样被配置。在这个粒子中,我们将会修改粒子的alpha在衰退的部分,但你可以应用同样的方法在任何合成的颜色中。
第一件事我们要做的是引用到当前的粒子在系统中当我们暂停的时候:
 
public class ParticleScript : MonoBehaviour {

    ...
    
    private ParticleSystem.Particle[] particles;
    
    ...
    
    void Update() {
        time += Time.deltaTime;
        
        if (!system.isPaused && time > timeToPause) {
            system.Pause();
            
            particles = new ParticleSystem.Particle[system.particleCount];
            system.GetParticles(particles);
        }
    }
}
我们定义一个队列中的粒子项目我们将会用使用储存粒子当我们暂停了系统。我们然后初始化它与当前数量的粒子在系统中用system.particleCount来作用到一个缓冲区,然后前往有粒子储存的缓冲区队列中用system.GetParticles
现在我们可以反复处理和修改这些粒子根据这个队列。在Update中,我们将要添加一些逻辑当系统被暂停来重新着色粒子像这样:
public class ParticleScript : MonoBehaviour {

    ...
    
    public float lifespan = 5.0f;
    
    ...
    
    
    void Update() {
        ...
        
        if (particles != null) {
            for (int p = 0; p < particles.Length; p++) {
                Color color = particles[p].startColor;
                color.a = ((lifespan - time + timeToPause) / lifespan);
                
                particles[p].startColor = color;
            }
            
            system.SetParticles(particles, particles.Length);
        }
    }
}
我们开始通过确定这个系统已经被暂停而且粒子已经被初始化,然后合并这些已经储藏的粒子当我们暂停这个系统的时候。对于单个粒子,我们抓住他们当前的颜色,并且更新alpha作为百分比的时间针对已经确认与总时间线对比过得粒子。同样需要注意的我们忽略了 timeToPause 添加到时间线来确认如何“淡出”之前的粒子

随着时间的推移这些粒子将会顺滑的淡出像这样:
 

表现
根 据这些粒子系统的数量,当你的粒子消散时,在每一个系统中的粒子,上面有一些规则有着基本的实施需要被标记,例如,你可能不想更新每一帧的粒子,而只更新 了第五帧,例如,你可能缓存当前的颜色,只更新粒子当这些变化非常重要时,列如,不要更新所有的粒子,在粒子系统中,当不同的alpha的差异是非常小的,甚至不会很明显。
如果你还想摧毁粒子系统,当它完全淡出识图(color.a <= 0f)而不是只是让它围绕。
这些表现的提升你选择的,如果有的话,将取决于你的案例,但是还是希望能给你一些启发对于一些特效你想要实现在你的游戏当中
完整的代码
最后,这里是完整的脚本,如下:
using UnityEngine;
using System.Collections;

public class ParticleScript : MonoBehaviour {
    
    public float lifespan = 5.0f;
    public float timeToPause = 2.0f;
    
    private ParticleSystem.Particle[] particles;
    private ParticleSystem system;
    private float time;
    
    void Awake() {
        system = GetComponent();
    }
    
    
    void Update() {
        time += Time.deltaTime;
        
        if (!system.isPaused && time > timeToPause) {
            system.Pause();
        
            particles = new ParticleSystem.Particle[system.particleCount];
            system.GetParticles(particles);
        }
        
        if (particles != null) {
            for (int p = 0; p < particles.Length; p++) {
                Color color = particles[p].startColor;
                color.a = ((lifespan - time + timeToPause) / lifespan);
                
                particles[p].startColor = color;
            }
        
            system.SetParticles(particles, particles.Length);
        }
    }
}
 
 
 
 

评论

此博客中的热门博文

【厚积薄发】扒一扒Profiler中这几个“占坑鬼”

WaitForTargetFPS、Gfx.WaitForPresent 和 Graphics.PresentAndSync是我们经常会被问到的参数。想必正在读此文的你也经常在Profiler中遇到过这几项CPU开销过大的情况。对此,我们今天就来好好地聊一聊这几个参数的具体含义和触发规则。

Unity3D研究院之提取游戏资源的三个工具支持Unity5(八十四)

这两天无意间又发现了两个提取Unity游戏资源的工具,这会儿刚好有时间我就码点字总结一下。 一、disunity 因为之前写过了所以这里就不介绍了 。Unity3D研究院之mac上从.ipa中提取unity3D游戏资源(六十六)  http://www.xuanyusong.com/archives/2584 二、UnityAssetsExplorer 下载地址: http://www.nexusmods.com/pillarsofeternity/mods/27/?tab=2&navtag=http%3A%2F%2Fwww.nexusmods.com%2Fpillarsofeternity%2Fajax%2Fmodfiles%2F%3Fid%3D27&pUp=1 百度云下载地址: http://pan.baidu.com/s/1AwTrg 如果你想解Unity5的游戏包,请使用 UnityAssetsExplorer 1.5 以上版本。 百度云下载地址: http://pan.baidu.com/s/1sjkjSJz 如下图所示,OpenAssets-File 选一个 .asset 或者一个.assetbundle 然后Extract All即可导出,感觉只是在disunity上增加了一个可视化的功能。 三、UnityStudio 其实我觉得这个工具非常牛逼、前面两个都只能把资源解开,预览图片资源得用别的工具才能打开。然而UnityStudio可以直接在自己的软件上查 看图片、shader、文本、还能直接播放音频、甚至还能看场景Hierarchy视图的树状结构。强烈推荐用UnityStudio啊。 下载地址: http://forum.xentax.com/viewtopic.php?f=10&t=11807 百度云下载地址: http://pan.baidu.com/s/1hqjMnOg UnityStudio最新版本下载 支持unity5.x   https://github.com/Perfare/UnityStudio/releases 直接预览图片 直接播放音频 查看场景树状结构 查看Shader代码。 ...

ScriptableObject 序列化

  ScriptableObject是一个类,它允许你存储大量用于共享的数据独立脚本实例,不要迷惑这个类同样可以叫做 SerializableObject,可以理解成是一个Unity串行化工具。这是一个编辑器类并且你可以在Inspector面板中编辑数据。例如: 如果你有一个存储了一百万数据的 int[],这个数组占用4MB内存,放在Prefab上,那么当你每次实例化Prefab,你都会得到这个数组的一个副本。如果你实例化10个这个 Prefab,那就会占用40MB内存。 可序列化的类型 Unity的serializes(序列化)支持所有原生的类型,也支持strings,arrays,lists还有Unity的Vector3等都支持,而且还支持自定义的类,但需要有一个串行的属性。 使用情景 预期使用情况,使用ScriptableObject是减少内存使用量,避免Values的副本。但是你也可以用它来定义可插拨的数据集。这方面的 一个例子是:想像RPG游戏中的NPC商店,你可以创建自定义ShopContens ScriptableObject,每个资产定义了一组可用于购买物品。在这样一个场景,游戏中有三个区域,每个区域都可以提供不同层级的项目。你的店铺 脚本将引用ShopContents对象,定义哪些项目可供选择。 Tips 当在检查ScriptableObject引用时,你可以在Inspector双击这个参考字段。 你可以创建一个自定义的Editor来查看不同的类似在Inspector,以帮助你管理它所表示的数据。 游戏关卡数据序列化 策划需求 一个游戏中的配置表数据,这些数据一般都是由策划在Excel等工具上配置,要运用到游戏中时,一般需要做一个转换,比如类似转换。这时可以使用 ScriptableObject,将数据预先处理成程序需要访问的数据结构,存储在ScriptableObject中,然后打包成一个外部文件,这样 在游戏运行的时候就不用做解析和组装了,这个功能对大批量的公用数据尤其有用!! 思路分析 策划在Art工程拼接好关卡信息之后,客户端根据关卡的中元素的位置,大小等信息生成出关卡,这中间有一个存储关卡信息的过程。我们的做法是把关卡 的信息存储在ScriptableObject上,然后在E...