Version: 2020.3
Collision 模块
Sub Emitters 模块

Triggers 模块

内置粒子系统的 Triggers 模块可用于基于粒子与场景中一个或多个碰撞体的相互作用来访问和修改粒子。启用此模块时,粒子系统将在附加的脚本上调用 OnParticleTrigger() 回调,因此可以根据粒子相对于场景中碰撞体的位置来访问粒子列表。

粒子系统 Triggers 模块
粒子系统 Triggers 模块

使用 Triggers 模块

首先,指定粒子可与场景中的哪些碰撞体进行碰撞。为此,请将一个或多个碰撞体分配给 Colliders 列表属性。要增加列表中的碰撞体数量,请单击 Colliders 列表下方的 Add (+) 按钮。要从列表中移除某个碰撞体,请选择该碰撞体,然后单击 Remove (-) 按钮。如果尚未将碰撞体分配给列表的索引,则可以使用空条目右侧较小的 Add (+) 按钮来创建和分配新的碰撞体。这将创建一个新的游戏对象作为粒子系统的子项,并将球形碰撞体附加到该游戏对象,然后将碰撞体分配给空条目。

添加碰撞体后,可指定当粒子满足传递特定触发事件类型的条件时将执行的操作。事件类型有四种,它们描述了粒子如何与碰撞体相互作用。这些事件类型如下:

  • Inside:粒子在碰撞体的边界内。
  • Outside:粒子在碰撞体的边界外。
  • Enter:粒子进入碰撞体的边界。
  • Exit:粒子退出碰撞体的边界。

在 Inspector 中,每种事件类型都有一个下拉选单,可让您选择当粒子通过触发事件的条件时粒子将发生什么情况。选项包括:

  • Callback:允许您在 OnParticleTrigger() 回调函数中访问粒子。
  • Kill:销毁粒子。您无法在 OnParticleTrigger() 回调函数中访问粒子。
  • Ignore:忽略粒子。您无法在 OnParticleTrigger() 回调函数中访问粒子。

在 OnParticleTrigger() 中访问粒子

如果选择 Callback 作为对某一触发事件的反应,则可以从附加的脚本访问满足事件条件的粒子。为此,首先需要将 OnParticleTrigger() 函数添加到附加的脚本。在此函数中,调用 ParticlePhysicsExtensions.GetTriggerParticles() 函数可获取满足触发事件条件的粒子列表。此函数接受 ParticleSystemTriggerEventType(用于指定需要获取粒子的触发事件,即 InsideOutsideEnter 还是 Exit)以及一个粒子列表(函数将向其中填充结果)。从这一列表中,可以访问、修改或销毁任何粒子。该函数还可以采用一个可选参数来输出碰撞信息,例如每个粒子触发哪个碰撞体。Collider Query Mode 属性通过此参数控制可以获得哪些信息。

有关该 API 以及如何使用该 API 的更多信息,请参阅下文的示例

属性

属性 描述
Inside 指定粒子系统在粒子位于碰撞体内的每一帧对粒子采取的操作。选项包括:
Callback:将粒子添加到可在 OnParticleTrigger() 回调中获取的列表中
Kill:销毁粒子。
Ignore:忽略粒子。
Outside 指定粒子系统在粒子位于碰撞体外的每一帧对粒子采取的操作。选项包括:
Callback:将粒子添加到可在 OnParticleTrigger() 回调中获取的列表中
Kill:销毁粒子。
Ignore:忽略粒子。
Enter 指定粒子系统在粒子进入碰撞体的帧对粒子采取的操作。选项包括:
Callback:将粒子添加到可在 OnParticleTrigger() 回调中获取的列表中
Kill:销毁粒子。
Ignore:忽略粒子。
Exit 指定粒子系统在粒子退出碰撞体的帧对粒子采取的操作。选项包括:
Callback:将粒子添加到可在 OnParticleTrigger() 回调中获取的列表中
Kill:销毁粒子。
Ignore:忽略粒子。
Collider Query Mode 指定此粒子系统用于获取有关与粒子交互的碰撞体的信息的方法。这增加了处理触发器模块所需的资源,因此,如果不需要任何额外的碰撞信息,请将此属性设置为 Disabled。选项是:
Disabled:没有获取关于每个粒子与哪个碰撞体交互的任何信息。
One:获取有关每个粒子交互的第一个碰撞体的信息。如果粒子与帧中的多个碰撞体交互,则返回 Collider 列表中与粒子交互的第一个碰撞体。
All:获取有关每个粒子交互的每个碰撞体的信息。
Radius Scale 粒子的碰撞体边界。允许您更紧密地将粒子的碰撞体边界匹配到粒子的视觉外观。如果粒子为圆形且其纹理具有淡入淡出效果,这将很有用,因为默认粒子碰撞体将在粒子达到视觉效果之前位于触发器内。请注意,当事件实际触发时,此设置不会更改,但是可以延迟或提前达到触发器的视觉效果。

