2023-11-07 10:42:16 +08:00
|
|
|
using System;
|
2020-08-28 13:38:13 +08:00
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Runtime.CompilerServices;
|
2020-09-28 20:35:40 +08:00
|
|
|
using Coffee.UIParticleExtensions;
|
2018-06-22 18:48:14 +08:00
|
|
|
using UnityEngine;
|
2020-08-20 03:42:16 +08:00
|
|
|
using UnityEngine.Rendering;
|
2023-08-15 20:56:09 +08:00
|
|
|
using UnityEngine.Serialization;
|
2018-06-22 18:48:14 +08:00
|
|
|
using UnityEngine.UI;
|
2023-11-07 10:42:16 +08:00
|
|
|
using Random = UnityEngine.Random;
|
2018-06-22 18:48:14 +08:00
|
|
|
|
2020-08-28 13:38:13 +08:00
|
|
|
[assembly: InternalsVisibleTo("Coffee.UIParticle.Editor")]
|
|
|
|
|
2018-06-22 18:48:14 +08:00
|
|
|
namespace Coffee.UIExtensions
|
|
|
|
{
|
2020-02-12 20:38:06 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Render maskable and sortable particle effect ,without Camera, RenderTexture or Canvas.
|
|
|
|
/// </summary>
|
2022-02-18 03:57:27 +08:00
|
|
|
[ExecuteAlways]
|
2020-08-28 13:38:13 +08:00
|
|
|
[RequireComponent(typeof(RectTransform))]
|
2020-08-11 23:09:55 +08:00
|
|
|
[RequireComponent(typeof(CanvasRenderer))]
|
2023-08-18 10:42:22 +08:00
|
|
|
public class UIParticle : MaskableGraphic, ISerializationCallbackReceiver
|
2020-02-12 20:38:06 +08:00
|
|
|
{
|
2024-01-23 22:17:57 +08:00
|
|
|
public enum AutoScalingMode
|
|
|
|
{
|
|
|
|
None,
|
|
|
|
UIParticle,
|
|
|
|
Transform
|
|
|
|
}
|
|
|
|
|
2022-06-11 22:10:17 +08:00
|
|
|
public enum MeshSharing
|
|
|
|
{
|
|
|
|
None,
|
|
|
|
Auto,
|
|
|
|
Primary,
|
|
|
|
PrimarySimulator,
|
2023-08-17 08:43:02 +08:00
|
|
|
Replica
|
2022-06-11 22:10:17 +08:00
|
|
|
}
|
|
|
|
|
2023-08-18 10:42:22 +08:00
|
|
|
public enum PositionMode
|
|
|
|
{
|
|
|
|
Relative,
|
|
|
|
Absolute
|
|
|
|
}
|
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
[HideInInspector]
|
|
|
|
[SerializeField]
|
2024-06-27 10:38:28 +08:00
|
|
|
[Obsolete]
|
2023-08-17 08:43:02 +08:00
|
|
|
internal bool m_IsTrail;
|
2020-02-12 20:38:06 +08:00
|
|
|
|
2023-08-18 10:42:56 +08:00
|
|
|
[HideInInspector]
|
|
|
|
[FormerlySerializedAs("m_IgnoreParent")]
|
|
|
|
[SerializeField]
|
2024-06-27 10:38:28 +08:00
|
|
|
[Obsolete]
|
2023-08-18 10:42:56 +08:00
|
|
|
private bool m_IgnoreCanvasScaler;
|
|
|
|
|
2023-08-18 10:42:22 +08:00
|
|
|
[HideInInspector]
|
|
|
|
[SerializeField]
|
2024-06-27 10:38:28 +08:00
|
|
|
[Obsolete]
|
|
|
|
internal bool m_AbsoluteMode;
|
2023-08-18 10:42:22 +08:00
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
[Tooltip("Scale the rendering particles. When the `3D` toggle is enabled, 3D scale (x, y, z) is supported.")]
|
2022-06-08 11:54:11 +08:00
|
|
|
[SerializeField]
|
|
|
|
private Vector3 m_Scale3D = new Vector3(10, 10, 10);
|
2020-10-04 22:26:53 +08:00
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
[Tooltip("If you want to update material properties (e.g. _MainTex_ST, _Color) in AnimationClip, " +
|
|
|
|
"use this to mark as animatable.")]
|
2022-06-08 11:54:11 +08:00
|
|
|
[SerializeField]
|
2020-08-20 03:42:16 +08:00
|
|
|
internal AnimatableProperty[] m_AnimatableProperties = new AnimatableProperty[0];
|
2020-02-12 20:38:06 +08:00
|
|
|
|
2022-06-08 11:54:11 +08:00
|
|
|
[Tooltip("Particles")]
|
|
|
|
[SerializeField]
|
2020-08-28 13:38:13 +08:00
|
|
|
private List<ParticleSystem> m_Particles = new List<ParticleSystem>();
|
2020-02-12 20:38:06 +08:00
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
[Tooltip("Particle simulation results are shared within the same group. " +
|
|
|
|
"A large number of the same effects can be displayed with a small load.\n" +
|
|
|
|
"None: Disable mesh sharing.\n" +
|
|
|
|
"Auto: Automatically select Primary/Replica.\n" +
|
|
|
|
"Primary: Provides particle simulation results to the same group.\n" +
|
2023-08-17 08:43:02 +08:00
|
|
|
"Primary Simulator: Primary, but do not render the particle (simulation only).\n" +
|
2024-06-27 10:38:28 +08:00
|
|
|
"Replica: Render simulation results provided by the primary.")]
|
2022-06-11 22:10:17 +08:00
|
|
|
[SerializeField]
|
|
|
|
private MeshSharing m_MeshSharing = MeshSharing.None;
|
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
[Tooltip("Mesh sharing group ID.\n" +
|
|
|
|
"If non-zero is specified, particle simulation results are shared within the group.")]
|
2022-06-11 22:10:17 +08:00
|
|
|
[SerializeField]
|
2023-08-17 08:43:02 +08:00
|
|
|
private int m_GroupId;
|
2022-06-11 22:10:17 +08:00
|
|
|
|
2022-06-14 12:27:54 +08:00
|
|
|
[SerializeField]
|
2023-08-17 08:43:02 +08:00
|
|
|
private int m_GroupMaxId;
|
2022-06-14 12:27:54 +08:00
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
[Tooltip("Emission position mode.\n" +
|
|
|
|
"Relative: The particles will be emitted from the scaled position.\n" +
|
|
|
|
"Absolute: The particles will be emitted from the world position.")]
|
2022-06-25 01:04:23 +08:00
|
|
|
[SerializeField]
|
2023-08-18 10:42:22 +08:00
|
|
|
private PositionMode m_PositionMode = PositionMode.Relative;
|
2022-06-25 01:04:23 +08:00
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
[SerializeField]
|
2024-06-27 10:38:28 +08:00
|
|
|
[Obsolete]
|
|
|
|
internal bool m_AutoScaling;
|
2023-11-07 10:42:16 +08:00
|
|
|
|
|
|
|
[SerializeField]
|
2024-06-27 10:38:28 +08:00
|
|
|
[Tooltip(
|
|
|
|
"How to automatically adjust when the Canvas scale is changed by the screen size or reference resolution.\n" +
|
|
|
|
"None: Do nothing.\n" +
|
|
|
|
"Transform: Transform.lossyScale (=world scale) will be set to (1, 1, 1).\n" +
|
|
|
|
"UIParticle: UIParticle.scale will be adjusted.")]
|
2023-11-07 10:42:16 +08:00
|
|
|
private AutoScalingMode m_AutoScalingMode = AutoScalingMode.Transform;
|
|
|
|
|
2024-06-26 22:13:09 +08:00
|
|
|
[SerializeField]
|
|
|
|
[Tooltip("Use a custom view.\n" +
|
|
|
|
"Use this if the particles are not displayed correctly due to min/max particle size.")]
|
|
|
|
private bool m_UseCustomView;
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
[Tooltip("Custom view size.\n" +
|
|
|
|
"Change the bake view size.")]
|
|
|
|
private float m_CustomViewSize = 10;
|
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
private readonly List<UIParticleRenderer> _renderers = new List<UIParticleRenderer>();
|
2024-06-20 11:51:02 +08:00
|
|
|
private Camera _bakeCamera;
|
2024-06-27 10:38:28 +08:00
|
|
|
private Canvas _canvas;
|
|
|
|
private int _groupId;
|
2024-06-18 16:13:35 +08:00
|
|
|
private bool _isScaleStored;
|
2024-06-27 10:38:28 +08:00
|
|
|
private Vector3 _storedScale;
|
|
|
|
private DrivenRectTransformTracker _tracker;
|
2020-08-28 13:38:13 +08:00
|
|
|
|
2020-08-20 03:42:16 +08:00
|
|
|
/// <summary>
|
2023-08-17 08:43:02 +08:00
|
|
|
/// Should this graphic be considered a target for ray-casting?
|
2020-08-20 03:42:16 +08:00
|
|
|
/// </summary>
|
|
|
|
public override bool raycastTarget
|
2020-02-12 20:38:06 +08:00
|
|
|
{
|
2024-01-23 22:17:57 +08:00
|
|
|
get => false;
|
2020-08-28 13:38:13 +08:00
|
|
|
set { }
|
2020-08-20 03:42:16 +08:00
|
|
|
}
|
2020-02-12 20:38:06 +08:00
|
|
|
|
2022-06-11 22:10:17 +08:00
|
|
|
/// <summary>
|
2024-06-27 10:38:28 +08:00
|
|
|
/// Particle simulation results are shared within the same group.
|
|
|
|
/// A large number of the same effects can be displayed with a small load.
|
2023-08-17 08:43:02 +08:00
|
|
|
/// None: disable mesh sharing.
|
2023-08-14 14:32:26 +08:00
|
|
|
/// Auto: automatically select Primary/Replica.
|
2022-06-11 22:10:17 +08:00
|
|
|
/// Primary: provides particle simulation results to the same group.
|
|
|
|
/// Primary Simulator: Primary, but do not render the particle (simulation only).
|
2023-08-14 14:32:26 +08:00
|
|
|
/// Replica: render simulation results provided by the primary.
|
2022-06-11 22:10:17 +08:00
|
|
|
/// </summary>
|
|
|
|
public MeshSharing meshSharing
|
|
|
|
{
|
2024-01-23 22:17:57 +08:00
|
|
|
get => m_MeshSharing;
|
|
|
|
set => m_MeshSharing = value;
|
2022-06-11 22:10:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
2023-08-17 08:43:02 +08:00
|
|
|
/// Mesh sharing group ID.
|
|
|
|
/// If non-zero is specified, particle simulation results are shared within the group.
|
2022-06-11 22:10:17 +08:00
|
|
|
/// </summary>
|
|
|
|
public int groupId
|
|
|
|
{
|
2024-01-23 22:17:57 +08:00
|
|
|
get => _groupId;
|
2022-06-14 12:27:54 +08:00
|
|
|
set
|
|
|
|
{
|
|
|
|
if (m_GroupId == value) return;
|
|
|
|
m_GroupId = value;
|
|
|
|
if (m_GroupId != m_GroupMaxId)
|
2023-08-17 08:43:02 +08:00
|
|
|
{
|
2022-06-14 12:27:54 +08:00
|
|
|
ResetGroupId();
|
2023-08-17 08:43:02 +08:00
|
|
|
}
|
2022-06-14 12:27:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public int groupMaxId
|
|
|
|
{
|
2024-01-23 22:17:57 +08:00
|
|
|
get => m_GroupMaxId;
|
2022-06-14 12:27:54 +08:00
|
|
|
set
|
|
|
|
{
|
|
|
|
if (m_GroupMaxId == value) return;
|
|
|
|
m_GroupMaxId = value;
|
|
|
|
ResetGroupId();
|
|
|
|
}
|
2022-06-11 22:10:17 +08:00
|
|
|
}
|
|
|
|
|
2022-06-25 01:04:23 +08:00
|
|
|
/// <summary>
|
2024-06-27 10:38:28 +08:00
|
|
|
/// Emission position mode.
|
|
|
|
/// Relative: The particles will be emitted from the scaled position.
|
|
|
|
/// Absolute: The particles will be emitted from the world position.
|
2023-08-18 10:42:22 +08:00
|
|
|
/// </summary>
|
|
|
|
public PositionMode positionMode
|
|
|
|
{
|
2024-01-23 22:17:57 +08:00
|
|
|
get => m_PositionMode;
|
|
|
|
set => m_PositionMode = value;
|
2023-08-18 10:42:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Particle position mode.
|
|
|
|
/// Relative: The particles will be emitted from the scaled position of the ParticleSystem.
|
|
|
|
/// Absolute: The particles will be emitted from the world position of the ParticleSystem.
|
2022-06-25 01:04:23 +08:00
|
|
|
/// </summary>
|
2024-06-27 10:38:28 +08:00
|
|
|
[Obsolete("The absoluteMode is now obsolete. Please use the autoScalingMode instead.", false)]
|
2022-06-25 01:04:23 +08:00
|
|
|
public bool absoluteMode
|
|
|
|
{
|
2024-01-23 22:17:57 +08:00
|
|
|
get => m_PositionMode == PositionMode.Absolute;
|
|
|
|
set => positionMode = value ? PositionMode.Absolute : PositionMode.Relative;
|
2022-06-25 01:04:23 +08:00
|
|
|
}
|
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
/// <summary>
|
2023-11-07 10:42:16 +08:00
|
|
|
/// Prevents the root-Canvas scale from affecting the hierarchy-scaled ParticleSystem.
|
2023-08-17 08:43:02 +08:00
|
|
|
/// </summary>
|
2023-11-07 10:42:16 +08:00
|
|
|
[Obsolete("The autoScaling is now obsolete. Please use the autoScalingMode instead.", false)]
|
2023-08-15 20:56:09 +08:00
|
|
|
public bool autoScaling
|
|
|
|
{
|
2024-01-23 22:17:57 +08:00
|
|
|
get => m_AutoScalingMode != AutoScalingMode.None;
|
|
|
|
set => autoScalingMode = value ? AutoScalingMode.Transform : AutoScalingMode.None;
|
2023-11-07 10:42:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
2024-06-27 10:38:28 +08:00
|
|
|
/// How to automatically adjust when the Canvas scale is changed by the screen size or reference resolution.
|
|
|
|
/// <para/>
|
|
|
|
/// None: Do nothing.
|
|
|
|
/// <para/>
|
2023-11-07 10:42:16 +08:00
|
|
|
/// Transform: Transform.lossyScale (=world scale) will be set to (1, 1, 1).
|
2024-06-27 10:38:28 +08:00
|
|
|
/// <para/>
|
2023-11-07 10:42:16 +08:00
|
|
|
/// UIParticle: UIParticle.scale will be adjusted.
|
|
|
|
/// </summary>
|
|
|
|
public AutoScalingMode autoScalingMode
|
|
|
|
{
|
2024-01-23 22:17:57 +08:00
|
|
|
get => m_AutoScalingMode;
|
2023-08-15 20:56:09 +08:00
|
|
|
set
|
|
|
|
{
|
2023-11-07 10:42:16 +08:00
|
|
|
if (m_AutoScalingMode == value) return;
|
|
|
|
m_AutoScalingMode = value;
|
2024-06-18 16:13:35 +08:00
|
|
|
|
|
|
|
if (autoScalingMode != AutoScalingMode.Transform && _isScaleStored)
|
|
|
|
{
|
|
|
|
transform.localScale = _storedScale;
|
|
|
|
_isScaleStored = false;
|
|
|
|
}
|
2023-08-15 20:56:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-26 22:13:09 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Use a custom view.
|
|
|
|
/// Use this if the particles are not displayed correctly due to min/max particle size.
|
|
|
|
/// </summary>
|
|
|
|
public bool useCustomView
|
|
|
|
{
|
|
|
|
get => m_UseCustomView;
|
|
|
|
set => m_UseCustomView = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Custom view size.
|
|
|
|
/// Change the bake view size.
|
|
|
|
/// </summary>
|
|
|
|
public float customViewSize
|
|
|
|
{
|
|
|
|
get => m_CustomViewSize;
|
|
|
|
set => m_CustomViewSize = Mathf.Max(0.1f, value);
|
|
|
|
}
|
|
|
|
|
2024-01-23 22:17:57 +08:00
|
|
|
internal bool useMeshSharing => m_MeshSharing != MeshSharing.None;
|
2022-06-11 22:10:17 +08:00
|
|
|
|
2024-01-23 22:17:57 +08:00
|
|
|
internal bool isPrimary =>
|
|
|
|
m_MeshSharing == MeshSharing.Primary
|
|
|
|
|| m_MeshSharing == MeshSharing.PrimarySimulator;
|
2022-06-11 22:10:17 +08:00
|
|
|
|
2024-01-23 22:17:57 +08:00
|
|
|
internal bool canSimulate =>
|
|
|
|
m_MeshSharing == MeshSharing.None
|
|
|
|
|| m_MeshSharing == MeshSharing.Auto
|
|
|
|
|| m_MeshSharing == MeshSharing.Primary
|
|
|
|
|| m_MeshSharing == MeshSharing.PrimarySimulator;
|
2022-06-11 22:10:17 +08:00
|
|
|
|
2024-01-23 22:17:57 +08:00
|
|
|
internal bool canRender =>
|
|
|
|
m_MeshSharing == MeshSharing.None
|
|
|
|
|| m_MeshSharing == MeshSharing.Auto
|
|
|
|
|| m_MeshSharing == MeshSharing.Primary
|
|
|
|
|| m_MeshSharing == MeshSharing.Replica;
|
2022-06-11 22:10:17 +08:00
|
|
|
|
2020-02-12 20:38:06 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Particle effect scale.
|
|
|
|
/// </summary>
|
2020-08-12 22:19:08 +08:00
|
|
|
public float scale
|
|
|
|
{
|
2024-01-23 22:17:57 +08:00
|
|
|
get => m_Scale3D.x;
|
|
|
|
set => m_Scale3D = new Vector3(value, value, value);
|
2020-10-04 22:26:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Particle effect scale.
|
|
|
|
/// </summary>
|
|
|
|
public Vector3 scale3D
|
|
|
|
{
|
2024-01-23 22:17:57 +08:00
|
|
|
get => m_Scale3D;
|
|
|
|
set => m_Scale3D = value;
|
2020-02-12 20:38:06 +08:00
|
|
|
}
|
|
|
|
|
2023-11-07 10:42:16 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Particle effect scale.
|
|
|
|
/// </summary>
|
2024-06-18 16:47:45 +08:00
|
|
|
public Vector3 scale3DForCalc => autoScalingMode == AutoScalingMode.Transform
|
|
|
|
? m_Scale3D
|
2024-06-18 16:48:08 +08:00
|
|
|
: m_Scale3D.GetScaled(canvasScale, transform.localScale);
|
2023-11-07 10:42:16 +08:00
|
|
|
|
2024-01-23 22:17:57 +08:00
|
|
|
public List<ParticleSystem> particles => m_Particles;
|
2020-02-12 20:38:06 +08:00
|
|
|
|
2022-06-08 11:54:11 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Paused.
|
|
|
|
/// </summary>
|
2023-08-17 08:43:02 +08:00
|
|
|
public bool isPaused { get; private set; }
|
2022-06-08 11:54:11 +08:00
|
|
|
|
2023-08-15 20:56:09 +08:00
|
|
|
public Vector3 parentScale { get; private set; }
|
|
|
|
|
2023-11-07 10:42:16 +08:00
|
|
|
public Vector3 canvasScale { get; private set; }
|
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
protected override void OnEnable()
|
|
|
|
{
|
2024-06-18 16:13:35 +08:00
|
|
|
_isScaleStored = false;
|
2023-08-17 08:43:02 +08:00
|
|
|
ResetGroupId();
|
|
|
|
UIParticleUpdater.Register(this);
|
|
|
|
RegisterDirtyMaterialCallback(UpdateRendererMaterial);
|
|
|
|
|
|
|
|
if (0 < particles.Count)
|
|
|
|
{
|
|
|
|
RefreshParticles(particles);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RefreshParticles();
|
|
|
|
}
|
|
|
|
|
|
|
|
base.OnEnable();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// This function is called when the behaviour becomes disabled.
|
|
|
|
/// </summary>
|
|
|
|
protected override void OnDisable()
|
|
|
|
{
|
2024-06-18 16:13:35 +08:00
|
|
|
_tracker.Clear();
|
|
|
|
if (autoScalingMode == AutoScalingMode.Transform && _isScaleStored)
|
|
|
|
{
|
|
|
|
transform.localScale = _storedScale;
|
|
|
|
}
|
|
|
|
|
|
|
|
_isScaleStored = false;
|
2023-08-17 08:43:02 +08:00
|
|
|
UIParticleUpdater.Unregister(this);
|
|
|
|
_renderers.ForEach(r => r.Reset());
|
|
|
|
UnregisterDirtyMaterialCallback(UpdateRendererMaterial);
|
|
|
|
|
|
|
|
base.OnDisable();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Callback for when properties have been changed by animation.
|
|
|
|
/// </summary>
|
|
|
|
protected override void OnDidApplyAnimationProperties()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-08-18 10:42:22 +08:00
|
|
|
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void ISerializationCallbackReceiver.OnAfterDeserialize()
|
|
|
|
{
|
2024-06-27 10:38:28 +08:00
|
|
|
#pragma warning disable CS0612 // Type or member is obsolete
|
2023-11-07 10:42:16 +08:00
|
|
|
if (m_IgnoreCanvasScaler || m_AutoScaling)
|
2023-08-18 10:42:56 +08:00
|
|
|
{
|
2023-08-18 19:30:01 +08:00
|
|
|
m_IgnoreCanvasScaler = false;
|
2023-08-18 10:42:56 +08:00
|
|
|
m_AutoScaling = false;
|
2023-11-07 10:42:16 +08:00
|
|
|
m_AutoScalingMode = AutoScalingMode.Transform;
|
2023-08-18 10:42:56 +08:00
|
|
|
}
|
|
|
|
|
2023-08-18 10:42:22 +08:00
|
|
|
if (m_AbsoluteMode)
|
|
|
|
{
|
2023-08-18 19:30:01 +08:00
|
|
|
m_AbsoluteMode = false;
|
2023-08-18 10:42:22 +08:00
|
|
|
m_PositionMode = PositionMode.Absolute;
|
|
|
|
}
|
2024-06-27 10:38:28 +08:00
|
|
|
#pragma warning restore CS0612 // Type or member is obsolete
|
2023-08-18 10:42:22 +08:00
|
|
|
}
|
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Play the ParticleSystems.
|
|
|
|
/// </summary>
|
2020-08-28 13:38:13 +08:00
|
|
|
public void Play()
|
2020-08-20 03:42:16 +08:00
|
|
|
{
|
2022-06-08 11:54:11 +08:00
|
|
|
particles.Exec(p => p.Simulate(0, false, true));
|
|
|
|
isPaused = false;
|
2020-02-12 20:38:06 +08:00
|
|
|
}
|
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Pause the ParticleSystems.
|
|
|
|
/// </summary>
|
2020-08-28 13:38:13 +08:00
|
|
|
public void Pause()
|
2020-08-20 03:42:16 +08:00
|
|
|
{
|
2020-08-28 13:38:13 +08:00
|
|
|
particles.Exec(p => p.Pause());
|
2022-06-08 11:54:11 +08:00
|
|
|
isPaused = true;
|
|
|
|
}
|
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Unpause the ParticleSystems.
|
|
|
|
/// </summary>
|
2022-06-08 11:54:11 +08:00
|
|
|
public void Resume()
|
|
|
|
{
|
|
|
|
isPaused = false;
|
2020-08-20 03:42:16 +08:00
|
|
|
}
|
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Stop the ParticleSystems.
|
|
|
|
/// </summary>
|
2020-08-28 13:38:13 +08:00
|
|
|
public void Stop()
|
2020-08-20 03:42:16 +08:00
|
|
|
{
|
2020-08-28 13:38:13 +08:00
|
|
|
particles.Exec(p => p.Stop());
|
2022-06-08 11:54:11 +08:00
|
|
|
isPaused = true;
|
2020-08-20 03:42:16 +08:00
|
|
|
}
|
2023-08-17 08:43:02 +08:00
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Start emission of the ParticleSystems.
|
|
|
|
/// </summary>
|
2023-08-15 08:52:16 +08:00
|
|
|
public void StartEmission()
|
|
|
|
{
|
|
|
|
particles.Exec(p =>
|
|
|
|
{
|
|
|
|
var emission = p.emission;
|
|
|
|
emission.enabled = true;
|
|
|
|
});
|
|
|
|
}
|
2023-08-17 08:43:02 +08:00
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Stop emission of the ParticleSystems.
|
|
|
|
/// </summary>
|
2023-08-15 08:52:16 +08:00
|
|
|
public void StopEmission()
|
|
|
|
{
|
|
|
|
particles.Exec(p =>
|
|
|
|
{
|
|
|
|
var emission = p.emission;
|
|
|
|
emission.enabled = false;
|
|
|
|
});
|
|
|
|
}
|
2020-08-20 03:42:16 +08:00
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Clear the particles of the ParticleSystems.
|
|
|
|
/// </summary>
|
2021-02-23 12:30:46 +08:00
|
|
|
public void Clear()
|
|
|
|
{
|
|
|
|
particles.Exec(p => p.Clear());
|
2022-06-08 11:54:11 +08:00
|
|
|
isPaused = true;
|
2021-02-23 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Get all base materials to render.
|
|
|
|
/// </summary>
|
|
|
|
public void GetMaterials(List<Material> result)
|
|
|
|
{
|
|
|
|
if (result == null) return;
|
|
|
|
|
|
|
|
for (var i = 0; i < _renderers.Count; i++)
|
|
|
|
{
|
|
|
|
var r = _renderers[i];
|
|
|
|
if (!r || !r.material) continue;
|
|
|
|
result.Add(r.material);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Refresh UIParticle using the ParticleSystem instance.
|
|
|
|
/// </summary>
|
2020-09-02 13:15:30 +08:00
|
|
|
public void SetParticleSystemInstance(GameObject instance)
|
|
|
|
{
|
|
|
|
SetParticleSystemInstance(instance, true);
|
|
|
|
}
|
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Refresh UIParticle using the ParticleSystem instance.
|
|
|
|
/// </summary>
|
2020-09-03 00:02:59 +08:00
|
|
|
public void SetParticleSystemInstance(GameObject instance, bool destroyOldParticles)
|
2020-09-02 13:15:30 +08:00
|
|
|
{
|
|
|
|
if (!instance) return;
|
|
|
|
|
2024-06-26 16:17:38 +08:00
|
|
|
var childCount = transform.childCount;
|
|
|
|
for (var i = 0; i < childCount; i++)
|
2020-09-02 13:15:30 +08:00
|
|
|
{
|
2024-06-26 16:17:38 +08:00
|
|
|
var go = transform.GetChild(i).gameObject;
|
|
|
|
if (go.TryGetComponent<Camera>(out var cam) && cam == _bakeCamera) continue;
|
|
|
|
if (go.TryGetComponent<UIParticleRenderer>(out var _)) continue;
|
|
|
|
|
2020-09-02 13:15:30 +08:00
|
|
|
go.SetActive(false);
|
2023-08-17 08:43:02 +08:00
|
|
|
if (destroyOldParticles)
|
|
|
|
{
|
|
|
|
Misc.Destroy(go);
|
|
|
|
}
|
2020-09-02 13:15:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
var tr = instance.transform;
|
|
|
|
tr.SetParent(transform, false);
|
|
|
|
tr.localPosition = Vector3.zero;
|
|
|
|
|
2020-09-03 00:02:59 +08:00
|
|
|
RefreshParticles(instance);
|
2020-09-02 13:15:30 +08:00
|
|
|
}
|
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Refresh UIParticle using the prefab.
|
|
|
|
/// The prefab is automatically instantiated.
|
|
|
|
/// </summary>
|
2020-09-02 13:15:30 +08:00
|
|
|
public void SetParticleSystemPrefab(GameObject prefab)
|
|
|
|
{
|
|
|
|
if (!prefab) return;
|
|
|
|
|
|
|
|
SetParticleSystemInstance(Instantiate(prefab.gameObject), true);
|
|
|
|
}
|
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Refresh UIParticle.
|
|
|
|
/// Collect ParticleSystems under the GameObject and refresh the UIParticle.
|
|
|
|
/// </summary>
|
2020-08-28 13:38:13 +08:00
|
|
|
public void RefreshParticles()
|
2020-08-20 03:42:16 +08:00
|
|
|
{
|
2020-09-03 00:02:59 +08:00
|
|
|
RefreshParticles(gameObject);
|
|
|
|
}
|
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Refresh UIParticle.
|
|
|
|
/// Collect ParticleSystems under the GameObject and refresh the UIParticle.
|
|
|
|
/// </summary>
|
2022-06-17 12:35:19 +08:00
|
|
|
private void RefreshParticles(GameObject root)
|
2020-09-03 00:02:59 +08:00
|
|
|
{
|
|
|
|
if (!root) return;
|
2023-08-17 16:48:48 +08:00
|
|
|
root.GetComponentsInChildren(true, particles);
|
2024-06-27 10:38:28 +08:00
|
|
|
for (var i = particles.Count - 1; 0 <= i; i--)
|
|
|
|
{
|
|
|
|
var ps = particles[i];
|
|
|
|
if (!ps || ps.GetComponentInParent<UIParticle>(true) != this)
|
|
|
|
{
|
|
|
|
particles.RemoveAt(i);
|
|
|
|
}
|
|
|
|
}
|
2020-08-28 13:38:13 +08:00
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
for (var i = 0; i < particles.Count; i++)
|
2020-08-28 15:50:13 +08:00
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
var ps = particles[i];
|
2020-08-28 15:50:13 +08:00
|
|
|
var tsa = ps.textureSheetAnimation;
|
2022-06-08 11:54:11 +08:00
|
|
|
if (tsa.mode == ParticleSystemAnimationMode.Sprites && tsa.uvChannelMask == 0)
|
2023-08-17 08:43:02 +08:00
|
|
|
{
|
2020-08-28 15:50:13 +08:00
|
|
|
tsa.uvChannelMask = UVChannelFlags.UV0;
|
2023-08-17 08:43:02 +08:00
|
|
|
}
|
2020-08-28 15:50:13 +08:00
|
|
|
}
|
|
|
|
|
2022-06-08 11:54:11 +08:00
|
|
|
RefreshParticles(particles);
|
2020-08-20 03:42:16 +08:00
|
|
|
}
|
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Refresh UIParticle using a list of ParticleSystems.
|
|
|
|
/// </summary>
|
|
|
|
public void RefreshParticles(List<ParticleSystem> particleSystems)
|
2020-02-12 20:38:06 +08:00
|
|
|
{
|
2024-06-27 10:38:28 +08:00
|
|
|
// Collect children UIParticleRenderer components.
|
2023-08-14 14:42:25 +08:00
|
|
|
// #246: Nullptr exceptions when using nested UIParticle components in hierarchy
|
2023-08-17 08:43:02 +08:00
|
|
|
_renderers.Clear();
|
2024-06-27 10:38:28 +08:00
|
|
|
var childCount = transform.childCount;
|
|
|
|
for (var i = 0; i < childCount; i++)
|
2023-08-14 14:42:25 +08:00
|
|
|
{
|
2024-06-27 10:38:28 +08:00
|
|
|
var child = transform.GetChild(i);
|
|
|
|
if (child.TryGetComponent(out UIParticleRenderer uiParticleRenderer))
|
2023-08-14 14:42:25 +08:00
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
_renderers.Add(uiParticleRenderer);
|
2023-08-14 14:42:25 +08:00
|
|
|
}
|
|
|
|
}
|
2020-08-28 13:38:13 +08:00
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
// Reset the UIParticleRenderer components.
|
2023-08-17 08:43:02 +08:00
|
|
|
for (var i = 0; i < _renderers.Count; i++)
|
2023-08-14 14:44:04 +08:00
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
_renderers[i].Reset(i);
|
2023-08-14 14:44:04 +08:00
|
|
|
}
|
|
|
|
|
2024-06-27 10:38:28 +08:00
|
|
|
// Set the ParticleSystem to the UIParticleRenderer. If the trail is enabled, set it additionally.
|
2020-08-28 13:38:13 +08:00
|
|
|
var j = 0;
|
2024-06-27 10:38:28 +08:00
|
|
|
for (var i = 0; i < particleSystems.Count; i++)
|
2020-02-12 20:38:06 +08:00
|
|
|
{
|
2024-06-27 10:38:28 +08:00
|
|
|
var ps = particleSystems[i];
|
2023-08-17 08:43:02 +08:00
|
|
|
if (!ps) continue;
|
|
|
|
GetRenderer(j++).Set(this, ps, false);
|
2024-06-27 10:38:28 +08:00
|
|
|
|
|
|
|
// If the trail is enabled, set it additionally.
|
2023-08-17 08:43:02 +08:00
|
|
|
if (ps.trails.enabled)
|
2020-08-20 03:42:16 +08:00
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
GetRenderer(j++).Set(this, ps, true);
|
2020-08-20 03:42:16 +08:00
|
|
|
}
|
2020-02-12 20:38:06 +08:00
|
|
|
}
|
2020-08-20 03:42:16 +08:00
|
|
|
}
|
|
|
|
|
2022-06-11 21:32:14 +08:00
|
|
|
internal void UpdateTransformScale()
|
2020-09-14 17:29:16 +08:00
|
|
|
{
|
2024-06-18 16:13:35 +08:00
|
|
|
_tracker.Clear();
|
2023-11-07 10:42:16 +08:00
|
|
|
canvasScale = canvas.rootCanvas.transform.localScale.Inverse();
|
2023-08-15 20:56:09 +08:00
|
|
|
parentScale = transform.parent.lossyScale;
|
2024-06-18 16:13:35 +08:00
|
|
|
if (autoScalingMode != AutoScalingMode.Transform)
|
|
|
|
{
|
|
|
|
if (_isScaleStored)
|
|
|
|
{
|
|
|
|
transform.localScale = _storedScale;
|
|
|
|
}
|
|
|
|
|
|
|
|
_isScaleStored = false;
|
|
|
|
return;
|
|
|
|
}
|
2023-08-15 20:56:09 +08:00
|
|
|
|
2024-06-18 16:13:35 +08:00
|
|
|
var currentScale = transform.localScale;
|
2024-06-26 22:13:19 +08:00
|
|
|
if (!_isScaleStored)
|
|
|
|
{
|
|
|
|
_storedScale = currentScale.IsVisible() ? currentScale : Vector3.one;
|
|
|
|
_isScaleStored = true;
|
|
|
|
}
|
|
|
|
|
2024-06-18 16:13:35 +08:00
|
|
|
_tracker.Add(this, rectTransform, DrivenTransformProperties.Scale);
|
2023-08-15 20:56:09 +08:00
|
|
|
var newScale = parentScale.Inverse();
|
2024-06-18 16:13:35 +08:00
|
|
|
if (currentScale != newScale)
|
2020-09-14 17:29:16 +08:00
|
|
|
{
|
2022-06-08 11:54:11 +08:00
|
|
|
transform.localScale = newScale;
|
2020-09-14 17:29:16 +08:00
|
|
|
}
|
2022-06-11 21:32:14 +08:00
|
|
|
}
|
2020-08-29 02:55:46 +08:00
|
|
|
|
2022-06-11 21:32:14 +08:00
|
|
|
internal void UpdateRenderers()
|
|
|
|
{
|
2022-06-17 12:35:19 +08:00
|
|
|
if (!isActiveAndEnabled) return;
|
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
for (var i = 0; i < _renderers.Count; i++)
|
2022-07-01 14:55:59 +08:00
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
var r = _renderers[i];
|
2024-06-27 10:38:28 +08:00
|
|
|
if (r) continue;
|
|
|
|
|
|
|
|
RefreshParticles(particles);
|
|
|
|
break;
|
2022-07-01 14:55:59 +08:00
|
|
|
}
|
|
|
|
|
2022-06-08 11:54:11 +08:00
|
|
|
var bakeCamera = GetBakeCamera();
|
2023-08-17 08:43:02 +08:00
|
|
|
for (var i = 0; i < _renderers.Count; i++)
|
2020-08-29 02:55:46 +08:00
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
var r = _renderers[i];
|
|
|
|
if (!r) continue;
|
2024-06-27 10:38:28 +08:00
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
r.UpdateMesh(bakeCamera);
|
2020-08-29 02:55:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-14 12:27:54 +08:00
|
|
|
internal void ResetGroupId()
|
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
_groupId = m_GroupId == m_GroupMaxId
|
|
|
|
? m_GroupId
|
|
|
|
: Random.Range(m_GroupId, m_GroupMaxId + 1);
|
2020-02-12 20:38:06 +08:00
|
|
|
}
|
2019-02-26 10:26:56 +08:00
|
|
|
|
2022-06-08 11:54:11 +08:00
|
|
|
protected override void UpdateMaterial()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-02-12 20:38:06 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Call to update the geometry of the Graphic onto the CanvasRenderer.
|
|
|
|
/// </summary>
|
|
|
|
protected override void UpdateGeometry()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-06-08 11:54:11 +08:00
|
|
|
private void UpdateRendererMaterial()
|
2020-02-12 20:38:06 +08:00
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
for (var i = 0; i < _renderers.Count; i++)
|
2020-02-12 20:38:06 +08:00
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
var r = _renderers[i];
|
|
|
|
if (!r) continue;
|
|
|
|
r.maskable = maskable;
|
|
|
|
r.SetMaterialDirty();
|
2020-02-12 20:38:06 +08:00
|
|
|
}
|
2020-08-12 22:19:08 +08:00
|
|
|
}
|
2020-08-28 15:50:13 +08:00
|
|
|
|
2022-06-11 21:32:14 +08:00
|
|
|
internal UIParticleRenderer GetRenderer(int index)
|
2020-10-04 22:26:53 +08:00
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
if (_renderers.Count <= index)
|
2022-06-08 11:54:11 +08:00
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
_renderers.Add(UIParticleRenderer.AddRenderer(this, index));
|
2022-06-08 11:54:11 +08:00
|
|
|
}
|
2023-08-17 08:43:02 +08:00
|
|
|
|
|
|
|
if (!_renderers[index])
|
2022-07-01 14:55:59 +08:00
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
_renderers[index] = UIParticleRenderer.AddRenderer(this, index);
|
2022-07-01 14:55:59 +08:00
|
|
|
}
|
2023-08-17 08:43:02 +08:00
|
|
|
|
|
|
|
return _renderers[index];
|
2020-10-04 22:26:53 +08:00
|
|
|
}
|
|
|
|
|
2022-06-08 11:54:11 +08:00
|
|
|
private Camera GetBakeCamera()
|
2020-08-28 15:50:13 +08:00
|
|
|
{
|
2022-06-08 11:54:11 +08:00
|
|
|
if (!canvas) return Camera.main;
|
2024-06-26 22:13:09 +08:00
|
|
|
if (!useCustomView && canvas.renderMode != RenderMode.ScreenSpaceOverlay && canvas.rootCanvas.worldCamera)
|
|
|
|
{
|
|
|
|
return canvas.rootCanvas.worldCamera;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_bakeCamera)
|
|
|
|
{
|
|
|
|
_bakeCamera.orthographicSize = useCustomView ? customViewSize : 10;
|
|
|
|
return _bakeCamera;
|
|
|
|
}
|
2020-08-28 15:50:13 +08:00
|
|
|
|
2024-06-20 11:51:02 +08:00
|
|
|
// Find existing baking camera.
|
|
|
|
var childCount = transform.childCount;
|
|
|
|
for (var i = 0; i < childCount; i++)
|
2023-08-17 08:43:02 +08:00
|
|
|
{
|
2024-06-20 11:51:02 +08:00
|
|
|
if (transform.GetChild(i).TryGetComponent<Camera>(out var cam)
|
|
|
|
&& cam.name == "[generated] UIParticle BakingCamera")
|
2023-08-18 16:23:13 +08:00
|
|
|
{
|
2024-06-20 11:51:02 +08:00
|
|
|
_bakeCamera = cam;
|
|
|
|
break;
|
2023-08-18 16:23:13 +08:00
|
|
|
}
|
2024-06-20 11:51:02 +08:00
|
|
|
}
|
2023-08-18 16:20:12 +08:00
|
|
|
|
2024-06-20 11:51:02 +08:00
|
|
|
// Create baking camera.
|
|
|
|
if (!_bakeCamera)
|
|
|
|
{
|
2024-06-26 18:17:05 +08:00
|
|
|
var go = new GameObject("[generated] UIParticle BakingCamera");
|
2024-06-20 11:51:02 +08:00
|
|
|
go.SetActive(false);
|
|
|
|
go.transform.SetParent(transform, false);
|
|
|
|
_bakeCamera = go.AddComponent<Camera>();
|
2020-10-04 22:26:53 +08:00
|
|
|
}
|
|
|
|
|
2024-06-20 11:51:02 +08:00
|
|
|
// Setup baking camera.
|
|
|
|
_bakeCamera.enabled = false;
|
2024-06-26 22:13:09 +08:00
|
|
|
_bakeCamera.orthographicSize = useCustomView ? customViewSize : 10;
|
2024-06-20 11:51:02 +08:00
|
|
|
_bakeCamera.transform.SetPositionAndRotation(new Vector3(0, 0, -1000), Quaternion.identity);
|
|
|
|
_bakeCamera.orthographic = true;
|
|
|
|
_bakeCamera.farClipPlane = 2000f;
|
|
|
|
_bakeCamera.clearFlags = CameraClearFlags.Nothing;
|
|
|
|
_bakeCamera.cullingMask = 0; // Nothing
|
|
|
|
_bakeCamera.allowHDR = false;
|
|
|
|
_bakeCamera.allowMSAA = false;
|
|
|
|
_bakeCamera.renderingPath = RenderingPath.Forward;
|
|
|
|
_bakeCamera.useOcclusionCulling = false;
|
|
|
|
|
2024-06-26 18:17:05 +08:00
|
|
|
_bakeCamera.gameObject.SetActive(false);
|
|
|
|
_bakeCamera.gameObject.hideFlags = HideFlags.HideAndDontSave;
|
|
|
|
|
2024-06-20 11:51:02 +08:00
|
|
|
return _bakeCamera;
|
2020-08-28 15:50:13 +08:00
|
|
|
}
|
2020-02-12 20:38:06 +08:00
|
|
|
}
|
2020-04-30 11:28:48 +08:00
|
|
|
}
|