You've already forked ParticleEffectForUGUI
mirror of
https://github.com/mob-sakai/ParticleEffectForUGUI.git
synced 2026-05-14 20:20:06 +00:00
Compare commits
37 Commits
5.0.0-prev
...
92fb173507
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92fb173507 | ||
|
|
298dc9a093 | ||
|
|
143face565 | ||
|
|
319ab5fe06 | ||
|
|
04c1ca72cd | ||
|
|
f2df47aeec | ||
|
|
1dfd756721 | ||
|
|
c54f63cb18 | ||
|
|
7fb6cda06d | ||
|
|
9441f4100c | ||
|
|
ba95fe74ad | ||
|
|
4532e358db | ||
|
|
4b98abd746 | ||
|
|
63ec8f61e3 | ||
|
|
29eebf79fa | ||
|
|
4b6da7c218 | ||
|
|
7ea0a436d1 | ||
|
|
803af8113d | ||
|
|
8b5f7ff57e | ||
|
|
3d0284c630 | ||
|
|
9832485c04 | ||
|
|
201bd9180e | ||
|
|
12d604fedd | ||
|
|
4f42996514 | ||
|
|
a0a2f4aece | ||
|
|
23cd448766 | ||
|
|
1c33dac125 | ||
|
|
f4b28b68b1 | ||
|
|
ff179f0271 | ||
|
|
abdf260352 | ||
|
|
847af6397e | ||
|
|
ac3e147bd9 | ||
|
|
598c85e0f4 | ||
|
|
5f479902aa | ||
|
|
2a66393cb0 | ||
|
|
2b3cec69ac | ||
|
|
a4dd8c5776 |
97
CHANGELOG.md
97
CHANGELOG.md
@@ -1,3 +1,100 @@
|
||||
## [4.12.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.12.0...v4.12.1) (2026-03-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ignore "EditorOnly" tagged gameObjects on refresh ([031d46a](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/031d46a3216c942d2d1a6ccfadf5f0b9e3ce3006))
|
||||
|
||||
# [4.12.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.4...v4.12.0) (2026-03-24)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* explicit null checks ([5384f61](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/5384f61c569e9f78ff9d5b45acfc6f5c2f021a87))
|
||||
|
||||
## [4.11.4](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.3...v4.11.4) (2025-12-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add early return for case where subEmitter module is disabled ([d1386a1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/d1386a12216743a6e09f1b9b87bea1dfcf7702e4))
|
||||
* avoid endless loop ([eb2e862](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/eb2e862e80e549c8cf16ddfed776c101c2413bac)), closes [#392](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/392)
|
||||
|
||||
## [4.11.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.2...v4.11.3) (2025-10-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix icon ([a9461ec](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/a9461ecb4d40d7fe878e12465d6e38faae7ae65b))
|
||||
* fix URL link in README ([1c8c65d](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/1c8c65d25e7f6fe7b1d20da4461333df8fc7578e)), closes [#376](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/376)
|
||||
* fix: second and subsequent bursts not displayed when world simulation and non-looping ([df2f3ca](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/df2f3caafbe279f1457d74f8183cb561ac14aa17)), closes [#326](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/326)
|
||||
* UIParticle in canvas with 0f-0.01f alpha value does not start to play until alpha value is greater than 0.01f, causes play calls to be delayed unintentionally if canvas alpha value is set to mentioned value range ([38aec2e](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/38aec2ea1afd77677d629c86665a3342d92e49d9))
|
||||
|
||||
## [4.11.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.1...v4.11.2) (2025-03-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* IL2CPP build fails on older versions of Unity ([0da6525](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/0da652520cd165b43de7404c0b0ab1fbcf9349d1))
|
||||
* NRE on enable ([0cff50e](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/0cff50ef696aa53fb7c46a9a737b7cf3a05b7b9b)), closes [#359](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/359)
|
||||
|
||||
## [4.11.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.0...v4.11.1) (2025-02-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* component icons will no longer be displayed in the scene view ([6dfbdae](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/6dfbdae38d3822ab9c2c6f0e4ca1ca32ee98a239))
|
||||
|
||||
# [4.11.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.7...v4.11.0) (2025-02-21)
|
||||
|
||||
|
||||
### 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)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 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)
|
||||
|
||||
## [4.10.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.0...v4.10.1) (2024-09-29)
|
||||
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace Coffee.UIExtensions
|
||||
for (var j = 0; j < mats.Count; j++)
|
||||
{
|
||||
var mat = mats[j];
|
||||
if (!mat || !mat.shader) continue;
|
||||
if (mat == null || mat.shader == null) continue;
|
||||
|
||||
for (var i = 0; i < ShaderUtil.GetPropertyCount(mat.shader); i++)
|
||||
{
|
||||
|
||||
@@ -28,6 +28,11 @@ namespace Coffee.UIExtensions
|
||||
[CanEditMultipleObjects]
|
||||
internal class UIParticleEditor : GraphicEditor
|
||||
{
|
||||
internal class State : ScriptableSingleton<State>
|
||||
{
|
||||
public bool is3DScaleMode;
|
||||
}
|
||||
|
||||
//################################
|
||||
// Constant or Static Members.
|
||||
//################################
|
||||
@@ -46,7 +51,6 @@ 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;
|
||||
@@ -58,8 +62,10 @@ 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
|
||||
@@ -95,6 +101,7 @@ 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)
|
||||
@@ -103,7 +110,7 @@ namespace Coffee.UIExtensions
|
||||
{
|
||||
var ps = sp.GetArrayElementAtIndex(index).objectReferenceValue as ParticleSystem;
|
||||
var materialCount = 0;
|
||||
if (ps && ps.TryGetComponent<ParticleSystemRenderer>(out var psr))
|
||||
if (ps != null && ps.TryGetComponent<ParticleSystemRenderer>(out var psr))
|
||||
{
|
||||
materialCount = psr.sharedMaterials.Length;
|
||||
}
|
||||
@@ -117,7 +124,7 @@ namespace Coffee.UIExtensions
|
||||
var p = sp.GetArrayElementAtIndex(index);
|
||||
EditorGUI.ObjectField(rect, p, GUIContent.none);
|
||||
var ps = p.objectReferenceValue as ParticleSystem;
|
||||
if (!ps || !ps.TryGetComponent<ParticleSystemRenderer>(out var psr)) return;
|
||||
if (ps == null || !ps.TryGetComponent<ParticleSystemRenderer>(out var psr)) return;
|
||||
|
||||
rect.x += 15;
|
||||
rect.width -= 15;
|
||||
@@ -163,6 +170,19 @@ 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>
|
||||
@@ -171,7 +191,7 @@ namespace Coffee.UIExtensions
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
var current = target as UIParticle;
|
||||
if (!current) return;
|
||||
if (current == null) return;
|
||||
|
||||
Profiler.BeginSample("(UIP:E) OnInspectorGUI");
|
||||
serializedObject.Update();
|
||||
@@ -181,7 +201,11 @@ namespace Coffee.UIExtensions
|
||||
|
||||
// Scale
|
||||
EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4);
|
||||
s_XYZMode = DrawFloatOrVector3Field(_scale3D, s_XYZMode);
|
||||
if (DrawFloatOrVector3Field(_scale3D, _is3DScaleMode) != _is3DScaleMode)
|
||||
{
|
||||
State.instance.is3DScaleMode = _is3DScaleMode = !_is3DScaleMode;
|
||||
}
|
||||
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
// AnimatableProperties
|
||||
@@ -222,6 +246,9 @@ namespace Coffee.UIExtensions
|
||||
_customViewSize.floatValue = Mathf.Max(0.1f, _customViewSize.floatValue);
|
||||
}
|
||||
|
||||
// Time Scale Multiplier
|
||||
EditorGUILayout.PropertyField(_timeScaleMultiplier);
|
||||
|
||||
// Target ParticleSystems.
|
||||
EditorGUI.BeginChangeCheck();
|
||||
_ro.DoLayoutList();
|
||||
@@ -240,7 +267,7 @@ namespace Coffee.UIExtensions
|
||||
Profiler.BeginSample("(UIP:E) Non-UI built-in shader is not supported.");
|
||||
foreach (var mat in s_TempMaterials)
|
||||
{
|
||||
if (!mat || !mat.shader) continue;
|
||||
if (mat == null || mat.shader == null) continue;
|
||||
var shader = mat.shader;
|
||||
if (IsBuiltInObject(shader) && !shader.name.StartsWith("UI/"))
|
||||
{
|
||||
@@ -259,7 +286,7 @@ namespace Coffee.UIExtensions
|
||||
{
|
||||
foreach (var mat in s_TempMaterials)
|
||||
{
|
||||
if (!mat || !mat.shader) continue;
|
||||
if (mat == null || mat.shader == null) continue;
|
||||
var shader = mat.shader;
|
||||
if (!s_Shaders.Add(shader)) continue;
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 418 B After Width: | Height: | Size: 418 B |
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a55e246f37df405bac88eac692e3a86
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -144,7 +144,7 @@ _This package requires **Unity 2018.3 or later**._
|
||||
|
||||
#### Install as Embedded Package
|
||||
|
||||
1. Download a source code zip file from [Releases](https://github.com/mob-sakai/ParticleEffectForUGUI.git/releases) and extract it.
|
||||
1. Download a source code zip file from [Releases](https://github.com/mob-sakai/ParticleEffectForUGUI/releases) and extract it.
|
||||
2. Place it in your project's `Packages` directory.
|
||||

|
||||
- If you want to fix bugs or add features, install it as an embedded package.
|
||||
@@ -158,7 +158,7 @@ _This package requires **Unity 2018.3 or later**._
|
||||
|
||||
`UIParticle` controls the ParticleSystems that are attached to its own game objects and child game objects.
|
||||
|
||||

|
||||

|
||||
|
||||
- **Maskable**: Does this graphic allow maskable.
|
||||
- **Scale**: Scale the rendering particles. When the `3D` toggle is enabled, 3D scale (x, y, z) is supported.
|
||||
@@ -180,6 +180,7 @@ _This package requires **Unity 2018.3 or later**._
|
||||
- **UIParticle:** UIParticle.scale will be adjusted.
|
||||
- **Use Custom View:** Use this if the particles are not displayed correctly due to min/max particle size.
|
||||
- **Custom view size:** Change the bake view size.
|
||||
- **Time Scale Multiplier:** Time scale multiplier.
|
||||
- **Rendering Order**: The ParticleSystem list to be rendered. You can change the order and the materials.
|
||||
|
||||
**NOTE:** Press the `Refresh` button to reconstruct the rendering order based on children ParticleSystem's sorting order
|
||||
@@ -210,7 +211,7 @@ and z-position.
|
||||
If you want to mask particles, set a stencil-supported shader (such as `UI/UIAdditive`) to the material for
|
||||
ParticleSystem.
|
||||
If you use some custom shaders, see
|
||||
the [How to Make a Custom Shader to Support Mask/RectMask2D Component](#how-to-make-a-custom-shader-to-support-maskrectmask2d-component)
|
||||
the [How to Make a Custom Shader to Support Mask/RectMask2D Component](#how-to-make-a-custom-shader-to-support-mask-and-rectmask2d-component)
|
||||
section.
|
||||
|
||||

|
||||
|
||||
BIN
Runtime/Coffee.UIParticle.R.dll
Normal file
BIN
Runtime/Coffee.UIParticle.R.dll
Normal file
Binary file not shown.
33
Runtime/Coffee.UIParticle.R.dll.meta
Normal file
33
Runtime/Coffee.UIParticle.R.dll.meta
Normal file
@@ -0,0 +1,33 @@
|
||||
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:
|
||||
@@ -18,10 +18,10 @@ namespace Coffee.UIParticleInternal
|
||||
public static T[] GetComponentsInChildren<T>(this Component self, int depth)
|
||||
where T : Component
|
||||
{
|
||||
var results = ListPool<T>.Rent();
|
||||
var results = InternalListPool<T>.Rent();
|
||||
self.GetComponentsInChildren_Internal(results, depth);
|
||||
var array = results.ToArray();
|
||||
ListPool<T>.Return(ref results);
|
||||
InternalListPool<T>.Return(ref results);
|
||||
return array;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Coffee.UIParticleInternal
|
||||
private static void GetComponentsInChildren_Internal<T>(this Component self, List<T> results, int depth)
|
||||
where T : Component
|
||||
{
|
||||
if (!self || results == null || depth < 0) return;
|
||||
if (self == null || results == null || depth < 0) return;
|
||||
|
||||
var tr = self.transform;
|
||||
if (tr.TryGetComponent<T>(out var t))
|
||||
@@ -59,7 +59,7 @@ namespace Coffee.UIParticleInternal
|
||||
/// </summary>
|
||||
public static T GetOrAddComponent<T>(this Component self) where T : Component
|
||||
{
|
||||
if (!self) return null;
|
||||
if (self == null) return null;
|
||||
return self.TryGetComponent<T>(out var component)
|
||||
? component
|
||||
: self.gameObject.AddComponent<T>();
|
||||
@@ -134,10 +134,39 @@ 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
|
||||
{
|
||||
if (!self) return null;
|
||||
if (self == null) return null;
|
||||
if (!includeInactive) return self.GetComponentInParent<T>();
|
||||
|
||||
var current = self.transform;
|
||||
@@ -155,9 +184,9 @@ namespace Coffee.UIParticleInternal
|
||||
/// <summary>
|
||||
/// Verify whether it can be converted to the specified component.
|
||||
/// </summary>
|
||||
internal static bool CanConvertTo<T>(this Object context) where T : MonoBehaviour
|
||||
internal static bool CanConvertTo<T>(this Object context) where T : MonoBehaviour
|
||||
{
|
||||
return context && context.GetType() != typeof(T);
|
||||
return context != null && context.GetType() != typeof(T);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -175,7 +204,7 @@ namespace Coffee.UIParticleInternal
|
||||
target.enabled = false;
|
||||
|
||||
// Find MonoScript of the specified component.
|
||||
foreach (var script in Resources.FindObjectsOfTypeAll<MonoScript>())
|
||||
foreach (var script in MonoImporter.GetAllRuntimeMonoScripts())
|
||||
{
|
||||
if (script.GetClass() != typeof(T))
|
||||
{
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
using System.Diagnostics;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal static class Misc
|
||||
{
|
||||
public static void Destroy(Object obj)
|
||||
{
|
||||
if (!obj) return;
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Object.DestroyImmediate(obj);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Object.Destroy(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DestroyImmediate(Object obj)
|
||||
{
|
||||
if (!obj) return;
|
||||
#if UNITY_EDITOR
|
||||
if (Application.isEditor)
|
||||
{
|
||||
Object.DestroyImmediate(obj);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Object.Destroy(obj);
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional("UNITY_EDITOR")]
|
||||
public static void SetDirty(Object obj)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!obj) return;
|
||||
EditorUtility.SetDirty(obj);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,23 +17,25 @@ namespace Coffee.UIParticleInternal
|
||||
Type.GetType("UnityEditor.Experimental.U2D.SpriteEditorExtension, UnityEditor")
|
||||
?? Type.GetType("UnityEditor.U2D.SpriteEditorExtension, UnityEditor");
|
||||
|
||||
private static readonly MethodInfo s_GetActiveAtlasTextureMethod = s_SpriteEditorExtensionType
|
||||
.GetMethod("GetActiveAtlasTexture", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
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_GetActiveAtlasMethod = s_SpriteEditorExtensionType
|
||||
.GetMethod("GetActiveAtlas", 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));
|
||||
|
||||
/// <summary>
|
||||
/// Get the actual texture of a sprite in play mode or edit mode.
|
||||
/// </summary>
|
||||
public static Texture2D GetActualTexture(this Sprite self)
|
||||
{
|
||||
if (!self) return null;
|
||||
if (self == null) return null;
|
||||
|
||||
if (Application.isPlaying) return self.texture;
|
||||
|
||||
var ret = s_GetActiveAtlasTextureMethod.Invoke(null, new object[] { self }) as Texture2D;
|
||||
return ret ? ret : self.texture;
|
||||
var ret = s_GetActiveAtlasTextureMethod(self);
|
||||
return ret != null ? ret : self.texture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -41,9 +43,9 @@ namespace Coffee.UIParticleInternal
|
||||
/// </summary>
|
||||
public static SpriteAtlas GetActiveAtlas(this Sprite self)
|
||||
{
|
||||
if (!self) return null;
|
||||
if (self == null) return null;
|
||||
|
||||
return s_GetActiveAtlasMethod.Invoke(null, new object[] { self }) as SpriteAtlas;
|
||||
return s_GetActiveAtlasMethod(self);
|
||||
}
|
||||
#else
|
||||
/// <summary>
|
||||
@@ -51,7 +53,7 @@ namespace Coffee.UIParticleInternal
|
||||
/// </summary>
|
||||
internal static Texture2D GetActualTexture(this Sprite self)
|
||||
{
|
||||
return self ? self.texture : null;
|
||||
return self != null ? self.texture : null;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -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,6 +14,14 @@ 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;
|
||||
@@ -24,32 +32,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)
|
||||
if (defaultSettings == null)
|
||||
{
|
||||
// When create a new instance, automatically set it as default settings.
|
||||
defaultSettings = t.GetProperty("instance", flags)
|
||||
?.GetValue(null, null) as PreloadedProjectSettings;
|
||||
defaultSettings = CreateInstance(t) as PreloadedProjectSettings;
|
||||
SetDefaultSettings(defaultSettings);
|
||||
}
|
||||
else if (GetPreloadedSettings(t).Length != 1)
|
||||
{
|
||||
SetDefaultSettings(defaultSettings);
|
||||
}
|
||||
}
|
||||
|
||||
EditorApplication.QueuePlayerLoopUpdate();
|
||||
if (defaultSettings != null)
|
||||
{
|
||||
defaultSettings.OnInitialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static string GetDefaultName(Type type, bool nicify)
|
||||
{
|
||||
var typeName = type.Name.Replace("ProjectSettings", "");
|
||||
var typeName = type.Name;
|
||||
return nicify
|
||||
? ObjectNames.NicifyVariableName(typeName)
|
||||
: typeName;
|
||||
@@ -58,7 +66,7 @@ namespace Coffee.UIParticleInternal
|
||||
private static Object[] GetPreloadedSettings(Type type)
|
||||
{
|
||||
return PlayerSettings.GetPreloadedAssets()
|
||||
.Where(x => x && x.GetType() == type)
|
||||
.Where(x => x != null && x.GetType() == type)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
@@ -68,12 +76,13 @@ namespace Coffee.UIParticleInternal
|
||||
?? AssetDatabase.FindAssets($"t:{nameof(PreloadedProjectSettings)}")
|
||||
.Select(AssetDatabase.GUIDToAssetPath)
|
||||
.Select(AssetDatabase.LoadAssetAtPath<PreloadedProjectSettings>)
|
||||
.FirstOrDefault(x => x && x.GetType() == type);
|
||||
.FirstOrDefault(x => x != null && x.GetType() == type);
|
||||
}
|
||||
|
||||
protected static void SetDefaultSettings(PreloadedProjectSettings asset)
|
||||
{
|
||||
if (!asset) return;
|
||||
if (asset == null) return;
|
||||
|
||||
var type = asset.GetType();
|
||||
if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(asset)))
|
||||
{
|
||||
@@ -84,13 +93,17 @@ namespace Coffee.UIParticleInternal
|
||||
|
||||
var assetPath = $"Assets/ProjectSettings/{GetDefaultName(type, false)}.asset";
|
||||
assetPath = AssetDatabase.GenerateUniqueAssetPath(assetPath);
|
||||
AssetDatabase.CreateAsset(asset, assetPath);
|
||||
if (!File.Exists(assetPath))
|
||||
{
|
||||
AssetDatabase.CreateAsset(asset, assetPath);
|
||||
asset.OnCreateAsset();
|
||||
}
|
||||
}
|
||||
|
||||
var preloadedAssets = PlayerSettings.GetPreloadedAssets();
|
||||
var projectSettings = GetPreloadedSettings(type);
|
||||
PlayerSettings.SetPreloadedAssets(preloadedAssets
|
||||
.Where(x => x)
|
||||
.Where(x => x != null)
|
||||
.Except(projectSettings.Except(new[] { asset }))
|
||||
.Append(asset)
|
||||
.Distinct()
|
||||
@@ -98,6 +111,14 @@ namespace Coffee.UIParticleInternal
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
protected virtual void OnCreateAsset()
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void OnInitialize()
|
||||
{
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
@@ -112,17 +133,19 @@ namespace Coffee.UIParticleInternal
|
||||
#if UNITY_EDITOR
|
||||
private string _jsonText;
|
||||
|
||||
public static bool hasInstance => s_Instance != null;
|
||||
|
||||
public static T instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_Instance) return s_Instance;
|
||||
if (s_Instance != null) return s_Instance;
|
||||
|
||||
s_Instance = GetDefaultSettings(typeof(T)) as T;
|
||||
if (s_Instance) return s_Instance;
|
||||
if (s_Instance != null) return s_Instance;
|
||||
|
||||
s_Instance = CreateInstance<T>();
|
||||
if (!s_Instance)
|
||||
if (s_Instance == null)
|
||||
{
|
||||
s_Instance = null;
|
||||
return s_Instance;
|
||||
@@ -151,7 +174,7 @@ namespace Coffee.UIParticleInternal
|
||||
}
|
||||
}
|
||||
#else
|
||||
public static T instance => s_Instance ? s_Instance : s_Instance = CreateInstance<T>();
|
||||
public static T instance => s_Instance != null ? s_Instance : s_Instance = CreateInstance<T>();
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
@@ -160,7 +183,7 @@ namespace Coffee.UIParticleInternal
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var isDefaultSettings = !s_Instance || s_Instance == this || GetDefaultSettings(typeof(T)) == this;
|
||||
var isDefaultSettings = s_Instance == null || s_Instance == this || GetDefaultSettings(typeof(T)) == this;
|
||||
if (!isDefaultSettings)
|
||||
{
|
||||
DestroyImmediate(this, true);
|
||||
@@ -170,7 +193,7 @@ namespace Coffee.UIParticleInternal
|
||||
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
||||
#endif
|
||||
|
||||
if (s_Instance) return;
|
||||
if (s_Instance != null) return;
|
||||
s_Instance = this as T;
|
||||
}
|
||||
|
||||
@@ -199,7 +222,7 @@ namespace Coffee.UIParticleInternal
|
||||
|
||||
public override void OnGUI(string searchContext)
|
||||
{
|
||||
if (!_target)
|
||||
if (_target == null)
|
||||
{
|
||||
if (_editor)
|
||||
{
|
||||
|
||||
@@ -10,8 +10,9 @@ namespace Coffee.UIParticleInternal
|
||||
/// </summary>
|
||||
internal class FastActionBase<T>
|
||||
{
|
||||
private static readonly ObjectPool<LinkedListNode<T>> s_NodePool =
|
||||
new ObjectPool<LinkedListNode<T>>(() => new LinkedListNode<T>(default), _ => true, x => x.Value = default);
|
||||
private static readonly InternalObjectPool<LinkedListNode<T>> s_NodePool =
|
||||
new InternalObjectPool<LinkedListNode<T>>(() => new LinkedListNode<T>(default), _ => true,
|
||||
x => x.Value = default);
|
||||
|
||||
private readonly LinkedList<T> _delegates = new LinkedList<T>();
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Coffee.UIParticleInternal
|
||||
public static void LogIf(bool enable, object tag, object message, Object context = null)
|
||||
{
|
||||
if (!enable) return;
|
||||
Log_Internal(LogType.Log, tag, message, context ? context : tag as Object);
|
||||
Log_Internal(LogType.Log, tag, message, context != null ? context : tag as Object);
|
||||
}
|
||||
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
@@ -56,7 +56,7 @@ namespace Coffee.UIParticleInternal
|
||||
#endif
|
||||
public static void Log(object tag, object message, Object context = null)
|
||||
{
|
||||
Log_Internal(LogType.Log, tag, message, context ? context : tag as Object);
|
||||
Log_Internal(LogType.Log, tag, message, context != null ? context : tag as Object);
|
||||
}
|
||||
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
@@ -64,13 +64,13 @@ namespace Coffee.UIParticleInternal
|
||||
#endif
|
||||
public static void LogWarning(object tag, object message, Object context = null)
|
||||
{
|
||||
Log_Internal(LogType.Warning, tag, message, context ? context : tag as Object);
|
||||
Log_Internal(LogType.Warning, tag, message, context != null ? context : tag as Object);
|
||||
}
|
||||
|
||||
public static void LogError(object tag, object message, Object context = null)
|
||||
{
|
||||
#if ENABLE_COFFEE_LOGGER
|
||||
Log_Internal(LogType.Error, tag, message, context ? context : tag as Object);
|
||||
Log_Internal(LogType.Error, tag, message, context != null ? context : tag as Object);
|
||||
#else
|
||||
Debug.LogError($"{tag}: {message}", context);
|
||||
#endif
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Coffee.UIParticleInternal
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void Clear()
|
||||
public static void Clear()
|
||||
{
|
||||
s_Repository.Clear();
|
||||
}
|
||||
|
||||
132
Runtime/Internal/Utilities/Misc.cs
Normal file
132
Runtime/Internal/Utilities/Misc.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
#if UNITY_EDITOR
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
using UnityEditor.SceneManagement;
|
||||
#else
|
||||
using UnityEditor.Experimental.SceneManagement;
|
||||
#endif
|
||||
#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 == null) return;
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Object.DestroyImmediate(obj);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Object.Destroy(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DestroyImmediate(Object obj)
|
||||
{
|
||||
if (obj == null) return;
|
||||
#if UNITY_EDITOR
|
||||
if (Application.isEditor)
|
||||
{
|
||||
Object.DestroyImmediate(obj);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Object.Destroy(obj);
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional("UNITY_EDITOR")]
|
||||
public static void SetDirty(Object obj)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (obj == null) return;
|
||||
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
|
||||
|
||||
[Conditional("UNITY_EDITOR")]
|
||||
public static void QueuePlayerLoopUpdate()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!EditorApplication.isPlaying)
|
||||
{
|
||||
EditorApplication.QueuePlayerLoopUpdate();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if !UNITY_2021_2_OR_NEWER
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
[Conditional("UNITY_EDITOR")]
|
||||
internal class IconAttribute : Attribute
|
||||
{
|
||||
private readonly string _path;
|
||||
|
||||
public IconAttribute(string path)
|
||||
{
|
||||
_path = path;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private static Action<Object, Texture2D> s_SetIconForObject = typeof(EditorGUIUtility)
|
||||
.GetMethod("SetIconForObject", BindingFlags.Static | BindingFlags.NonPublic)
|
||||
.CreateDelegate(typeof(Action<Object, Texture2D>), null) as Action<Object, Texture2D>;
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
private static void InitializeOnLoadMethod()
|
||||
{
|
||||
if (Misc.isBatchOrBuilding) return;
|
||||
|
||||
var types = TypeCache.GetTypesWithAttribute<IconAttribute>();
|
||||
var scripts = MonoImporter.GetAllRuntimeMonoScripts();
|
||||
foreach (var type in types)
|
||||
{
|
||||
var script = scripts.FirstOrDefault(x => x.GetClass() == type);
|
||||
if (script == null) continue;
|
||||
|
||||
var path = type.GetCustomAttribute<IconAttribute>()?._path;
|
||||
var icon = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
|
||||
if (icon == null) continue;
|
||||
|
||||
s_SetIconForObject(script, icon);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39ed6a6b0a72e482488bd298b2ae762e
|
||||
guid: 182319ecc315e4858b119764af0fbcb0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -6,15 +6,58 @@ namespace Coffee.UIParticleInternal
|
||||
/// <summary>
|
||||
/// Object pool.
|
||||
/// </summary>
|
||||
internal class ObjectPool<T>
|
||||
internal class InternalObjectPool<T> where T : class
|
||||
{
|
||||
#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 ObjectPool(Func<T> onCreate, Predicate<T> onValid, Action<T> onReturn)
|
||||
public InternalObjectPool(Func<T> onCreate, Predicate<T> onValid, Action<T> onReturn)
|
||||
{
|
||||
_onCreate = onCreate;
|
||||
_onValid = onValid;
|
||||
@@ -54,15 +97,40 @@ 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 ListPool<T>
|
||||
internal static class InternalListPool<T>
|
||||
{
|
||||
private static readonly ObjectPool<List<T>> s_ListPool =
|
||||
new ObjectPool<List<T>>(() => new List<T>(), _ => true, x => x.Clear());
|
||||
#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());
|
||||
|
||||
/// <summary>
|
||||
/// Rent an instance from the pool.
|
||||
@@ -81,5 +149,6 @@ namespace Coffee.UIParticleInternal
|
||||
{
|
||||
s_ListPool.Return(ref toRelease);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace Coffee.UIParticleInternal
|
||||
Profiler.BeginSample("(COF)[ObjectRepository] GetFromCache");
|
||||
if (_cache.TryGetValue(hash, out var entry))
|
||||
{
|
||||
if (!entry.storedObject)
|
||||
if (entry.storedObject == null)
|
||||
{
|
||||
Release(ref entry.storedObject);
|
||||
Profiler.EndSample();
|
||||
@@ -116,7 +116,7 @@ namespace Coffee.UIParticleInternal
|
||||
|
||||
private void Add(Hash128 hash, ref T obj, T newObject)
|
||||
{
|
||||
if (!newObject)
|
||||
if (newObject == null)
|
||||
{
|
||||
Release(ref obj);
|
||||
obj = newObject;
|
||||
@@ -151,7 +151,7 @@ namespace Coffee.UIParticleInternal
|
||||
&& _cache.TryGetValue(hash, out var entry))
|
||||
{
|
||||
entry.reference--;
|
||||
if (entry.reference <= 0 || !entry.storedObject)
|
||||
if (entry.reference <= 0 || entry.storedObject == null)
|
||||
{
|
||||
Remove(entry);
|
||||
}
|
||||
@@ -192,7 +192,7 @@ namespace Coffee.UIParticleInternal
|
||||
public void Release(Action<T> onRelease)
|
||||
{
|
||||
reference = 0;
|
||||
if (storedObject)
|
||||
if (storedObject != null)
|
||||
{
|
||||
onRelease?.Invoke(storedObject);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ 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()
|
||||
{
|
||||
@@ -48,6 +50,15 @@ 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>
|
||||
@@ -77,6 +88,17 @@ 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();
|
||||
}
|
||||
|
||||
@@ -9,12 +9,16 @@ using UnityEngine.UI;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
[assembly: InternalsVisibleTo("Coffee.UIParticle.Editor")]
|
||||
[assembly: InternalsVisibleTo("Coffee.UIParticle.Editor.Tests")]
|
||||
[assembly: InternalsVisibleTo("Coffee.UIParticle.PerformanceDemo")]
|
||||
[assembly: InternalsVisibleTo("Coffee.UIParticle.Demo")]
|
||||
|
||||
namespace Coffee.UIExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Render maskable and sortable particle effect ,without Camera, RenderTexture or Canvas.
|
||||
/// </summary>
|
||||
[Icon("Packages/com.coffee.ui-particle/Editor/UIParticleIcon.png")]
|
||||
[ExecuteAlways]
|
||||
[RequireComponent(typeof(RectTransform))]
|
||||
[RequireComponent(typeof(CanvasRenderer))]
|
||||
@@ -117,6 +121,10 @@ namespace Coffee.UIExtensions
|
||||
"Change the bake view size.")]
|
||||
private float m_CustomViewSize = 10;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("Time scale multiplier.")]
|
||||
private float m_TimeScaleMultiplier = 1;
|
||||
|
||||
private readonly List<UIParticleRenderer> _renderers = new List<UIParticleRenderer>();
|
||||
private Camera _bakeCamera;
|
||||
private int _groupId;
|
||||
@@ -255,6 +263,15 @@ 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 =>
|
||||
@@ -454,7 +471,7 @@ namespace Coffee.UIExtensions
|
||||
for (var i = 0; i < _renderers.Count; i++)
|
||||
{
|
||||
var r = _renderers[i];
|
||||
if (!r || !r.material) continue;
|
||||
if (r == null || r.material == null) continue;
|
||||
result.Add(r.material);
|
||||
}
|
||||
}
|
||||
@@ -472,7 +489,7 @@ namespace Coffee.UIExtensions
|
||||
/// </summary>
|
||||
public void SetParticleSystemInstance(GameObject instance, bool destroyOldParticles)
|
||||
{
|
||||
if (!instance) return;
|
||||
if (instance == null) return;
|
||||
|
||||
var childCount = transform.childCount;
|
||||
for (var i = 0; i < childCount; i++)
|
||||
@@ -501,7 +518,7 @@ namespace Coffee.UIExtensions
|
||||
/// </summary>
|
||||
public void SetParticleSystemPrefab(GameObject prefab)
|
||||
{
|
||||
if (!prefab) return;
|
||||
if (prefab == null) return;
|
||||
|
||||
SetParticleSystemInstance(Instantiate(prefab.gameObject), true);
|
||||
}
|
||||
@@ -521,12 +538,14 @@ namespace Coffee.UIExtensions
|
||||
/// </summary>
|
||||
private void RefreshParticles(GameObject root)
|
||||
{
|
||||
if (!root) return;
|
||||
if (root == null) return;
|
||||
root.GetComponentsInChildren(true, particles);
|
||||
for (var i = particles.Count - 1; 0 <= i; i--)
|
||||
{
|
||||
var ps = particles[i];
|
||||
if (!ps || ps.GetComponentInParent<UIParticle>(true) != this)
|
||||
if (!ps
|
||||
|| ps.gameObject.CompareTag("EditorOnly") // Ignore "EditorOnly" tagged ParticleSystems.
|
||||
|| ps.GetComponentInParent<UIParticle>(true) != this) // Ignore ParticleSystems that are not under this UIParticle.
|
||||
{
|
||||
particles.RemoveAt(i);
|
||||
}
|
||||
@@ -574,13 +593,15 @@ namespace Coffee.UIExtensions
|
||||
for (var i = 0; i < particleSystems.Count; i++)
|
||||
{
|
||||
var ps = particleSystems[i];
|
||||
if (!ps) continue;
|
||||
GetRenderer(j++).Set(this, ps, false);
|
||||
if (ps == null) continue;
|
||||
|
||||
var mainEmitter = ps.GetMainEmitter(particleSystems);
|
||||
GetRenderer(j++).Set(this, ps, false, mainEmitter);
|
||||
|
||||
// If the trail is enabled, set it additionally.
|
||||
if (ps.trails.enabled)
|
||||
{
|
||||
GetRenderer(j++).Set(this, ps, true);
|
||||
GetRenderer(j++).Set(this, ps, true, mainEmitter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -623,7 +644,7 @@ namespace Coffee.UIExtensions
|
||||
for (var i = 0; i < _renderers.Count; i++)
|
||||
{
|
||||
var r = _renderers[i];
|
||||
if (r) continue;
|
||||
if (r != null) continue;
|
||||
|
||||
RefreshParticles(particles);
|
||||
break;
|
||||
@@ -633,7 +654,7 @@ namespace Coffee.UIExtensions
|
||||
for (var i = 0; i < _renderers.Count; i++)
|
||||
{
|
||||
var r = _renderers[i];
|
||||
if (!r) continue;
|
||||
if (r == null) continue;
|
||||
|
||||
r.UpdateMesh(bakeCamera);
|
||||
}
|
||||
@@ -662,7 +683,7 @@ namespace Coffee.UIExtensions
|
||||
for (var i = 0; i < _renderers.Count; i++)
|
||||
{
|
||||
var r = _renderers[i];
|
||||
if (!r) continue;
|
||||
if (r == null) continue;
|
||||
r.maskable = maskable;
|
||||
r.SetMaterialDirty();
|
||||
}
|
||||
@@ -675,7 +696,7 @@ namespace Coffee.UIExtensions
|
||||
_renderers.Add(UIParticleRenderer.AddRenderer(this, index));
|
||||
}
|
||||
|
||||
if (!_renderers[index])
|
||||
if (_renderers[index] == null)
|
||||
{
|
||||
_renderers[index] = UIParticleRenderer.AddRenderer(this, index);
|
||||
}
|
||||
@@ -685,13 +706,13 @@ namespace Coffee.UIExtensions
|
||||
|
||||
private Camera GetBakeCamera()
|
||||
{
|
||||
if (!canvas) return Camera.main;
|
||||
if (canvas == null) return Camera.main;
|
||||
if (!useCustomView && canvas.renderMode != RenderMode.ScreenSpaceOverlay && canvas.rootCanvas.worldCamera)
|
||||
{
|
||||
return canvas.rootCanvas.worldCamera;
|
||||
}
|
||||
|
||||
if (_bakeCamera)
|
||||
if (_bakeCamera != null)
|
||||
{
|
||||
_bakeCamera.orthographicSize = useCustomView ? customViewSize : 10;
|
||||
return _bakeCamera;
|
||||
@@ -710,7 +731,7 @@ namespace Coffee.UIExtensions
|
||||
}
|
||||
|
||||
// Create baking camera.
|
||||
if (!_bakeCamera)
|
||||
if (_bakeCamera == null)
|
||||
{
|
||||
var go = new GameObject("[generated] UIParticle BakingCamera");
|
||||
go.SetActive(false);
|
||||
|
||||
@@ -5,7 +5,7 @@ MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 5f0675613942149309588d556e33d990, type: 3}
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
@@ -208,7 +208,7 @@ namespace Coffee.UIExtensions
|
||||
|
||||
private Vector3 GetDestinationPosition(UIParticle uiParticle, ParticleSystem particleSystem)
|
||||
{
|
||||
var isUI = uiParticle && uiParticle.enabled;
|
||||
var isUI = uiParticle != null && uiParticle.enabled;
|
||||
var psPos = particleSystem.transform.position;
|
||||
var attractorPos = transform.position;
|
||||
var dstPos = attractorPos;
|
||||
|
||||
@@ -15,6 +15,7 @@ using UnityEngine.UI;
|
||||
|
||||
namespace Coffee.UIExtensions
|
||||
{
|
||||
[Icon("Packages/com.coffee.ui-particle/Editor/UIParticleIcon.png")]
|
||||
[ExecuteAlways]
|
||||
[RequireComponent(typeof(RectTransform))]
|
||||
[RequireComponent(typeof(CanvasRenderer))]
|
||||
@@ -40,6 +41,7 @@ namespace Coffee.UIExtensions
|
||||
private Vector2Int _prevScreenSize;
|
||||
private bool _preWarm;
|
||||
private ParticleSystemRenderer _renderer;
|
||||
private ParticleSystem _mainEmitter;
|
||||
|
||||
public override Texture mainTexture => _isTrail ? null : _particleSystem.GetTextureForSprite();
|
||||
|
||||
@@ -53,7 +55,7 @@ namespace Coffee.UIExtensions
|
||||
s_Corners[1] = transform.TransformPoint(_lastBounds.min.x, _lastBounds.max.y, 0);
|
||||
s_Corners[2] = transform.TransformPoint(_lastBounds.max.x, _lastBounds.max.y, 0);
|
||||
s_Corners[3] = transform.TransformPoint(_lastBounds.max.x, _lastBounds.min.y, 0);
|
||||
if (canvas)
|
||||
if (canvas != null)
|
||||
{
|
||||
var worldToLocalMatrix = canvas.rootCanvas.transform.worldToLocalMatrix;
|
||||
for (var i = 0; i < 4; ++i)
|
||||
@@ -93,7 +95,7 @@ namespace Coffee.UIExtensions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_materialForRendering)
|
||||
if (_materialForRendering == null)
|
||||
{
|
||||
_materialForRendering = base.materialForRendering;
|
||||
}
|
||||
@@ -104,7 +106,7 @@ namespace Coffee.UIExtensions
|
||||
|
||||
public void Reset(int index = -1)
|
||||
{
|
||||
if (_renderer)
|
||||
if (_renderer != null)
|
||||
{
|
||||
_renderer.enabled = true;
|
||||
}
|
||||
@@ -112,13 +114,14 @@ namespace Coffee.UIExtensions
|
||||
_parent = null;
|
||||
_particleSystem = null;
|
||||
_renderer = null;
|
||||
_mainEmitter = null;
|
||||
if (0 <= index)
|
||||
{
|
||||
_index = index;
|
||||
}
|
||||
|
||||
//_emitter = null;
|
||||
if (this && isActiveAndEnabled)
|
||||
if (isActiveAndEnabled)
|
||||
{
|
||||
material = null;
|
||||
canvasRenderer.Clear();
|
||||
@@ -137,7 +140,7 @@ namespace Coffee.UIExtensions
|
||||
base.OnEnable();
|
||||
|
||||
hideFlags = UIParticleProjectSettings.globalHideFlags;
|
||||
if (!s_CombineInstances[0].mesh)
|
||||
if (s_CombineInstances[0].mesh == null)
|
||||
{
|
||||
s_CombineInstances[0].mesh = new Mesh
|
||||
{
|
||||
@@ -223,7 +226,7 @@ namespace Coffee.UIExtensions
|
||||
return _modifiedMaterial;
|
||||
}
|
||||
|
||||
public void Set(UIParticle parent, ParticleSystem ps, bool isTrail)
|
||||
public void Set(UIParticle parent, ParticleSystem ps, bool isTrail, ParticleSystem mainEmitter)
|
||||
{
|
||||
_parent = parent;
|
||||
maskable = parent.maskable;
|
||||
@@ -246,10 +249,7 @@ 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();
|
||||
@@ -266,6 +266,7 @@ namespace Coffee.UIExtensions
|
||||
_prevScreenSize = new Vector2Int(Screen.width, Screen.height);
|
||||
_prevCanvasScale = canvas ? canvas.scaleFactor : 1f;
|
||||
_delay = true;
|
||||
_mainEmitter = mainEmitter;
|
||||
|
||||
canvasRenderer.SetTexture(null);
|
||||
|
||||
@@ -282,10 +283,6 @@ namespace Coffee.UIExtensions
|
||||
|| !transform.lossyScale.GetScaled(_parent.scale3DForCalc).IsVisible() // Scale is not visible.
|
||||
|| (!_particleSystem.IsAlive() && !_particleSystem.isPlaying) // No particle.
|
||||
|| (_isTrail && !_particleSystem.trails.enabled) // Trail, but it is not enabled.
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
|| canvasRenderer.GetInheritedAlpha() <
|
||||
0.01f // #102: Do not bake particle system to mesh when the alpha is zero.
|
||||
#endif
|
||||
)
|
||||
{
|
||||
Profiler.BeginSample("[UIParticleRenderer] Clear Mesh");
|
||||
@@ -297,13 +294,31 @@ namespace Coffee.UIExtensions
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset custom data.
|
||||
// var customData = _particleSystem.customData;
|
||||
// if (!customData.enabled || customData.GetMode(ParticleSystemCustomData.Custom1) == ParticleSystemCustomDataMode.Disabled)
|
||||
// {
|
||||
// customData.SetVector(ParticleSystemCustomData.Custom1, 0, 0);
|
||||
// customData.SetVector(ParticleSystemCustomData.Custom1, 1, 0);
|
||||
// customData.SetVector(ParticleSystemCustomData.Custom1, 2, 0);
|
||||
// customData.SetVector(ParticleSystemCustomData.Custom1, 3, 0);
|
||||
// }
|
||||
//
|
||||
// if (!customData.enabled || customData.GetMode(ParticleSystemCustomData.Custom2) == ParticleSystemCustomDataMode.Disabled)
|
||||
// {
|
||||
// customData.SetVector(ParticleSystemCustomData.Custom2, 0, 0);
|
||||
// customData.SetVector(ParticleSystemCustomData.Custom2, 1, 0);
|
||||
// customData.SetVector(ParticleSystemCustomData.Custom2, 2, 0);
|
||||
// customData.SetVector(ParticleSystemCustomData.Custom2, 3, 0);
|
||||
// }
|
||||
|
||||
var main = _particleSystem.main;
|
||||
var scale = GetWorldScale();
|
||||
var psPos = _particleSystem.transform.position;
|
||||
|
||||
// Simulate particles.
|
||||
Profiler.BeginSample("[UIParticle] Bake Mesh > Simulate Particles");
|
||||
if (!_isTrail && _parent.canSimulate)
|
||||
if (!_isTrail && _parent.canSimulate && !_mainEmitter)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
@@ -314,6 +329,13 @@ namespace Coffee.UIExtensions
|
||||
#endif
|
||||
{
|
||||
ResolveResolutionChange(psPos, scale);
|
||||
|
||||
// fix: second and subsequent bursts not displayed when world simulation and non-looping. (#326)
|
||||
if (!_particleSystem.IsLocalSpace() && !main.loop && _particleSystem.time == 0)
|
||||
{
|
||||
_delay = true;
|
||||
}
|
||||
|
||||
Simulate(scale, _parent.isPaused || _delay);
|
||||
|
||||
if (_delay && !_parent.isPaused)
|
||||
@@ -421,7 +443,7 @@ namespace Coffee.UIExtensions
|
||||
workerMesh.LinearToGamma();
|
||||
}
|
||||
|
||||
var components = ListPool<Component>.Rent();
|
||||
var components = InternalListPool<Component>.Rent();
|
||||
GetComponents(typeof(IMeshModifier), components);
|
||||
for (var i = 0; i < components.Count; i++)
|
||||
{
|
||||
@@ -430,7 +452,7 @@ namespace Coffee.UIExtensions
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
}
|
||||
|
||||
ListPool<Component>.Return(ref components);
|
||||
InternalListPool<Component>.Return(ref components);
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
@@ -442,7 +464,7 @@ namespace Coffee.UIExtensions
|
||||
|
||||
// Get grouped renderers.
|
||||
Profiler.BeginSample("[UIParticleRenderer] Set Mesh");
|
||||
var renderers = ListPool<UIParticleRenderer>.Rent();
|
||||
var renderers = InternalListPool<UIParticleRenderer>.Rent();
|
||||
if (_parent.useMeshSharing)
|
||||
{
|
||||
UIParticleUpdater.GetGroupedRenderers(_parent.groupId, _index, renderers);
|
||||
@@ -459,7 +481,7 @@ namespace Coffee.UIExtensions
|
||||
r.canvasRenderer.SetMaterial(materialForRendering, 0);
|
||||
}
|
||||
|
||||
ListPool<UIParticleRenderer>.Return(ref renderers);
|
||||
InternalListPool<UIParticleRenderer>.Return(ref renderers);
|
||||
|
||||
if (_parent.canRender)
|
||||
{
|
||||
@@ -542,6 +564,30 @@ 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))
|
||||
@@ -604,6 +650,7 @@ namespace Coffee.UIExtensions
|
||||
: main.useUnscaledTime
|
||||
? Time.unscaledDeltaTime
|
||||
: Time.deltaTime;
|
||||
deltaTime *= _parent.timeScaleMultiplier;
|
||||
|
||||
// Pre-warm:
|
||||
if (0 < deltaTime && _preWarm)
|
||||
@@ -684,7 +731,7 @@ namespace Coffee.UIExtensions
|
||||
if (s_Mpb.isEmpty) return;
|
||||
|
||||
// #41: Copy the value from MaterialPropertyBlock to CanvasRenderer
|
||||
if (!materialForRendering) return;
|
||||
if (materialForRendering == null) return;
|
||||
|
||||
for (var i = 0; i < _parent.m_AnimatableProperties.Length; i++)
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 5f0675613942149309588d556e33d990, type: 3}
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
@@ -16,37 +16,50 @@ namespace Coffee.UIExtensions
|
||||
|
||||
public static void Register(UIParticle particle)
|
||||
{
|
||||
if (!particle) return;
|
||||
if (particle == null) return;
|
||||
s_ActiveParticles.Add(particle);
|
||||
}
|
||||
|
||||
public static void Unregister(UIParticle particle)
|
||||
{
|
||||
if (!particle) return;
|
||||
if (particle == null) return;
|
||||
s_ActiveParticles.Remove(particle);
|
||||
}
|
||||
|
||||
public static void Register(UIParticleAttractor attractor)
|
||||
{
|
||||
if (!attractor) return;
|
||||
if (attractor == null) return;
|
||||
s_ActiveAttractors.Add(attractor);
|
||||
}
|
||||
|
||||
public static void Unregister(UIParticleAttractor attractor)
|
||||
{
|
||||
if (!attractor) return;
|
||||
if (attractor == null) return;
|
||||
s_ActiveAttractors.Remove(attractor);
|
||||
}
|
||||
|
||||
#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()
|
||||
{
|
||||
@@ -58,7 +71,7 @@ namespace Coffee.UIExtensions
|
||||
for (var i = 0; i < s_ActiveParticles.Count; i++)
|
||||
{
|
||||
var uip = s_ActiveParticles[i];
|
||||
if (!uip || !uip.canvas || !uip.isPrimary || !s_UpdatedGroupIds.Add(uip.groupId)) continue;
|
||||
if (uip == null || uip.canvas == null || !uip.isPrimary || !s_UpdatedGroupIds.Add(uip.groupId)) continue;
|
||||
|
||||
uip.UpdateTransformScale();
|
||||
uip.UpdateRenderers();
|
||||
@@ -68,7 +81,7 @@ namespace Coffee.UIExtensions
|
||||
for (var i = 0; i < s_ActiveParticles.Count; i++)
|
||||
{
|
||||
var uip = s_ActiveParticles[i];
|
||||
if (!uip || !uip.canvas) continue;
|
||||
if (uip == null || uip.canvas == null) continue;
|
||||
|
||||
uip.UpdateTransformScale();
|
||||
|
||||
@@ -112,7 +125,7 @@ namespace Coffee.UIExtensions
|
||||
var uip = s_ActiveParticles[i];
|
||||
if (!uip.useMeshSharing || uip.groupId != groupId) continue;
|
||||
if (uip.isPrimary) return uip;
|
||||
if (!primary && uip.canSimulate) primary = uip;
|
||||
if (primary == null && uip.canSimulate) primary = uip;
|
||||
}
|
||||
|
||||
return primary;
|
||||
|
||||
@@ -13,11 +13,7 @@ namespace Coffee.UIParticleInternal
|
||||
{
|
||||
if (s_TmpParticles.Length < size)
|
||||
{
|
||||
while (s_TmpParticles.Length < size)
|
||||
{
|
||||
size = Mathf.NextPowerOfTwo(size);
|
||||
}
|
||||
|
||||
size = Mathf.NextPowerOfTwo(size);
|
||||
s_TmpParticles = new ParticleSystem.Particle[size];
|
||||
}
|
||||
|
||||
@@ -88,11 +84,11 @@ namespace Coffee.UIParticleInternal
|
||||
var bRenderer = b.GetComponent<ParticleSystemRenderer>();
|
||||
|
||||
// Render queue: ascending
|
||||
var aMat = aRenderer.sharedMaterial ? aRenderer.sharedMaterial : aRenderer.trailMaterial;
|
||||
var bMat = bRenderer.sharedMaterial ? bRenderer.sharedMaterial : bRenderer.trailMaterial;
|
||||
if (!aMat && !bMat) return 0;
|
||||
if (!aMat) return -1;
|
||||
if (!bMat) return 1;
|
||||
var aMat = aRenderer.sharedMaterial != null ? aRenderer.sharedMaterial : aRenderer.trailMaterial;
|
||||
var bMat = bRenderer.sharedMaterial != null ? bRenderer.sharedMaterial : bRenderer.trailMaterial;
|
||||
if (aMat == null && bMat == null) return 0;
|
||||
if (aMat == null) return -1;
|
||||
if (bMat == null) return 1;
|
||||
|
||||
if (sortByMaterial)
|
||||
{
|
||||
@@ -146,7 +142,7 @@ namespace Coffee.UIParticleInternal
|
||||
|
||||
public static Texture2D GetTextureForSprite(this ParticleSystem self)
|
||||
{
|
||||
if (!self) return null;
|
||||
if (self == null) return null;
|
||||
|
||||
// Get sprite's texture.
|
||||
var tsaModule = self.textureSheetAnimation;
|
||||
@@ -155,7 +151,7 @@ namespace Coffee.UIParticleInternal
|
||||
for (var i = 0; i < tsaModule.spriteCount; i++)
|
||||
{
|
||||
var sprite = tsaModule.GetSprite(i);
|
||||
if (!sprite) continue;
|
||||
if (sprite == null) continue;
|
||||
|
||||
return sprite.GetActualTexture();
|
||||
}
|
||||
@@ -167,9 +163,38 @@ namespace Coffee.UIParticleInternal
|
||||
{
|
||||
foreach (var p in self)
|
||||
{
|
||||
if (!p) continue;
|
||||
if (p == null) continue;
|
||||
action.Invoke(p);
|
||||
}
|
||||
}
|
||||
|
||||
public static ParticleSystem GetMainEmitter(this ParticleSystem self, List<ParticleSystem> list)
|
||||
{
|
||||
if (self == null || 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)
|
||||
{
|
||||
if (self == null || parent == null) return false;
|
||||
|
||||
var subEmitters = parent.subEmitters;
|
||||
if (!subEmitters.enabled) return false; // No sub emitters.
|
||||
|
||||
var count = subEmitters.subEmittersCount;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
if (subEmitters.GetSubEmitterSystem(i) == self) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Coffee.UIExtensions.Demo
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (!m_Origin) return;
|
||||
if (m_Origin == null) return;
|
||||
m_Origin.SetActive(false);
|
||||
|
||||
var parent = m_Origin.transform.parent;
|
||||
|
||||
@@ -42,7 +42,7 @@ public class UIElementDragger : MonoBehaviour, IBeginDragHandler, IDragHandler,
|
||||
break;
|
||||
case Target.Custom:
|
||||
_rectTransform.localPosition += delta;
|
||||
if (m_CustomTarget)
|
||||
if (m_CustomTarget != null)
|
||||
{
|
||||
if (m_UseCanvasScale)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Coffee.UIParticleInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
using UnityEngine.UI;
|
||||
@@ -51,11 +52,7 @@ namespace Coffee.UIExtensions.Demo
|
||||
|
||||
public void EnableAnimations(bool flag)
|
||||
{
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
foreach (var animator in FindObjectsByType<Animator>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
||||
#else
|
||||
foreach (var animator in FindObjectsOfType<Animator>())
|
||||
#endif
|
||||
foreach (var animator in Misc.FindObjectsOfType<Animator>())
|
||||
{
|
||||
animator.enabled = flag;
|
||||
}
|
||||
@@ -83,11 +80,7 @@ namespace Coffee.UIExtensions.Demo
|
||||
|
||||
public void UIParticle_Scale(float scale)
|
||||
{
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
foreach (var uip in FindObjectsByType<UIParticle>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
||||
#else
|
||||
foreach (var uip in FindObjectsOfType<UIParticle>())
|
||||
#endif
|
||||
foreach (var uip in Misc.FindObjectsOfType<UIParticle>())
|
||||
{
|
||||
uip.scale = scale;
|
||||
}
|
||||
@@ -95,11 +88,7 @@ namespace Coffee.UIExtensions.Demo
|
||||
|
||||
public void ParticleSystem_WorldSpaseSimulation(bool flag)
|
||||
{
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
foreach (var p in FindObjectsByType<ParticleSystem>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
||||
#else
|
||||
foreach (var p in FindObjectsOfType<ParticleSystem>())
|
||||
#endif
|
||||
foreach (var p in Misc.FindObjectsOfType<ParticleSystem>())
|
||||
{
|
||||
var main = p.main;
|
||||
main.simulationSpace = flag
|
||||
@@ -135,11 +124,7 @@ namespace Coffee.UIExtensions.Demo
|
||||
|
||||
public void ParticleSystem_SetScale(float scale)
|
||||
{
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
foreach (var ps in FindObjectsByType<ParticleSystem>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
||||
#else
|
||||
foreach (var ps in FindObjectsOfType<ParticleSystem>())
|
||||
#endif
|
||||
foreach (var ps in Misc.FindObjectsOfType<ParticleSystem>())
|
||||
{
|
||||
ps.transform.localScale = new Vector3(scale, scale, scale);
|
||||
}
|
||||
|
||||
@@ -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.10.1",
|
||||
"version": "4.12.1",
|
||||
"unity": "2018.2",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
||||
Reference in New Issue
Block a user