Compare commits

..

4 Commits

Author SHA1 Message Date
semantic-release-bot
db00e26221 chore(release): 5.0.0-preview.11 [skip ci]
# [5.0.0-preview.11](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v5.0.0-preview.10...v5.0.0-preview.11) (2024-09-29)

### Features

* change the default value of `UIParticle.scale` from `10` to `1` ([4e188dd](4e188dd39e))
* UIParticle no longer inherits from MaskableGraphic ([52eb28c](52eb28cdaf))

### BREAKING CHANGES

* Some members inherited from MaskableGraphic will no longer be available.
2024-09-29 19:21:37 +00:00
mob-sakai
6dde9e5399 feat: change the default value of UIParticle.scale from 10 to 1 2024-09-30 04:20:36 +09:00
mob-sakai
9f31c57f59 feat: UIParticle no longer inherits from MaskableGraphic
BREAKING CHANGE: Some members inherited from MaskableGraphic will no longer be available.
2024-09-30 03:51:33 +09:00
mob-sakai
81b4489329 docs: update documents 2024-09-30 03:51:33 +09:00
20 changed files with 144 additions and 437 deletions

View File

@@ -1,52 +1,15 @@
# [4.11.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.7...v4.11.0) (2025-02-21)
# [5.0.0-preview.11](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v5.0.0-preview.10...v5.0.0-preview.11) (2024-09-29)
### Features
* add 'TimeScaleMultiplier' option ([925af0b](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/925af0b6046f65f23a778f67cefa8ff9cbedb513))
## [4.10.7](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.6...v4.10.7) (2025-01-14)
* change the default value of `UIParticle.scale` from `10` to `1` ([4e188dd](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/4e188dd39ee32dd1339066a6946e43ba3580c324))
* UIParticle no longer inherits from MaskableGraphic ([52eb28c](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/52eb28cdafe7c9009d5a4b76978e002798440e8d))
### Bug Fixes
### BREAKING CHANGES
* editor crashed on exit play mode (editor, windows) ([47ee45c](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/47ee45cbbe651a8f87ca2b8a3948f8b88db8211e)), closes [#351](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/351)
## [4.10.6](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.5...v4.10.6) (2025-01-03)
### Bug Fixes
* sub-emitter particles may not render correctly in certain scenarios ([8276684](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/8276684c3b1646f0490ed64557547ba15281664a)), closes [#348](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/348)
* sub-emitter's `inherit velocity` module doubles at runtime ([67de3d1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/67de3d1bd3e16dc9b564625cb990c53d75769506)), closes [#349](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/349)
## [4.10.5](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.4...v4.10.5) (2024-12-23)
### Bug Fixes
* '3D' scale toggle in the inspector does not keep on reload ([934f4b8](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/934f4b8f1c61f8ff20228d0ebcea9f636a3758ed)), closes [#346](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/346)
## [4.10.4](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.3...v4.10.4) (2024-12-19)
### Bug Fixes
* rendering issues when playing with opening a prefab stage ([95235a9](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/95235a929b82cf681365ed6eba837d857f83e3d2)), closes [#345](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/345)
## [4.10.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.2...v4.10.3) (2024-11-20)
### Bug Fixes
* if not configured as a preloaded asset, the project settings asset will be regenerated ([abe0948](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/abe09485f65dd4efd18e74675e752e0213bdf3be)), closes [#342](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/342)
## [4.10.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.1...v4.10.2) (2024-11-01)
### Bug Fixes
* trail incorrect offset ([afe00a1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/afe00a1dde80eb1c0a7bb668b75f4c3733d3fa43)), closes [#335](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/335)
* Some members inherited from MaskableGraphic will no longer be available.
## [4.10.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.0...v4.10.1) (2024-09-29)

View File

@@ -2,7 +2,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.UI;
using UnityEditorInternal;
using UnityEngine;
using UnityEngine.Profiling;
@@ -26,13 +25,8 @@ namespace Coffee.UIExtensions
{
[CustomEditor(typeof(UIParticle))]
[CanEditMultipleObjects]
internal class UIParticleEditor : GraphicEditor
internal class UIParticleEditor : Editor
{
internal class State : ScriptableSingleton<State>
{
public bool is3DScaleMode;
}
//################################
// Constant or Static Members.
//################################
@@ -51,6 +45,7 @@ namespace Coffee.UIExtensions
private static readonly GUIContent s_ContentPrimary = new GUIContent("Primary");
private static readonly Regex s_RegexBuiltInGuid = new Regex(@"^0{16}.0{15}$", RegexOptions.Compiled);
private static readonly List<Material> s_TempMaterials = new List<Material>();
private static bool s_XYZMode;
private SerializedProperty _maskable;
private SerializedProperty _scale3D;
@@ -62,10 +57,8 @@ namespace Coffee.UIExtensions
private SerializedProperty _autoScalingMode;
private SerializedProperty _useCustomView;
private SerializedProperty _customViewSize;
private SerializedProperty _timeScaleMultiplier;
private ReorderableList _ro;
private bool _showMax;
private bool _is3DScaleMode;
private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>();
#if UNITY_2018 || UNITY_2019
@@ -87,10 +80,8 @@ namespace Coffee.UIExtensions
/// <summary>
/// This function is called when the object becomes enabled and active.
/// </summary>
protected override void OnEnable()
private void OnEnable()
{
base.OnEnable();
_maskable = serializedObject.FindProperty("m_Maskable");
_scale3D = serializedObject.FindProperty("m_Scale3D");
_animatableProperties = serializedObject.FindProperty("m_AnimatableProperties");
@@ -101,7 +92,6 @@ namespace Coffee.UIExtensions
_autoScalingMode = serializedObject.FindProperty("m_AutoScalingMode");
_useCustomView = serializedObject.FindProperty("m_UseCustomView");
_customViewSize = serializedObject.FindProperty("m_CustomViewSize");
_timeScaleMultiplier = serializedObject.FindProperty("m_TimeScaleMultiplier");
var sp = serializedObject.FindProperty("m_Particles");
_ro = new ReorderableList(sp.serializedObject, sp, true, true, true, true)
@@ -170,19 +160,6 @@ namespace Coffee.UIExtensions
uip.RefreshParticles(uip.particles);
}
}
// Initialize 3D scale mode.
_is3DScaleMode = State.instance.is3DScaleMode;
if (!_is3DScaleMode)
{
var x = _scale3D.FindPropertyRelative("x");
var y = _scale3D.FindPropertyRelative("y");
var z = _scale3D.FindPropertyRelative("z");
_is3DScaleMode = !Mathf.Approximately(x.floatValue, y.floatValue) ||
!Mathf.Approximately(y.floatValue, z.floatValue) ||
y.hasMultipleDifferentValues ||
z.hasMultipleDifferentValues;
}
}
/// <summary>
@@ -201,11 +178,7 @@ namespace Coffee.UIExtensions
// Scale
EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4);
if (DrawFloatOrVector3Field(_scale3D, _is3DScaleMode) != _is3DScaleMode)
{
State.instance.is3DScaleMode = _is3DScaleMode = !_is3DScaleMode;
}
s_XYZMode = DrawFloatOrVector3Field(_scale3D, s_XYZMode);
EditorGUI.EndDisabledGroup();
// AnimatableProperties
@@ -246,9 +219,6 @@ namespace Coffee.UIExtensions
_customViewSize.floatValue = Mathf.Max(0.1f, _customViewSize.floatValue);
}
// Time Scale Multiplier
EditorGUILayout.PropertyField(_timeScaleMultiplier);
// Target ParticleSystems.
EditorGUI.BeginChangeCheck();
_ro.DoLayoutList();
@@ -464,9 +434,11 @@ namespace Coffee.UIExtensions
{
if (!p || (ignoreCurrent && target == p)) return;
var cr = p.canvasRenderer;
DestroyImmediate(p);
DestroyImmediate(cr);
Misc.DestroyImmediate(p);
if (p.TryGetComponent<CanvasRenderer>(out var cr))
{
Misc.DestroyImmediate(cr);
}
#if UNITY_2018_3_OR_NEWER
var stage = PrefabStageUtility.GetCurrentPrefabStage();

View File

@@ -11,7 +11,7 @@
[![](https://img.shields.io/github/watchers/mob-sakai/ParticleEffectForUGUI.svg?style=social&label=Watch)](https://github.com/mob-sakai/ParticleEffectForUGUI/subscription)
[![](https://img.shields.io/twitter/follow/mob_sakai.svg?label=Follow&style=social)](https://twitter.com/intent/follow?screen_name=mob_sakai)
<< [📝 Description](#-description-) | [📌 Key Features](#-key-features) | [🎮 Demo](#-demo) | [⚙ Installation](#-installation) | [🚀 Usage](#-usage) | [🛠 Development Note](#-development-note) | [🤝 Contributing](#-contributing) >>
<< [📝 Description](#-description-) | [📌 Key Features](#-key-features) | [🎮 Demo](#-demo) | [⚙ Installation](#-installation) | [🔄 Upgrading to 5.x](#-upgrading-from-3x4x-to-5x) | [🚀 Usage](#-usage) | [🛠 Development Note](#-development-note) | [🤝 Contributing](#-contributing) >>
## 📝 Description <!-- omit in toc -->
@@ -27,6 +27,8 @@ You can render, mask, and sort your `ParticleSystems` for UI without the need fo
- [Install via UPM (with Package Manager UI)](#install-via-upm-with-package-manager-ui)
- [Install via UPM (Manually)](#install-via-upm-manually)
- [Install as Embedded Package](#install-as-embedded-package)
- [🔄 Upgrading from 3.x/4.x to 5.x](#-upgrading-from-3x4x-to-5x)
- [Breaking Changes](#breaking-changes)
- [🚀 Usage](#-usage)
- [Component: UIParticle](#component-uiparticle)
- [Basic Usage](#basic-usage)
@@ -152,6 +154,17 @@ _This package requires **Unity 2018.3 or later**._
<br><br>
## 🔄 Upgrading from 3.x/4.x to 5.x
### Breaking Changes
- The default value of `UIParticle.scale` has been changed from `10` to `1`.
- `UIParticle` no longer inherits from `MaskableGraphic`.
- Add project settings for UIParticle
- enableLinearToGamma: Enables LinearToGamma during mesh baking
<br><br>
## 🚀 Usage
### Component: UIParticle

Binary file not shown.

View File

@@ -1,33 +0,0 @@
fileFormatVersion: 2
guid: 4d73b3825bf044d418ae21bb331d3902
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 1
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -18,10 +18,10 @@ namespace Coffee.UIParticleInternal
public static T[] GetComponentsInChildren<T>(this Component self, int depth)
where T : Component
{
var results = InternalListPool<T>.Rent();
var results = ListPool<T>.Rent();
self.GetComponentsInChildren_Internal(results, depth);
var array = results.ToArray();
InternalListPool<T>.Return(ref results);
ListPool<T>.Return(ref results);
return array;
}
@@ -134,35 +134,6 @@ namespace Coffee.UIParticleInternal
Profiler.EndSample();
}
/// <summary>
/// Add a component of a specific type to the children of a GameObject.
/// </summary>
public static void AddComponentOnChildren<T>(this Component self, bool includeSelf)
where T : Component
{
if (self == null) return;
Profiler.BeginSample("(COF)[ComponentExt] AddComponentOnChildren > Self");
if (includeSelf && !self.TryGetComponent<T>(out _))
{
self.gameObject.AddComponent<T>();
}
Profiler.EndSample();
Profiler.BeginSample("(COF)[ComponentExt] AddComponentOnChildren > Child");
var childCount = self.transform.childCount;
for (var i = 0; i < childCount; i++)
{
var child = self.transform.GetChild(i);
if (child.TryGetComponent<T>(out _)) continue;
child.gameObject.AddComponent<T>();
}
Profiler.EndSample();
}
#if !UNITY_2021_2_OR_NEWER && !UNITY_2020_3_45 && !UNITY_2020_3_46 && !UNITY_2020_3_47 && !UNITY_2020_3_48
public static T GetComponentInParent<T>(this Component self, bool includeInactive) where T : Component
{

View File

@@ -1,27 +1,11 @@
using System;
using System.Diagnostics;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
#if UNITY_EDITOR && UNITY_2021_2_OR_NEWER
using UnityEditor.SceneManagement;
#elif UNITY_EDITOR
using UnityEditor.Experimental.SceneManagement;
#endif
namespace Coffee.UIParticleInternal
{
internal static class Misc
{
public static T[] FindObjectsOfType<T>() where T : Object
{
#if UNITY_2023_1_OR_NEWER
return Object.FindObjectsByType<T>(FindObjectsInactive.Include, FindObjectsSortMode.None);
#else
return Object.FindObjectsOfType<T>();
#endif
}
public static void Destroy(Object obj)
{
if (!obj) return;
@@ -60,17 +44,5 @@ namespace Coffee.UIParticleInternal
EditorUtility.SetDirty(obj);
#endif
}
#if UNITY_EDITOR
public static T[] GetAllComponentsInPrefabStage<T>() where T : Component
{
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
if (prefabStage == null) return Array.Empty<T>();
return prefabStage.prefabContentsRoot.GetComponentsInChildren<T>(true);
}
public static bool isBatchOrBuilding => Application.isBatchMode || BuildPipeline.isBuildingPlayer;
#endif
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 182319ecc315e4858b119764af0fbcb0
guid: 39ed6a6b0a72e482488bd298b2ae762e
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -17,15 +17,11 @@ namespace Coffee.UIParticleInternal
Type.GetType("UnityEditor.Experimental.U2D.SpriteEditorExtension, UnityEditor")
?? Type.GetType("UnityEditor.U2D.SpriteEditorExtension, UnityEditor");
private static readonly Func<Sprite, Texture2D> s_GetActiveAtlasTextureMethod =
(Func<Sprite, Texture2D>)Delegate.CreateDelegate(typeof(Func<Sprite, Texture2D>),
s_SpriteEditorExtensionType
.GetMethod("GetActiveAtlasTexture", BindingFlags.Static | BindingFlags.NonPublic));
private static readonly MethodInfo s_GetActiveAtlasTextureMethod = s_SpriteEditorExtensionType
.GetMethod("GetActiveAtlasTexture", BindingFlags.Static | BindingFlags.NonPublic);
private static readonly Func<Sprite, SpriteAtlas> s_GetActiveAtlasMethod =
(Func<Sprite, SpriteAtlas>)Delegate.CreateDelegate(typeof(Func<Sprite, SpriteAtlas>),
s_SpriteEditorExtensionType
.GetMethod("GetActiveAtlas", BindingFlags.Static | BindingFlags.NonPublic));
private static readonly MethodInfo s_GetActiveAtlasMethod = s_SpriteEditorExtensionType
.GetMethod("GetActiveAtlas", BindingFlags.Static | BindingFlags.NonPublic);
/// <summary>
/// Get the actual texture of a sprite in play mode or edit mode.
@@ -34,7 +30,9 @@ namespace Coffee.UIParticleInternal
{
if (!self) return null;
var ret = s_GetActiveAtlasTextureMethod(self);
if (Application.isPlaying) return self.texture;
var ret = s_GetActiveAtlasTextureMethod.Invoke(null, new object[] { self }) as Texture2D;
return ret ? ret : self.texture;
}
@@ -45,7 +43,7 @@ namespace Coffee.UIParticleInternal
{
if (!self) return null;
return s_GetActiveAtlasMethod(self);
return s_GetActiveAtlasMethod.Invoke(null, new object[] { self }) as SpriteAtlas;
}
#else
/// <summary>

View File

@@ -1,9 +1,9 @@
using System;
using System.Linq;
using System.Reflection;
using UnityEngine;
using Object = UnityEngine.Object;
#if UNITY_EDITOR
using System.IO;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
@@ -14,14 +14,6 @@ namespace Coffee.UIParticleInternal
public abstract class PreloadedProjectSettings : ScriptableObject
#if UNITY_EDITOR
{
private class Postprocessor : AssetPostprocessor
{
private static void OnPostprocessAllAssets(string[] _, string[] __, string[] ___, string[] ____)
{
Initialize();
}
}
private class PreprocessBuildWithReport : IPreprocessBuildWithReport
{
int IOrderedCallback.callbackOrder => 0;
@@ -32,32 +24,32 @@ namespace Coffee.UIParticleInternal
}
}
[InitializeOnLoadMethod]
[InitializeOnEnterPlayMode]
private static void Initialize()
{
const BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
foreach (var t in TypeCache.GetTypesDerivedFrom(typeof(PreloadedProjectSettings<>)))
{
var defaultSettings = GetDefaultSettings(t);
if (!defaultSettings)
{
// When create a new instance, automatically set it as default settings.
defaultSettings = CreateInstance(t) as PreloadedProjectSettings;
SetDefaultSettings(defaultSettings);
defaultSettings = t.GetProperty("instance", flags)
?.GetValue(null, null) as PreloadedProjectSettings;
}
else if (GetPreloadedSettings(t).Length != 1)
{
SetDefaultSettings(defaultSettings);
}
if (defaultSettings)
{
defaultSettings.OnInitialize();
}
}
EditorApplication.QueuePlayerLoopUpdate();
}
protected static string GetDefaultName(Type type, bool nicify)
{
var typeName = type.Name;
var typeName = type.Name.Replace("ProjectSettings", "");
return nicify
? ObjectNames.NicifyVariableName(typeName)
: typeName;
@@ -82,7 +74,6 @@ namespace Coffee.UIParticleInternal
protected static void SetDefaultSettings(PreloadedProjectSettings asset)
{
if (!asset) return;
var type = asset.GetType();
if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(asset)))
{
@@ -93,11 +84,7 @@ namespace Coffee.UIParticleInternal
var assetPath = $"Assets/ProjectSettings/{GetDefaultName(type, false)}.asset";
assetPath = AssetDatabase.GenerateUniqueAssetPath(assetPath);
if (!File.Exists(assetPath))
{
AssetDatabase.CreateAsset(asset, assetPath);
asset.OnCreateAsset();
}
AssetDatabase.CreateAsset(asset, assetPath);
}
var preloadedAssets = PlayerSettings.GetPreloadedAssets();
@@ -111,14 +98,6 @@ namespace Coffee.UIParticleInternal
AssetDatabase.Refresh();
}
protected virtual void OnCreateAsset()
{
}
protected virtual void OnInitialize()
{
}
}
#else
{
@@ -133,8 +112,6 @@ namespace Coffee.UIParticleInternal
#if UNITY_EDITOR
private string _jsonText;
public static bool hasInstance => s_Instance;
public static T instance
{
get

View File

@@ -10,9 +10,8 @@ namespace Coffee.UIParticleInternal
/// </summary>
internal class FastActionBase<T>
{
private static readonly InternalObjectPool<LinkedListNode<T>> s_NodePool =
new InternalObjectPool<LinkedListNode<T>>(() => new LinkedListNode<T>(default), _ => true,
x => x.Value = default);
private static readonly ObjectPool<LinkedListNode<T>> s_NodePool =
new ObjectPool<LinkedListNode<T>>(() => new LinkedListNode<T>(default), _ => true, x => x.Value = default);
private readonly LinkedList<T> _delegates = new LinkedList<T>();

View File

@@ -15,7 +15,7 @@ namespace Coffee.UIParticleInternal
#if UNITY_EDITOR
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
public static void Clear()
private static void Clear()
{
s_Repository.Clear();
}

View File

@@ -6,58 +6,15 @@ namespace Coffee.UIParticleInternal
/// <summary>
/// Object pool.
/// </summary>
internal class InternalObjectPool<T> where T : class
internal class ObjectPool<T>
{
#if UNITY_2021_1_OR_NEWER
private readonly Predicate<T> _onValid; // Delegate for checking if instances are valid
private readonly UnityEngine.Pool.ObjectPool<T> _pool;
public InternalObjectPool(Func<T> onCreate, Predicate<T> onValid, Action<T> onReturn)
{
_pool = new UnityEngine.Pool.ObjectPool<T>(onCreate, null, onReturn);
_onValid = onValid;
}
/// <summary>
/// Rent an instance from the pool.
/// When you no longer need it, return it with <see cref="Return" />.
/// </summary>
public T Rent()
{
while (0 < _pool.CountInactive)
{
var instance = _pool.Get();
if (_onValid(instance))
{
return instance;
}
}
// If there are no instances in the pool, create a new one.
Logging.Log(this, $"A new instance is created (pooled: {_pool.CountInactive}, created: {_pool.CountAll}).");
return _pool.Get();
}
/// <summary>
/// Return an instance to the pool and assign null.
/// Be sure to return the instance obtained with <see cref="Rent" /> with this method.
/// </summary>
public void Return(ref T instance)
{
if (instance == null) return; // Ignore if already pooled or null.
_pool.Release(instance);
Logging.Log(this, $"An instance is released (pooled: {_pool.CountInactive}, created: {_pool.CountAll}).");
instance = default; // Set the reference to null.
}
#else
private readonly Func<T> _onCreate; // Delegate for creating instances
private readonly Action<T> _onReturn; // Delegate for returning instances to the pool
private readonly Predicate<T> _onValid; // Delegate for checking if instances are valid
private readonly Stack<T> _pool = new Stack<T>(32); // Object pool
private int _count; // Total count of created instances
public InternalObjectPool(Func<T> onCreate, Predicate<T> onValid, Action<T> onReturn)
public ObjectPool(Func<T> onCreate, Predicate<T> onValid, Action<T> onReturn)
{
_onCreate = onCreate;
_onValid = onValid;
@@ -97,40 +54,15 @@ namespace Coffee.UIParticleInternal
Logging.Log(this, $"An instance is released (pooled: {_pool.Count}, created: {_count}).");
instance = default; // Set the reference to null.
}
#endif
}
/// <summary>
/// Object pool for <see cref="List{T}" />.
/// </summary>
internal static class InternalListPool<T>
internal static class ListPool<T>
{
#if UNITY_2021_1_OR_NEWER
/// <summary>
/// Rent an instance from the pool.
/// When you no longer need it, return it with <see cref="Return" />.
/// </summary>
public static List<T> Rent()
{
return UnityEngine.Pool.ListPool<T>.Get();
}
/// <summary>
/// Return an instance to the pool and assign null.
/// Be sure to return the instance obtained with <see cref="Rent" /> with this method.
/// </summary>
public static void Return(ref List<T> toRelease)
{
if (toRelease != null)
{
UnityEngine.Pool.ListPool<T>.Release(toRelease);
}
toRelease = null;
}
#else
private static readonly InternalObjectPool<List<T>> s_ListPool =
new InternalObjectPool<List<T>>(() => new List<T>(), _ => true, x => x.Clear());
private static readonly ObjectPool<List<T>> s_ListPool =
new ObjectPool<List<T>>(() => new List<T>(), _ => true, x => x.Clear());
/// <summary>
/// Rent an instance from the pool.
@@ -149,6 +81,5 @@ namespace Coffee.UIParticleInternal
{
s_ListPool.Return(ref toRelease);
}
#endif
}
}

View File

@@ -14,8 +14,6 @@ namespace Coffee.UIParticleInternal
private static readonly FastAction s_AfterCanvasRebuildAction = new FastAction();
private static readonly FastAction s_LateAfterCanvasRebuildAction = new FastAction();
private static readonly FastAction s_BeforeCanvasRebuildAction = new FastAction();
private static readonly FastAction s_OnScreenSizeChangedAction = new FastAction();
private static Vector2Int s_LastScreenSize;
static UIExtraCallbacks()
{
@@ -50,15 +48,6 @@ namespace Coffee.UIParticleInternal
remove => s_AfterCanvasRebuildAction.Remove(value);
}
/// <summary>
/// Event that occurs when the screen size changes.
/// </summary>
public static event Action onScreenSizeChanged
{
add => s_OnScreenSizeChangedAction.Add(value);
remove => s_OnScreenSizeChangedAction.Remove(value);
}
/// <summary>
/// Initializes the UIExtraCallbacks to ensure proper event handling.
/// </summary>
@@ -88,17 +77,6 @@ namespace Coffee.UIParticleInternal
/// </summary>
private static void OnBeforeCanvasRebuild()
{
var screenSize = new Vector2Int(Screen.width, Screen.height);
if (s_LastScreenSize != screenSize)
{
if (s_LastScreenSize != default)
{
s_OnScreenSizeChangedAction.Invoke();
}
s_LastScreenSize = screenSize;
}
s_BeforeCanvasRebuildAction.Invoke();
InitializeAfterCanvasRebuild();
}

View File

@@ -3,14 +3,12 @@ using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Coffee.UIParticleInternal;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Rendering;
using UnityEngine.Serialization;
using UnityEngine.UI;
using Random = UnityEngine.Random;
[assembly: InternalsVisibleTo("Coffee.UIParticle.Editor")]
[assembly: InternalsVisibleTo("Coffee.UIParticle.PerformanceDemo")]
[assembly: InternalsVisibleTo("Coffee.UIParticle.Demo")]
namespace Coffee.UIExtensions
{
@@ -20,7 +18,7 @@ namespace Coffee.UIExtensions
[ExecuteAlways]
[RequireComponent(typeof(RectTransform))]
[RequireComponent(typeof(CanvasRenderer))]
public class UIParticle : MaskableGraphic, ISerializationCallbackReceiver
public class UIParticle : UIBehaviour, ISerializationCallbackReceiver
{
public enum AutoScalingMode
{
@@ -62,7 +60,7 @@ namespace Coffee.UIExtensions
[Tooltip("Scale the rendering particles. When the `3D` toggle is enabled, 3D scale (x, y, z) is supported.")]
[SerializeField]
private Vector3 m_Scale3D = new Vector3(10, 10, 10);
private Vector3 m_Scale3D = new Vector3(1, 1, 1);
[Tooltip("If you want to update material properties (e.g. _MainTex_ST, _Color) in AnimationClip, " +
"use this to mark as animatable.")]
@@ -120,23 +118,47 @@ namespace Coffee.UIExtensions
private float m_CustomViewSize = 10;
[SerializeField]
[Tooltip("Time scale multiplier.")]
private float m_TimeScaleMultiplier = 1;
private bool m_Maskable = true;
private readonly List<UIParticleRenderer> _renderers = new List<UIParticleRenderer>();
private Camera _bakeCamera;
private Canvas _canvas;
private int _groupId;
private bool _isScaleStored;
private Vector3 _storedScale;
private DrivenRectTransformTracker _tracker;
/// <summary>
/// Should this graphic be considered a target for ray-casting?
/// </summary>
public override bool raycastTarget
public RectTransform rectTransform => transform as RectTransform;
public Canvas canvas
{
get => false;
set { }
get
{
if (_canvas) return _canvas;
var tr = transform;
while (tr && !_canvas)
{
if (tr.TryGetComponent(out _canvas)) return _canvas;
tr = tr.parent;
}
return null;
}
}
/// <summary>
/// Does this graphic allow masking.
/// </summary>
public bool maskable
{
get => m_Maskable;
set
{
if (value == m_Maskable) return;
m_Maskable = value;
UpdateRendererMaterial();
}
}
/// <summary>
@@ -261,15 +283,6 @@ namespace Coffee.UIExtensions
set => m_CustomViewSize = Mathf.Max(0.1f, value);
}
/// <summary>
/// Time scale multiplier.
/// </summary>
public float timeScaleMultiplier
{
get => m_TimeScaleMultiplier;
set => m_TimeScaleMultiplier = value;
}
internal bool useMeshSharing => m_MeshSharing != MeshSharing.None;
internal bool isPrimary =>
@@ -322,15 +335,15 @@ namespace Coffee.UIExtensions
public Vector3 parentScale { get; private set; }
public Vector3 canvasScale { get; private set; }
private Vector3 canvasScale { get; set; }
protected override void OnEnable()
{
_isScaleStored = false;
ResetGroupId();
UIParticleUpdater.Register(this);
RegisterDirtyMaterialCallback(UpdateRendererMaterial);
//
if (0 < particles.Count)
{
RefreshParticles(particles);
@@ -340,7 +353,7 @@ namespace Coffee.UIExtensions
RefreshParticles();
}
base.OnEnable();
UpdateRendererMaterial();
}
/// <summary>
@@ -357,9 +370,15 @@ namespace Coffee.UIExtensions
_isScaleStored = false;
UIParticleUpdater.Unregister(this);
_renderers.ForEach(r => r.Reset());
UnregisterDirtyMaterialCallback(UpdateRendererMaterial);
_canvas = null;
}
base.OnDisable();
/// <summary>
/// Called when the state of the parent Canvas is changed.
/// </summary>
protected override void OnCanvasHierarchyChanged()
{
_canvas = null;
}
/// <summary>
@@ -369,6 +388,14 @@ namespace Coffee.UIExtensions
{
}
/// <summary>
/// This function is called when a direct or indirect parent of the transform of the GameObject has changed.
/// </summary>
protected override void OnTransformParentChanged()
{
_canvas = null;
}
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
}
@@ -590,14 +617,12 @@ namespace Coffee.UIExtensions
{
var ps = particleSystems[i];
if (!ps) continue;
var mainEmitter = ps.GetMainEmitter(particleSystems);
GetRenderer(j++).Set(this, ps, false, mainEmitter);
GetRenderer(j++).Set(this, ps, false);
// If the trail is enabled, set it additionally.
if (ps.trails.enabled)
{
GetRenderer(j++).Set(this, ps, true, mainEmitter);
GetRenderer(j++).Set(this, ps, true);
}
}
}
@@ -663,17 +688,6 @@ namespace Coffee.UIExtensions
: Random.Range(m_GroupId, m_GroupMaxId + 1);
}
protected override void UpdateMaterial()
{
}
/// <summary>
/// Call to update the geometry of the Graphic onto the CanvasRenderer.
/// </summary>
protected override void UpdateGeometry()
{
}
private void UpdateRendererMaterial()
{
for (var i = 0; i < _renderers.Count; i++)

View File

@@ -40,7 +40,6 @@ namespace Coffee.UIExtensions
private Vector2Int _prevScreenSize;
private bool _preWarm;
private ParticleSystemRenderer _renderer;
private ParticleSystem _mainEmitter;
public override Texture mainTexture => _isTrail ? null : _particleSystem.GetTextureForSprite();
@@ -113,7 +112,6 @@ namespace Coffee.UIExtensions
_parent = null;
_particleSystem = null;
_renderer = null;
_mainEmitter = null;
if (0 <= index)
{
_index = index;
@@ -225,7 +223,7 @@ namespace Coffee.UIExtensions
return _modifiedMaterial;
}
public void Set(UIParticle parent, ParticleSystem ps, bool isTrail, ParticleSystem mainEmitter)
public void Set(UIParticle parent, ParticleSystem ps, bool isTrail)
{
_parent = parent;
maskable = parent.maskable;
@@ -248,7 +246,10 @@ namespace Coffee.UIExtensions
ps.TryGetComponent(out _renderer);
_renderer.enabled = false;
//_emitter = emitter;
_isTrail = isTrail;
_renderer.GetSharedMaterials(s_Materials);
material = s_Materials[isTrail ? 1 : 0];
s_Materials.Clear();
@@ -265,7 +266,6 @@ namespace Coffee.UIExtensions
_prevScreenSize = new Vector2Int(Screen.width, Screen.height);
_prevCanvasScale = canvas ? canvas.scaleFactor : 1f;
_delay = true;
_mainEmitter = mainEmitter;
canvasRenderer.SetTexture(null);
@@ -303,7 +303,7 @@ namespace Coffee.UIExtensions
// Simulate particles.
Profiler.BeginSample("[UIParticle] Bake Mesh > Simulate Particles");
if (!_isTrail && _parent.canSimulate && !_mainEmitter)
if (!_isTrail && _parent.canSimulate)
{
#if UNITY_EDITOR
if (!Application.isPlaying)
@@ -421,7 +421,7 @@ namespace Coffee.UIExtensions
workerMesh.LinearToGamma();
}
var components = InternalListPool<Component>.Rent();
var components = ListPool<Component>.Rent();
GetComponents(typeof(IMeshModifier), components);
for (var i = 0; i < components.Count; i++)
{
@@ -430,7 +430,7 @@ namespace Coffee.UIExtensions
#pragma warning restore CS0618 // Type or member is obsolete
}
InternalListPool<Component>.Return(ref components);
ListPool<Component>.Return(ref components);
}
Profiler.EndSample();
@@ -442,7 +442,7 @@ namespace Coffee.UIExtensions
// Get grouped renderers.
Profiler.BeginSample("[UIParticleRenderer] Set Mesh");
var renderers = InternalListPool<UIParticleRenderer>.Rent();
var renderers = ListPool<UIParticleRenderer>.Rent();
if (_parent.useMeshSharing)
{
UIParticleUpdater.GetGroupedRenderers(_parent.groupId, _index, renderers);
@@ -459,7 +459,7 @@ namespace Coffee.UIExtensions
r.canvasRenderer.SetMaterial(materialForRendering, 0);
}
InternalListPool<UIParticleRenderer>.Return(ref renderers);
ListPool<UIParticleRenderer>.Return(ref renderers);
if (_parent.canRender)
{
@@ -542,30 +542,6 @@ namespace Coffee.UIExtensions
return Matrix4x4.Translate(psPos)
* Matrix4x4.Scale(scale);
case ParticleSystemSimulationSpace.World:
if (_isTrail)
{
return Matrix4x4.Translate(psPos)
* Matrix4x4.Scale(scale)
* Matrix4x4.Translate(-psPos);
}
if (_mainEmitter)
{
if (_mainEmitter.IsLocalSpace())
{
return Matrix4x4.Translate(psPos)
* Matrix4x4.Scale(scale)
* Matrix4x4.Translate(-psPos);
}
else
{
psPos = _particleSystem.transform.position - _mainEmitter.transform.position;
return Matrix4x4.Translate(psPos)
* Matrix4x4.Scale(scale)
* Matrix4x4.Translate(-psPos);
}
}
return Matrix4x4.Scale(scale);
case ParticleSystemSimulationSpace.Custom:
return Matrix4x4.Translate(_particleSystem.main.customSimulationSpace.position.GetScaled(scale))
@@ -628,7 +604,6 @@ namespace Coffee.UIExtensions
: main.useUnscaledTime
? Time.unscaledDeltaTime
: Time.deltaTime;
deltaTime *= _parent.timeScaleMultiplier;
// Pre-warm:
if (0 < deltaTime && _preWarm)

View File

@@ -40,26 +40,13 @@ namespace Coffee.UIExtensions
#if UNITY_EDITOR
[InitializeOnLoadMethod]
private static void InitializeOnLoad()
{
UIExtraCallbacks.onAfterCanvasRebuild += Refresh;
EditorApplication.playModeStateChanged += state =>
{
UIExtraCallbacks.onAfterCanvasRebuild -= Refresh;
if (state == PlayModeStateChange.EnteredEditMode || state == PlayModeStateChange.EnteredPlayMode)
{
UIExtraCallbacks.onAfterCanvasRebuild += Refresh;
}
};
}
#else
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
#endif
private static void InitializeOnLoad()
{
UIExtraCallbacks.onAfterCanvasRebuild += Refresh;
}
#endif
private static void Refresh()
{

View File

@@ -171,30 +171,5 @@ namespace Coffee.UIParticleInternal
action.Invoke(p);
}
}
public static ParticleSystem GetMainEmitter(this ParticleSystem self, List<ParticleSystem> list)
{
if (!self || list == null || list.Count == 0) return null;
for (var i = 0; i < list.Count; i++)
{
var parent = list[i];
if (parent != self && IsSubEmitterOf(self, parent)) return parent;
}
return null;
}
public static bool IsSubEmitterOf(this ParticleSystem self, ParticleSystem parent)
{
var subEmitters = parent.subEmitters;
var count = subEmitters.subEmittersCount;
for (var i = 0; i < count; i++)
{
if (subEmitters.GetSubEmitterSystem(i) == self) return true;
}
return false;
}
}
}

View File

@@ -1,4 +1,3 @@
using Coffee.UIParticleInternal;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI;
@@ -52,7 +51,11 @@ namespace Coffee.UIExtensions.Demo
public void EnableAnimations(bool flag)
{
foreach (var animator in Misc.FindObjectsOfType<Animator>())
#if UNITY_2023_1_OR_NEWER
foreach (var animator in FindObjectsByType<Animator>(FindObjectsInactive.Include, FindObjectsSortMode.None))
#else
foreach (var animator in FindObjectsOfType<Animator>())
#endif
{
animator.enabled = flag;
}
@@ -80,7 +83,11 @@ namespace Coffee.UIExtensions.Demo
public void UIParticle_Scale(float scale)
{
foreach (var uip in Misc.FindObjectsOfType<UIParticle>())
#if UNITY_2023_1_OR_NEWER
foreach (var uip in FindObjectsByType<UIParticle>(FindObjectsInactive.Include, FindObjectsSortMode.None))
#else
foreach (var uip in FindObjectsOfType<UIParticle>())
#endif
{
uip.scale = scale;
}
@@ -88,7 +95,11 @@ namespace Coffee.UIExtensions.Demo
public void ParticleSystem_WorldSpaseSimulation(bool flag)
{
foreach (var p in Misc.FindObjectsOfType<ParticleSystem>())
#if UNITY_2023_1_OR_NEWER
foreach (var p in FindObjectsByType<ParticleSystem>(FindObjectsInactive.Include, FindObjectsSortMode.None))
#else
foreach (var p in FindObjectsOfType<ParticleSystem>())
#endif
{
var main = p.main;
main.simulationSpace = flag
@@ -124,7 +135,11 @@ namespace Coffee.UIExtensions.Demo
public void ParticleSystem_SetScale(float scale)
{
foreach (var ps in Misc.FindObjectsOfType<ParticleSystem>())
#if UNITY_2023_1_OR_NEWER
foreach (var ps in FindObjectsByType<ParticleSystem>(FindObjectsInactive.Include, FindObjectsSortMode.None))
#else
foreach (var ps in FindObjectsOfType<ParticleSystem>())
#endif
{
ps.transform.localScale = new Vector3(scale, scale, scale);
}

View File

@@ -2,7 +2,7 @@
"name": "com.coffee.ui-particle",
"displayName": "UI Particle",
"description": "This package provides a component to render particle effects for uGUI.\nThe particle rendering is maskable and sortable, without the need for an extra Camera, RenderTexture, or Canvas.",
"version": "4.11.0",
"version": "5.0.0-preview.11",
"unity": "2018.2",
"license": "MIT",
"repository": {