中山大学3D游戏设计读书笔记 unity3D Note7

本文利用代码实现彩虹粒子系统以及心型线粒子系统
游戏演示视频地址http://www.iqiyi.com/w_19rz6hqaih.html
游戏具体代码地址https://github.com/dick20/3d-learning/tree/master/homework7


一. 游戏要求

使用粒子流编程控制制作一些效果, 如“粒子光环”
我根据这个粒子流技术,制作出彩虹粒子效果,以及心型曲线。


二. 设计思路

1.如何使用粒子系统?

sys
本次作业要求是通过代码来控制粒子流,那么我们控制的对象一定就是unity3d里面的Particle System。如果仅仅利用它里面的属性,通过鼠标勾选那么是不利于理解粒子效果。故这里就需要我们将某些特别的属性暴露出来,方便我们去修改。类似上图,在脚本函数中设置了Count粒子数目,size粒子大小,speed粒子速度等等变量,我们可以简单的修改这些变量来实现我们的粒子效果,而不再需要去查询繁琐的系统参数。

2.怎么通过代码修改粒子系统?

3
声明粒子系统变量,粒子属性数组,以及自己建立的粒子位置数组。
4
利用GetComponent函数来获得粒子系统的属性,再在下面进行修改。


三. 具体代码实现

1.声明基本变量属性

首先,我们先根据我们所要实现的彩虹粒子效果,声明必要的变量,其中包括Gradient组件来改变颜色,半圆的半径,粒子大小,速度,游离速度等等。
接着,我们为粒子的位置建立了一个属性类,其中包括三个属性,半径,角度,时间,通过这三个属性可以定位粒子的极坐标位置,以及通过时间来确定游离位置。

    private ParticleSystem particleSys;  // 粒子系统
    private ParticleSystem.Particle[] particleArr;  // 粒子数组  
    private Particle[] particles; // 粒子位置数组

    public Gradient colorGradient; // 粒子颜色改变器

    public int count = 10000;       // 粒子数量  
    public float size = 0.03f;      // 粒子大小  
    public float minRadius = 5.0f;  // 最小半径  
    public float maxRadius = 12.0f; // 最大半径  
    public bool clockwise = true;   // 顺时针|逆时针  
    public float speed = 2f;        // 速度  
    public float pingPong = 0.02f;  // 游离范围

    //粒子类,包括半径,角度,时间,相当于一个极坐标。
    public class Particle
    {
        public float radius = 0f, angle = 0f, time = 0f;
        public Particle(float x, float y, float z)
        {
            radius = x;
            angle = y;
            time = z;
        }
    }

2.生成粒子并确定粒子的位置

首先将上面第一步声明的数组赋值,初始化粒子系统的属性,然后通过RandomlySpread函数来给每一个粒子一个初始位置。由于这是一个半圆轨道,所以角度与半径是必须考虑的两个因素。最后必须利用SetParticles函数将改变了的粒子赋值回粒子系统,否则上面的改动将无法实现。

void Start () {
        particleArr = new ParticleSystem.Particle[count];
        particles = new Particle[count];

        // 初始化粒子系统  
        particleSys = this.GetComponent<ParticleSystem>();

        particleSys.startSpeed = 0;            // 粒子位置由程序控制  
        particleSys.startSize = size;          // 设置粒子大小  
        particleSys.loop = false;              // 设置粒子不循环
        particleSys.maxParticles = count;      // 设置最大粒子量  
        particleSys.Emit(count);               // 发射粒子
        particleSys.GetParticles(particleArr);

        RandomlySpread();   // 初始化各粒子位置
    }
    void RandomlySpread()
    {
        for (int i = 0; i < count; ++i)
        {   // 随机每个粒子距离中心的半径,同时希望粒子集中在平均半径附近  
            float midRadius = (maxRadius + minRadius) / 2;
            float minRate = Random.Range(1.0f, midRadius / minRadius);
            float maxRate = Random.Range(midRadius / maxRadius, 1.0f);
            float radius = Random.Range(minRadius * minRate, maxRadius * maxRate);

            // 随机每个粒子的角度  
            float angle = Random.Range(0.0f, 180.0f);
            float theta = angle / 180 * Mathf.PI;

            // 随机每个粒子的游离起始时间  
            float time = Random.Range(0.0f, 180.0f);

            particles[i] = new Particle(radius, angle, time);

            particleArr[i].position = new Vector3(particles[i].radius * Mathf.Cos(theta), 0f, particles[i].radius * Mathf.Sin(theta));
        }

        particleSys.SetParticles(particleArr, particleArr.Length);
    }