• 输入 1 可以使粒子碰撞体保持同一大小,并使事件在粒子接触碰撞体时发生
• 输入小于 1 的值可以使粒子碰撞体更小,并使触发看起来是在粒子穿透碰撞体之前发生
• 输入大于 1 的值可以使粒子碰撞体更大,并使触发看起来是在粒子穿透碰撞体之后发生
Visualize Bounds 指示是否在 Scene 视图中显示每个粒子的碰撞体边界。启用此属性可显示碰撞体边界,而禁用则可隐藏碰撞体边界。

示例

与碰撞体交互

下面的示例会导致粒子在进入碰撞体的边界时变为红色,然后在离开碰撞体的边界时变为绿色。

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[ExecuteInEditMode]
public class TriggerScript : MonoBehaviour
{
    ParticleSystem ps;

    // 这些列表用于包含与每帧的触发条件
    // 匹配的粒子。
    List<ParticleSystem.Particle> enter = new List<ParticleSystem.Particle>();
    List<ParticleSystem.Particle> exit = new List<ParticleSystem.Particle>();

    void OnEnable()
    {
        ps = GetComponent<ParticleSystem>();
    }

    void OnParticleTrigger()
    {
        // 获取与此帧的触发条件匹配的粒子
        int numEnter = ps.GetTriggerParticles(ParticleSystemTriggerEventType.Enter, enter);
        int numExit = ps.GetTriggerParticles(ParticleSystemTriggerEventType.Exit, exit);

        // iterate through the particles which entered the trigger and make them red
        for (int i = 0; i < numEnter; i++)
        {
            ParticleSystem.Particle p = enter[i];
            p.startColor = new Color32(255, 0, 0, 255);
            enter[i] = p;
        }

        // 迭代离开触发器的粒子并使它们变绿
        for (int i = 0; i < numExit; i++)
        {
            ParticleSystem.Particle p = exit[i];
            p.startColor = new Color32(0, 255, 0, 255);
            exit[i] = p;
        }

        // 将修改后的粒子重新分配回粒子系统
        ps.SetTriggerParticles(ParticleSystemTriggerEventType.Enter, enter);
        ps.SetTriggerParticles(ParticleSystemTriggerEventType.Exit, exit);
    }
}

请查看以下图像以了解此示例的结果:

Editor 视图
Editor 视图
Game 视图
Game 视图

与多个碰撞体交互

以下示例利用了您可以从 GetTriggerParticles() 函数中提取的附加碰撞数据。它会导致第一个碰撞体边界内的粒子变为红色,第二个碰撞体边界内的粒子变为蓝色,或者两个碰撞体内的粒子都变为绿色。如果粒子不在碰撞体内,也会变成白色。在本例中,Collider Query Mode 设置为 All

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[ExecuteInEditMode]
public class TriggerScript : MonoBehaviour
{
    void OnParticleTrigger()
    {
        ParticleSystem ps = GetComponent();
 
        // 粒子
        List inside = new List();
        List exit = new List();
 
        // 获取
        int numInside = ps.GetTriggerParticles(ParticleSystemTriggerEventType.Inside, inside, out var insideData);
        int numExit = ps.GetTriggerParticles(ParticleSystemTriggerEventType.Exit, exit);
 
        // 迭代
        for (int i = 0; i < numInside; i++)
        {
            ParticleSystem.Particle p = inside[i];
            if (insideData.GetColliderCount(i) == 1)
            {
                if (insideData.GetCollider(i, 0) == ps.trigger.GetCollider(0))
                    p.startColor = new Color32(255, 0, 0, 255);
                else
                    p.startColor = new Color32(0, 0, 255, 255);
            }
            else if (insideData.GetColliderCount(i) == 2)
            {
                p.startColor = new Color32(0, 255, 0, 255);
            }
            inside[i] = p;
        }
        for (int i = 0; i < numExit; i++)
        {
            ParticleSystem.Particle p = exit[i];
            p.startColor = new Color32(1, 1, 1, 255);
            exit[i] = p;
        }
 
        // 设置
        ps.SetTriggerParticles(ParticleSystemTriggerEventType.Inside, inside);
        ps.SetTriggerParticles(ParticleSystemTriggerEventType.Exit, exit);
    }
}

请查看以下图像以了解此示例的结果:

Collision 模块
Sub Emitters 模块