3.更新粒子的位置

我们在第二步所生成的粒子有了基本的形态,但是它们并不会运动。故我们在第三步必须给这些粒子更改属性来使它们运动起来。其中包括改变角度,以及确保粒子在半径方向游离,确定是顺时针还是逆时针。为了实现彩虹,我们还需要改变粒子的颜色值。最后同样需要利用SetParticles函数将改变了的粒子赋值回粒子系统,否则上面的改动将无法实现。

private int tier = 10;  // 速度差分层数
    void Update () {
        for (int i = 0; i < count; i++)
        {
            if (clockwise)  // 顺时针旋转  
                particles[i].angle -= (i % tier + 1) * (speed / particles[i].radius / tier);
            else            // 逆时针旋转  
                particles[i].angle += (i % tier + 1) * (speed / particles[i].radius / tier);
            // 保证angle在0~360度  
            particles[i].angle = (180.0f + particles[i].angle) % 180.0f;
            float theta = particles[i].angle / 180 * Mathf.PI;
            particleArr[i].position = new Vector3(particles[i].radius * Mathf.Cos(theta), 0f, particles[i].radius * Mathf.Sin(theta));
            // 粒子在半径方向上游离  
            particles[i].time += Time.deltaTime;
            particles[i].radius += Mathf.PingPong(particles[i].time / minRadius / maxRadius, pingPong) - pingPong / 2.0f;

            particleArr[i].color = colorGradient.Evaluate(Random.value);
        }

        particleSys.SetParticles(particleArr, particleArr.Length);
    }

通过这一份脚本,我们只需要新增7个粒子系统分别赋予不同颜色,并改变它们的半径便可以实现漂亮的彩虹。

粒子效果图如下:
show

4.Extra:做完彩虹后,我思考是不是可以做一些除了圆形之外的粒子效果呢?由此我想到了心型线。其实,我们只需要更改粒子的运动位置,以及运动速度完全就可以实现任意的效果。

以下是我对上面半圆形代码的修改,只需要在更新位置的部分,加上心型线的函数以及随机一个范围来增大心型线的宽度。
5

 float theta = Random.Range(0.0f, 360.0f) / 180 * Mathf.PI;
 particleArr[i].position = new Vector3(16 * Mathf.Sin(theta) * Mathf.Sin(theta) * Mathf.Sin(theta) + Random.Range(-1f, 1f), 0f, 13 * Mathf.Cos(theta) - 5 * Mathf.Cos(theta * 2) - 2 * Mathf.Cos(theta * 3) - Mathf.Cos(4 * theta) + Random.Range(-1f, 1f));

粒子效果图如下:
6


四. 总结

完成这个粒子系统,我收获了粒子系统的基本使用,如何通过代码来生成粒子,更改粒子运动轨迹,改变粒子运动速度,颜色等等。这个粒子系统并不难实现,只需要理解几个关键函数,以及需要一点创意。


由于作者水平有限,如有任何错误请指出并讨论,十分感谢!
想了解更多关于3d游戏设计代码,可以点击我的Github一起学习。
Github地址:https://github.com/dick20/3d-learning

猜你喜欢

转载自blog.csdn.net/dickdick111/article/details/80502793
今日推荐