You've already forked ParticleEffectForUGUI
mirror of
https://github.com/mob-sakai/ParticleEffectForUGUI.git
synced 2026-05-16 21:30:07 +00:00
Compare commits
24 Commits
4.10.7
...
5.0.0-prev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b068238e0a | ||
|
|
42fb0ecf23 | ||
|
|
79635e81d7 | ||
|
|
f388eb45ec | ||
|
|
f08809772a | ||
|
|
f96604ffc9 | ||
|
|
beac3b8048 | ||
|
|
a00bcd8a35 | ||
|
|
1f72048ef5 | ||
|
|
65f7555482 | ||
|
|
433f828ad9 | ||
|
|
1b8f0aac4a | ||
|
|
70271ae5e9 | ||
|
|
c3540a056c | ||
|
|
0cf4ae88c5 | ||
|
|
e579f524ba | ||
|
|
23dd7b5987 | ||
|
|
f476898b46 | ||
|
|
4e91b6f69b | ||
|
|
1bf669e09f | ||
|
|
54be6bf588 | ||
|
|
72f5f9441b | ||
|
|
acebfb27f6 | ||
|
|
a3e725fd5a |
138
CHANGELOG.md
138
CHANGELOG.md
@@ -1,144 +1,42 @@
|
|||||||
## [4.10.7](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.6...v4.10.7) (2025-01-14)
|
# [5.0.0-preview.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v5.0.0-preview.2...v5.0.0-preview.3) (2024-06-21)
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
### 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)
|
* generated baking-camera object remains in the prefab or scene ([fd66928](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/fd66928efe584aeb4f6347b9a9dca97d9512eb88))
|
||||||
|
|
||||||
## [4.10.6](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.5...v4.10.6) (2025-01-03)
|
# [5.0.0-preview.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v5.0.0-preview.1...v5.0.0-preview.2) (2024-06-20)
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
### 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)
|
* 'Resource ID out of range in GetResource' error in overlay rendering mode ([ff78b6f](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/ff78b6fe32ceed8ddad50e63dcb7a202eab95266)), closes [#308](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/308)
|
||||||
* 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)
|
* `UIParticle.transform.localScale` does not scale particles ([491ee7b](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/491ee7b0c3e528e1e577ae5ff2588d7c3bd8ecdb)), closes [#313](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/313)
|
||||||
|
* despite not using the size module, particles become smaller based on their z position ([c96ddf2](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c96ddf293e855f7ebccaaaf3b112092955545e61)), closes [#316](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/316)
|
||||||
## [4.10.5](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.4...v4.10.5) (2024-12-23)
|
* the ParticleSystem's localPosition drifts at certain scales due to floating-point precision issues ([a9c2b19](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/a9c2b19edf00e1c86c928ef23405906952ede852)), closes [#299](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/299) [#312](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/312)
|
||||||
|
* UIParticle is scaled by canvas size even when `AutoScalingMode.None` and `ScalingMode.Local` ([63b24d8](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/63b24d8a8b478b3165733ece3eec524e88b28855)), closes [#313](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/313)
|
||||||
|
* UIParticle is scaled incorrectly with nested canvases ([c95d8c6](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c95d8c6b1774396ff252d13121ad32a3cab0fe5c)), closes [#313](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/313)
|
||||||
### 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)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* mainTex will be ignored ([2ee69d0](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/2ee69d04245fabce185f67dc9bd68c870e556564))
|
|
||||||
|
|
||||||
# [4.10.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.9.1...v4.10.0) (2024-09-29)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* component icon is not set ([5ff6ec8](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/5ff6ec815a174de5d3f16d424f1204c60912a8d8))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
* add project settings ([1ce4e31](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/1ce4e31a9681bf1a201d2723c8d97e07ecc16592))
|
* remove overlay window (editor) ([fc3fbdd](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/fc3fbdd230595ad3471875ec6fec384a3dad0d17))
|
||||||
|
* reset previous position on start play for world space simulation ([e741584](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/e7415845074143abae23e3ae7eedc767a01d020d)), closes [#303](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/303)
|
||||||
|
* restore `Transform.localScale` when setting `autoScalingMode` to something other than `Transform` ([dfb94f4](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/dfb94f4badfb3035a4374579c53293460b4fd946))
|
||||||
|
|
||||||
## [4.9.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.9.0...v4.9.1) (2024-08-07)
|
# [5.0.0-preview.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.6...v5.0.0-preview.1) (2024-05-23)
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* ParticleSystem trails gain offset on parent canvas change ([2a1cd50](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/2a1cd502b452b5b56edf8bcfe91adf99d1bb5147)), closes [#323](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/323)
|
|
||||||
|
|
||||||
# [4.9.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.8.1...v4.9.0) (2024-07-18)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
* ParticleAttractor supports multiple ParticleSystems ([3834780](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/3834780fdb43443fe6e1ef89df54d26a24d62a91))
|
* add project settings for UIParticle ([b6e6185](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/b6e6185c521fef0f118f61cfdfdac07b87555c01))
|
||||||
|
* change the default value of `UIParticle.scale` from `10` to `1` ([1b3c0f9](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/1b3c0f92dcc6a1974d1ea074821e5264200e9711)), closes [#310](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/310)
|
||||||
## [4.8.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.8.0...v4.8.1) (2024-06-27)
|
* UIParticle no longer inherits from MaskableGraphic ([b6d921b](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/b6d921b3e47f749b5028d22b0e89b6eb3a1af7de))
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
### BREAKING CHANGES
|
||||||
|
|
||||||
* remove debug code ([669deb4](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/669deb41d4ac589d9db93b29bc8e95383e7f28a5))
|
* Some members inherited from MaskableGraphic will no longer be available.
|
||||||
|
|
||||||
# [4.8.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.7.2...v4.8.0) (2024-06-27)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* generated baking-camera object remains in the prefab or scene (again) ([de35cba](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/de35cba34c6312c1405ed522e9927c620c78e72d))
|
|
||||||
* SetParticleSystemInstance/Prefab APIs destroy generated objects ([ae3f3a8](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/ae3f3a8e62cc733420354d237ab765ac777127c8))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* add 'custom view' option. ([a703c29](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/a703c2921ca08c2280d0c8fde01e4c0b33b5c69e))
|
|
||||||
* remove overlay window (editor) ([8358170](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/835817049f4fcf00dd2bf98dbada14f041ad3544))
|
|
||||||
* restore `Transform.localScale` when setting `autoScalingMode` to something other than `Transform` (again) ([88a970d](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/88a970d93a2b69cf011d86bd1807569e90538e0e))
|
|
||||||
* the rendering order list in inspector is now more compact ([be90172](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/be901724e064befacf617f4940b0331e1d31e1ca))
|
|
||||||
|
|
||||||
## [4.7.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.7.1...v4.7.2) (2024-06-21)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* generated baking-camera object remains in the prefab or scene ([0bb8438](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/0bb843830197d8c1252232928becc211c0ada08d))
|
|
||||||
|
|
||||||
## [4.7.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.7.0...v4.7.1) (2024-06-20)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* despite not using the size module, particles become smaller based on their z position ([a8ed6e6](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/a8ed6e68584e1d9e45ed852eefcc03979ea7e0e1)), closes [#316](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/316)
|
|
||||||
|
|
||||||
# [4.7.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.8...v4.7.0) (2024-06-19)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* `UIParticle.transform.localScale` does not scale particles ([1d40e24](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/1d40e24c742741e97f03c55468ccb1e505341133)), closes [#313](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/313)
|
|
||||||
* UIParticle is scaled by canvas size even when `AutoScalingMode.None` and `ScalingMode.Local` ([54a4b1c](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/54a4b1cdfd06400c7be89c1ee704bb42a659c7c2)), closes [#313](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/313)
|
|
||||||
* UIParticle is scaled incorrectly with nested canvases ([f26920f](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/f26920f9825547222a4afbb31cc5dc5a002c3e9b)), closes [#313](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/313)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* reset previous position on start play for world space simulation ([3880484](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/3880484ce5190c42fc79c81d0b69e3fbeda09dd0)), closes [#303](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/303)
|
|
||||||
* restore `Transform.localScale` when setting `autoScalingMode` to something other than `Transform` ([5505247](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/5505247a94a929ff89635fde512a9b95691e0043))
|
|
||||||
|
|
||||||
## [4.6.8](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.7...v4.6.8) (2024-06-14)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* 'Resource ID out of range in GetResource' error in overlay rendering mode ([05286ce](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/05286cedfd17b1a0cb90a5e918513644f47cd831)), closes [#308](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/308)
|
|
||||||
|
|
||||||
## [4.6.7](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.6...v4.6.7) (2024-05-24)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* the ParticleSystem's localPosition drifts at certain scales due to floating-point precision issues ([e924eb4](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/e924eb45968a112347471cabaeabc274e4c37ce4)), closes [#299](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/299) [#312](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/312)
|
|
||||||
|
|
||||||
## [4.6.6](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.5...v4.6.6) (2024-05-23)
|
## [4.6.6](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.5...v4.6.6) (2024-05-23)
|
||||||
|
|
||||||
|
|||||||
@@ -31,35 +31,35 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result.Aggregate(s_Sb, (a, b) =>
|
result.Aggregate(s_Sb, (a, b) => s_Sb.AppendFormat("{0}, ", b));
|
||||||
{
|
|
||||||
s_Sb.Append(b);
|
|
||||||
return s_Sb.Append(", ");
|
|
||||||
});
|
|
||||||
s_Sb.Length -= 2;
|
s_Sb.Length -= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
return s_Sb.ToString();
|
return s_Sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Draw(SerializedProperty sp, List<Material> mats)
|
public static void Draw(SerializedProperty sp, Material[] mats)
|
||||||
{
|
{
|
||||||
var pos = EditorGUILayout.GetControlRect(true);
|
bool isClicked;
|
||||||
var label = new GUIContent(sp.displayName, sp.tooltip);
|
using (new EditorGUILayout.HorizontalScope(GUILayout.ExpandWidth(false)))
|
||||||
var rect = EditorGUI.PrefixLabel(pos, label);
|
{
|
||||||
var text = sp.hasMultipleDifferentValues
|
var pos = EditorGUILayout.GetControlRect(true);
|
||||||
? "-"
|
var label = new GUIContent(sp.displayName, sp.tooltip);
|
||||||
: CollectActiveNames(sp, s_ActiveNames);
|
var rect = EditorGUI.PrefixLabel(pos, label);
|
||||||
|
var text = sp.hasMultipleDifferentValues
|
||||||
|
? "-"
|
||||||
|
: CollectActiveNames(sp, s_ActiveNames);
|
||||||
|
isClicked = GUI.Button(rect, text, EditorStyles.popup);
|
||||||
|
}
|
||||||
|
|
||||||
if (!GUI.Button(rect, text, EditorStyles.popup)) return;
|
if (!isClicked) return;
|
||||||
|
|
||||||
var gm = new GenericMenu();
|
var gm = new GenericMenu();
|
||||||
gm.AddItem(s_ContentNothing, s_ActiveNames.Count == 0, x =>
|
gm.AddItem(s_ContentNothing, s_ActiveNames.Count == 0, () =>
|
||||||
{
|
{
|
||||||
var current = (SerializedProperty)x;
|
sp.ClearArray();
|
||||||
current.ClearArray();
|
sp.serializedObject.ApplyModifiedProperties();
|
||||||
current.serializedObject.ApplyModifiedProperties();
|
});
|
||||||
}, sp);
|
|
||||||
|
|
||||||
if (!sp.hasMultipleDifferentValues)
|
if (!sp.hasMultipleDifferentValues)
|
||||||
{
|
{
|
||||||
@@ -73,7 +73,7 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
s_Names.Clear();
|
s_Names.Clear();
|
||||||
for (var j = 0; j < mats.Count; j++)
|
for (var j = 0; j < mats.Length; j++)
|
||||||
{
|
{
|
||||||
var mat = mats[j];
|
var mat = mats[j];
|
||||||
if (!mat || !mat.shader) continue;
|
if (!mat || !mat.shader) continue;
|
||||||
@@ -82,7 +82,8 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
var name = ShaderUtil.GetPropertyName(mat.shader, i);
|
var name = ShaderUtil.GetPropertyName(mat.shader, i);
|
||||||
var type = (AnimatableProperty.ShaderPropertyType)ShaderUtil.GetPropertyType(mat.shader, i);
|
var type = (AnimatableProperty.ShaderPropertyType)ShaderUtil.GetPropertyType(mat.shader, i);
|
||||||
if (!s_Names.Add(name)) continue;
|
if (s_Names.Contains(name)) continue;
|
||||||
|
s_Names.Add(name);
|
||||||
|
|
||||||
AddMenu(gm, sp, new ShaderProperty(name, type), true);
|
AddMenu(gm, sp, new ShaderProperty(name, type), true);
|
||||||
|
|
||||||
|
|||||||
8
Editor/Internal.meta
Normal file
8
Editor/Internal.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3e440931f761e4e888510a4e6045287a
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -2,19 +2,19 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEditor.UI;
|
|
||||||
using UnityEditorInternal;
|
using UnityEditorInternal;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Profiling;
|
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using Coffee.UIParticleInternal;
|
|
||||||
#if UNITY_2021_2_OR_NEWER
|
#if UNITY_2021_2_OR_NEWER
|
||||||
using UnityEditor.Overlays;
|
using UnityEditor.Overlays;
|
||||||
#else
|
#else
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Coffee.UIParticleInternal;
|
||||||
using Object = UnityEngine.Object;
|
using Object = UnityEngine.Object;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if UNITY_2021_2_OR_NEWER
|
#if UNITY_2021_2_OR_NEWER
|
||||||
using UnityEditor.SceneManagement;
|
using UnityEditor.SceneManagement;
|
||||||
|
|
||||||
@@ -26,31 +26,20 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
[CustomEditor(typeof(UIParticle))]
|
[CustomEditor(typeof(UIParticle))]
|
||||||
[CanEditMultipleObjects]
|
[CanEditMultipleObjects]
|
||||||
internal class UIParticleEditor : GraphicEditor
|
internal class UIParticleEditor : Editor
|
||||||
{
|
{
|
||||||
internal class State : ScriptableSingleton<State>
|
|
||||||
{
|
|
||||||
public bool is3DScaleMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
//################################
|
//################################
|
||||||
// Constant or Static Members.
|
// Constant or Static Members.
|
||||||
//################################
|
//################################
|
||||||
private static readonly GUIContent[] s_ContentMaterials = new[]
|
|
||||||
{
|
|
||||||
new GUIContent("Material"),
|
|
||||||
new GUIContent("Trail Material")
|
|
||||||
};
|
|
||||||
|
|
||||||
private static readonly GUIContent s_ContentRenderingOrder = new GUIContent("Rendering Order");
|
private static readonly GUIContent s_ContentRenderingOrder = new GUIContent("Rendering Order");
|
||||||
private static readonly GUIContent s_ContentRefresh = new GUIContent("Refresh");
|
private static readonly GUIContent s_ContentRefresh = new GUIContent("Refresh");
|
||||||
private static readonly GUIContent s_ContentFix = new GUIContent("Fix");
|
private static readonly GUIContent s_ContentFix = new GUIContent("Fix");
|
||||||
|
private static readonly GUIContent s_ContentMaterial = new GUIContent("Material");
|
||||||
|
private static readonly GUIContent s_ContentTrailMaterial = new GUIContent("Trail Material");
|
||||||
private static readonly GUIContent s_Content3D = new GUIContent("3D");
|
private static readonly GUIContent s_Content3D = new GUIContent("3D");
|
||||||
private static readonly GUIContent s_ContentRandom = new GUIContent("Random");
|
private static readonly GUIContent s_ContentRandom = new GUIContent("Random");
|
||||||
private static readonly GUIContent s_ContentScale = new GUIContent("Scale");
|
private static readonly GUIContent s_ContentScale = new GUIContent("Scale");
|
||||||
private static readonly GUIContent s_ContentPrimary = new GUIContent("Primary");
|
private static bool s_XYZMode;
|
||||||
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 SerializedProperty _maskable;
|
private SerializedProperty _maskable;
|
||||||
private SerializedProperty _scale3D;
|
private SerializedProperty _scale3D;
|
||||||
@@ -60,11 +49,8 @@ namespace Coffee.UIExtensions
|
|||||||
private SerializedProperty _groupMaxId;
|
private SerializedProperty _groupMaxId;
|
||||||
private SerializedProperty _positionMode;
|
private SerializedProperty _positionMode;
|
||||||
private SerializedProperty _autoScalingMode;
|
private SerializedProperty _autoScalingMode;
|
||||||
private SerializedProperty _useCustomView;
|
|
||||||
private SerializedProperty _customViewSize;
|
|
||||||
private ReorderableList _ro;
|
private ReorderableList _ro;
|
||||||
private bool _showMax;
|
private bool _showMax;
|
||||||
private bool _is3DScaleMode;
|
|
||||||
|
|
||||||
private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>();
|
private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>();
|
||||||
#if UNITY_2018 || UNITY_2019
|
#if UNITY_2018 || UNITY_2019
|
||||||
@@ -86,10 +72,8 @@ namespace Coffee.UIExtensions
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// This function is called when the object becomes enabled and active.
|
/// This function is called when the object becomes enabled and active.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected override void OnEnable()
|
private void OnEnable()
|
||||||
{
|
{
|
||||||
base.OnEnable();
|
|
||||||
|
|
||||||
_maskable = serializedObject.FindProperty("m_Maskable");
|
_maskable = serializedObject.FindProperty("m_Maskable");
|
||||||
_scale3D = serializedObject.FindProperty("m_Scale3D");
|
_scale3D = serializedObject.FindProperty("m_Scale3D");
|
||||||
_animatableProperties = serializedObject.FindProperty("m_AnimatableProperties");
|
_animatableProperties = serializedObject.FindProperty("m_AnimatableProperties");
|
||||||
@@ -98,43 +82,31 @@ namespace Coffee.UIExtensions
|
|||||||
_groupMaxId = serializedObject.FindProperty("m_GroupMaxId");
|
_groupMaxId = serializedObject.FindProperty("m_GroupMaxId");
|
||||||
_positionMode = serializedObject.FindProperty("m_PositionMode");
|
_positionMode = serializedObject.FindProperty("m_PositionMode");
|
||||||
_autoScalingMode = serializedObject.FindProperty("m_AutoScalingMode");
|
_autoScalingMode = serializedObject.FindProperty("m_AutoScalingMode");
|
||||||
_useCustomView = serializedObject.FindProperty("m_UseCustomView");
|
|
||||||
_customViewSize = serializedObject.FindProperty("m_CustomViewSize");
|
|
||||||
|
|
||||||
var sp = serializedObject.FindProperty("m_Particles");
|
var sp = serializedObject.FindProperty("m_Particles");
|
||||||
_ro = new ReorderableList(sp.serializedObject, sp, true, true, true, true)
|
_ro = new ReorderableList(sp.serializedObject, sp, true, true, true, true)
|
||||||
{
|
{
|
||||||
elementHeightCallback = index =>
|
elementHeight = EditorGUIUtility.singleLineHeight * 3 + 4,
|
||||||
{
|
elementHeightCallback = _ => 3 * (EditorGUIUtility.singleLineHeight + 2),
|
||||||
var ps = sp.GetArrayElementAtIndex(index).objectReferenceValue as ParticleSystem;
|
|
||||||
var materialCount = 0;
|
|
||||||
if (ps && ps.TryGetComponent<ParticleSystemRenderer>(out var psr))
|
|
||||||
{
|
|
||||||
materialCount = psr.sharedMaterials.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (materialCount + 1) * (EditorGUIUtility.singleLineHeight + 2);
|
|
||||||
},
|
|
||||||
drawElementCallback = (rect, index, _, __) =>
|
drawElementCallback = (rect, index, _, __) =>
|
||||||
{
|
{
|
||||||
rect.y += 2;
|
EditorGUI.BeginDisabledGroup(sp.hasMultipleDifferentValues);
|
||||||
|
rect.y += 1;
|
||||||
rect.height = EditorGUIUtility.singleLineHeight;
|
rect.height = EditorGUIUtility.singleLineHeight;
|
||||||
var p = sp.GetArrayElementAtIndex(index);
|
var p = sp.GetArrayElementAtIndex(index);
|
||||||
EditorGUI.ObjectField(rect, p, GUIContent.none);
|
EditorGUI.ObjectField(rect, p, GUIContent.none);
|
||||||
var ps = p.objectReferenceValue as ParticleSystem;
|
|
||||||
if (!ps || !ps.TryGetComponent<ParticleSystemRenderer>(out var psr)) return;
|
|
||||||
|
|
||||||
rect.x += 15;
|
rect.x += 15;
|
||||||
rect.width -= 15;
|
rect.width -= 15;
|
||||||
var materials = new SerializedObject(psr).FindProperty("m_Materials");
|
var ps = p.objectReferenceValue as ParticleSystem;
|
||||||
var count = Mathf.Min(materials.arraySize, 2);
|
var materials = ps
|
||||||
for (var i = 0; i < count; i++)
|
? new SerializedObject(ps.GetComponent<ParticleSystemRenderer>()).FindProperty("m_Materials")
|
||||||
{
|
: null;
|
||||||
rect.y += rect.height + 2;
|
rect.y += rect.height + 1;
|
||||||
EditorGUI.PropertyField(rect, materials.GetArrayElementAtIndex(i), s_ContentMaterials[i]);
|
MaterialField(rect, s_ContentMaterial, materials, 0);
|
||||||
}
|
rect.y += rect.height + 1;
|
||||||
|
MaterialField(rect, s_ContentTrailMaterial, materials, 1);
|
||||||
if (materials.serializedObject.hasModifiedProperties)
|
EditorGUI.EndDisabledGroup();
|
||||||
|
if (materials != null && materials.serializedObject.hasModifiedProperties)
|
||||||
{
|
{
|
||||||
materials.serializedObject.ApplyModifiedProperties();
|
materials.serializedObject.ApplyModifiedProperties();
|
||||||
}
|
}
|
||||||
@@ -168,18 +140,19 @@ namespace Coffee.UIExtensions
|
|||||||
uip.RefreshParticles(uip.particles);
|
uip.RefreshParticles(uip.particles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize 3D scale mode.
|
private static void MaterialField(Rect rect, GUIContent label, SerializedProperty sp, int index)
|
||||||
_is3DScaleMode = State.instance.is3DScaleMode;
|
{
|
||||||
if (!_is3DScaleMode)
|
if (sp == null || sp.arraySize <= index)
|
||||||
{
|
{
|
||||||
var x = _scale3D.FindPropertyRelative("x");
|
EditorGUI.BeginDisabledGroup(true);
|
||||||
var y = _scale3D.FindPropertyRelative("y");
|
EditorGUI.ObjectField(rect, label, null, typeof(Material), true);
|
||||||
var z = _scale3D.FindPropertyRelative("z");
|
EditorGUI.EndDisabledGroup();
|
||||||
_is3DScaleMode = !Mathf.Approximately(x.floatValue, y.floatValue) ||
|
}
|
||||||
!Mathf.Approximately(y.floatValue, z.floatValue) ||
|
else
|
||||||
y.hasMultipleDifferentValues ||
|
{
|
||||||
z.hasMultipleDifferentValues;
|
EditorGUI.PropertyField(rect, sp.GetArrayElementAtIndex(index), label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +164,6 @@ namespace Coffee.UIExtensions
|
|||||||
var current = target as UIParticle;
|
var current = target as UIParticle;
|
||||||
if (!current) return;
|
if (!current) return;
|
||||||
|
|
||||||
Profiler.BeginSample("(UIP:E) OnInspectorGUI");
|
|
||||||
serializedObject.Update();
|
serializedObject.Update();
|
||||||
|
|
||||||
// Maskable
|
// Maskable
|
||||||
@@ -199,16 +171,17 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
// Scale
|
// Scale
|
||||||
EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4);
|
EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4);
|
||||||
if (DrawFloatOrVector3Field(_scale3D, _is3DScaleMode) != _is3DScaleMode)
|
s_XYZMode = DrawFloatOrVector3Field(_scale3D, s_XYZMode);
|
||||||
{
|
|
||||||
State.instance.is3DScaleMode = _is3DScaleMode = !_is3DScaleMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorGUI.EndDisabledGroup();
|
EditorGUI.EndDisabledGroup();
|
||||||
|
|
||||||
// AnimatableProperties
|
// AnimatableProperties
|
||||||
current.GetMaterials(s_TempMaterials);
|
var mats = current.particles
|
||||||
AnimatablePropertyEditor.Draw(_animatableProperties, s_TempMaterials);
|
.Where(x => x)
|
||||||
|
.Select(x => x.GetComponent<ParticleSystemRenderer>().sharedMaterial)
|
||||||
|
.Where(x => x)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
AnimatablePropertyEditor.Draw(_animatableProperties, mats);
|
||||||
|
|
||||||
// Mesh sharing
|
// Mesh sharing
|
||||||
EditorGUI.BeginChangeCheck();
|
EditorGUI.BeginChangeCheck();
|
||||||
@@ -216,12 +189,9 @@ namespace Coffee.UIExtensions
|
|||||||
if (EditorGUI.EndChangeCheck())
|
if (EditorGUI.EndChangeCheck())
|
||||||
{
|
{
|
||||||
serializedObject.ApplyModifiedProperties();
|
serializedObject.ApplyModifiedProperties();
|
||||||
foreach (var t in targets)
|
foreach (var uip in targets.OfType<UIParticle>())
|
||||||
{
|
{
|
||||||
if (t is UIParticle uip)
|
uip.ResetGroupId();
|
||||||
{
|
|
||||||
uip.ResetGroupId();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,29 +199,16 @@ namespace Coffee.UIExtensions
|
|||||||
EditorGUILayout.PropertyField(_positionMode);
|
EditorGUILayout.PropertyField(_positionMode);
|
||||||
|
|
||||||
// Auto Scaling
|
// Auto Scaling
|
||||||
EditorGUILayout.PropertyField(_autoScalingMode);
|
DrawAutoScaling(_autoScalingMode, targets.OfType<UIParticle>());
|
||||||
|
|
||||||
// Custom View Size
|
|
||||||
EditorGUILayout.PropertyField(_useCustomView);
|
|
||||||
EditorGUI.BeginChangeCheck();
|
|
||||||
EditorGUI.BeginDisabledGroup(!_useCustomView.boolValue);
|
|
||||||
EditorGUI.indentLevel++;
|
|
||||||
EditorGUILayout.PropertyField(_customViewSize);
|
|
||||||
EditorGUI.indentLevel--;
|
|
||||||
EditorGUI.EndDisabledGroup();
|
|
||||||
if (EditorGUI.EndChangeCheck())
|
|
||||||
{
|
|
||||||
_customViewSize.floatValue = Mathf.Max(0.1f, _customViewSize.floatValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Target ParticleSystems.
|
// Target ParticleSystems.
|
||||||
EditorGUI.BeginChangeCheck();
|
EditorGUI.BeginChangeCheck();
|
||||||
|
EditorGUI.BeginDisabledGroup(targets.OfType<UIParticle>().Any(x => !x.canvas));
|
||||||
_ro.DoLayoutList();
|
_ro.DoLayoutList();
|
||||||
|
EditorGUI.EndDisabledGroup();
|
||||||
serializedObject.ApplyModifiedProperties();
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
|
||||||
if (EditorGUI.EndChangeCheck())
|
if (EditorGUI.EndChangeCheck())
|
||||||
{
|
{
|
||||||
EditorApplication.QueuePlayerLoopUpdate();
|
|
||||||
foreach (var uip in targets.OfType<UIParticle>())
|
foreach (var uip in targets.OfType<UIParticle>())
|
||||||
{
|
{
|
||||||
uip.RefreshParticles(uip.particles);
|
uip.RefreshParticles(uip.particles);
|
||||||
@@ -259,8 +216,7 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Non-UI built-in shader is not supported.
|
// Non-UI built-in shader is not supported.
|
||||||
Profiler.BeginSample("(UIP:E) Non-UI built-in shader is not supported.");
|
foreach (var mat in current.materials)
|
||||||
foreach (var mat in s_TempMaterials)
|
|
||||||
{
|
{
|
||||||
if (!mat || !mat.shader) continue;
|
if (!mat || !mat.shader) continue;
|
||||||
var shader = mat.shader;
|
var shader = mat.shader;
|
||||||
@@ -273,18 +229,15 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Profiler.EndSample();
|
|
||||||
|
|
||||||
// Does the shader support UI masks?
|
// Does the shader support UI masks?
|
||||||
Profiler.BeginSample("(UIP:E) Does the shader support UI masks?");
|
|
||||||
if (current.maskable && current.GetComponentInParent<Mask>(false))
|
if (current.maskable && current.GetComponentInParent<Mask>(false))
|
||||||
{
|
{
|
||||||
foreach (var mat in s_TempMaterials)
|
foreach (var mat in current.materials)
|
||||||
{
|
{
|
||||||
if (!mat || !mat.shader) continue;
|
if (!mat || !mat.shader) continue;
|
||||||
var shader = mat.shader;
|
var shader = mat.shader;
|
||||||
if (!s_Shaders.Add(shader)) continue;
|
if (s_Shaders.Contains(shader)) continue;
|
||||||
|
s_Shaders.Add(shader);
|
||||||
foreach (var propName in s_MaskablePropertyNames)
|
foreach (var propName in s_MaskablePropertyNames)
|
||||||
{
|
{
|
||||||
if (mat.HasProperty(propName)) continue;
|
if (mat.HasProperty(propName)) continue;
|
||||||
@@ -298,9 +251,7 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s_TempMaterials.Clear();
|
|
||||||
s_Shaders.Clear();
|
s_Shaders.Clear();
|
||||||
Profiler.EndSample();
|
|
||||||
|
|
||||||
// UIParticle for trail should be removed.
|
// UIParticle for trail should be removed.
|
||||||
var label = "This UIParticle component should be removed. The UIParticle for trails is no longer needed.";
|
var label = "This UIParticle component should be removed. The UIParticle for trails is no longer needed.";
|
||||||
@@ -339,14 +290,12 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
Profiler.EndSample();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsBuiltInObject(Object obj)
|
private bool IsBuiltInObject(Object obj)
|
||||||
{
|
{
|
||||||
return AssetDatabase.IsMainAsset(obj)
|
return AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj, out var guid, out long _)
|
||||||
&& AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj, out var guid, out long _)
|
&& Regex.IsMatch(guid, "^0{16}.0{15}$", RegexOptions.Compiled);
|
||||||
&& s_RegexBuiltInGuid.IsMatch(guid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_2018 || UNITY_2019
|
#if UNITY_2018 || UNITY_2019
|
||||||
@@ -440,7 +389,7 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
EditorGUI.BeginDisabledGroup(true);
|
EditorGUI.BeginDisabledGroup(true);
|
||||||
var obj = UIParticleUpdater.GetPrimary(spGroupId.intValue);
|
var obj = UIParticleUpdater.GetPrimary(spGroupId.intValue);
|
||||||
EditorGUILayout.ObjectField(s_ContentPrimary, obj, typeof(UIParticle), false);
|
EditorGUILayout.ObjectField("Primary", obj, typeof(UIParticle), false);
|
||||||
EditorGUI.EndDisabledGroup();
|
EditorGUI.EndDisabledGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,7 +399,7 @@ namespace Coffee.UIExtensions
|
|||||||
return showMax;
|
return showMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DrawAutoScaling(SerializedProperty prop)
|
private static void DrawAutoScaling(SerializedProperty prop, IEnumerable<UIParticle> uiParticles)
|
||||||
{
|
{
|
||||||
EditorGUILayout.PropertyField(prop);
|
EditorGUILayout.PropertyField(prop);
|
||||||
}
|
}
|
||||||
@@ -459,9 +408,7 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
if (!p || (ignoreCurrent && target == p)) return;
|
if (!p || (ignoreCurrent && target == p)) return;
|
||||||
|
|
||||||
var cr = p.canvasRenderer;
|
|
||||||
DestroyImmediate(p);
|
DestroyImmediate(p);
|
||||||
DestroyImmediate(cr);
|
|
||||||
|
|
||||||
#if UNITY_2018_3_OR_NEWER
|
#if UNITY_2018_3_OR_NEWER
|
||||||
var stage = PrefabStageUtility.GetCurrentPrefabStage();
|
var stage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||||
|
|||||||
236
README.md
236
README.md
@@ -1,85 +1,61 @@
|
|||||||
# <img alt="UIParticleIcon" src="https://github.com/mob-sakai/ParticleEffectForUGUI/assets/12690315/d76e105e-a840-4f61-a1f6-8cf311c0812d" width="26"/> Particle Effect For UGUI (UI Particle) <!-- omit in toc -->
|
# <img alt="UIParticleIcon" src="https://github.com/mob-sakai/ParticleEffectForUGUI/assets/12690315/d76e105e-a840-4f61-a1f6-8cf311c0812d" width="26"/> Particle Effect For UGUI (UI Particle)
|
||||||
|
|
||||||
|
This package provides a component to render particle effects for uGUI in Unity 2018.2 or later.
|
||||||
|
The particle rendering is maskable and sortable, without the need for an extra Camera, RenderTexture, or Canvas.
|
||||||
|
|
||||||
[](https://openupm.com/packages/com.coffee.ui-particle/)
|
[](https://openupm.com/packages/com.coffee.ui-particle/)
|
||||||
[](https://github.com/mob-sakai/ParticleEffectForUGUI/releases)
|
[](https://github.com/mob-sakai/ParticleEffectForUGUI/releases)
|
||||||
[](https://github.com/mob-sakai/ParticleEffectForUGUI/blob/main/LICENSE.md)
|
[](https://github.com/mob-sakai/ParticleEffectForUGUI/blob/main/LICENSE.txt)
|
||||||

|

|
||||||

|
|
||||||

|
|
||||||

|

|
||||||
[](http://makeapullrequest.com)
|
[](http://makeapullrequest.com)
|
||||||
[](https://github.com/mob-sakai/ParticleEffectForUGUI/subscription)
|
|
||||||
[](https://twitter.com/intent/follow?screen_name=mob_sakai)
|
[](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) | [🎮 Demo](#-demo) | [⚙ Installation](#-installation) | [🚀 Usage](#-usage) | [🛠 Development Note](#-development-note) | [🤝 Contributing](#-contributing) >>
|
||||||
|
|
||||||
## 📝 Description <!-- omit in toc -->
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
This package uses the new APIs `MeshBake/MeshTrailBake` (introduced in Unity 2018.2) to render particles through `CanvasRenderer`.
|
|
||||||
You can render, mask, and sort your `ParticleSystems` for UI without the need for an additional `Camera`, `RenderTexture`, or `Canvas`.
|
|
||||||
|
|
||||||
- [📌 Key Features](#-key-features)
|
|
||||||
- [🎮 Demo](#-demo)
|
|
||||||
- [⚙ Installation](#-installation)
|
|
||||||
- [Install via OpenUPM](#install-via-openupm)
|
|
||||||
- [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)
|
|
||||||
- [🚀 Usage](#-usage)
|
|
||||||
- [Component: UIParticle](#component-uiparticle)
|
|
||||||
- [Basic Usage](#basic-usage)
|
|
||||||
- [Usage with Your Existing ParticleSystem Prefab](#usage-with-your-existing-particlesystem-prefab)
|
|
||||||
- [Usage with `Mask` or `RectMask2D` Component](#usage-with-mask-or-rectmask2d-component)
|
|
||||||
- [Usage with Script](#usage-with-script)
|
|
||||||
- [Component: UIParticleAttractor](#component-uiparticleattractor)
|
|
||||||
- [Project Settings](#project-settings)
|
|
||||||
- [🛠 Development Note](#-development-note)
|
|
||||||
- [Compares the Baking mesh approach with the conventional approach](#compares-the-baking-mesh-approach-with-the-conventional-approach)
|
|
||||||
- [Performance test results](#performance-test-results)
|
|
||||||
- [🔍 FAQ: Why Are My UIParticles Not Displayed Correctly?](#-faq-why-are-my-uiparticles-not-displayed-correctly)
|
|
||||||
- [Shader Limitation](#shader-limitation)
|
|
||||||
- [Built-in shaders are not supported](#built-in-shaders-are-not-supported)
|
|
||||||
- [(Unity 2018 or 2019) UV.zw components will be discarded](#unity-2018-or-2019-uvzw-components-will-be-discarded)
|
|
||||||
- [(Unity 2018 or 2019) Custom vertex streams](#unity-2018-or-2019-custom-vertex-streams)
|
|
||||||
- [Overheads](#overheads)
|
|
||||||
- [How to Make a Custom Shader to Support `Mask` and `RectMask2D` Component](#how-to-make-a-custom-shader-to-support-mask-and-rectmask2d-component)
|
|
||||||
- [🤝 Contributing](#-contributing)
|
|
||||||
- [Issues](#issues)
|
|
||||||
- [Pull Requests](#pull-requests)
|
|
||||||
- [Support](#support)
|
|
||||||
- [License](#license)
|
|
||||||
- [Author](#author)
|
|
||||||
- [See Also](#see-also)
|
|
||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
## 📌 Key Features
|
## 📝 Description
|
||||||
|
|
||||||
* **Easy to use:** The package is ready to use out of the box.
|

|
||||||
* **Sortable:** Sort particle effects and other UI elements by sibling index.
|
|
||||||
* **Maskable:** Supports `Mask` or `RectMask2D`.
|
This package utilizes the new APIs `MeshBake/MashTrailBake` (introduced with Unity 2018.2) to render particles through
|
||||||
* **No extra components required:** No need for an additional `Camera`, `RenderTexture`, or `Canvas`.
|
CanvasRenderer.
|
||||||
* **Trail module support:** Fully supports the Trail module.
|
You can render, mask, and sort your ParticleSystems for UI without the necessity of an additional Camera, RenderTexture,
|
||||||
* **CanvasGroup alpha support:** Integrates with `CanvasGroup` alpha.
|
or Canvas.
|
||||||
* **No allocations:** Efficiently renders particles without allocations.
|
|
||||||
* **Any canvas render mode support:** Works with overlay, camera space, and world space.
|
### Features
|
||||||
* **Any Render pipeline support:** Compatible with Universal Render Pipeline (URP) and High Definition Render Pipeline (HDRP).
|
|
||||||
* **Disabling domain reload support:** Supports disabling `Enter Play Mode Options > Reload Domain`.
|
* Easy to use: The package is ready to use out of the box.
|
||||||
* **Animatable material properties:** Supports changing material properties with AnimationClip (AnimatableProperty).
|
* Sort particle effects and other UI by sibling index.
|
||||||

|
* No extra Camera, RenderTexture, or Canvas required.
|
||||||
* **Multiple materials:** Supports 8+ materials.
|
* Masking options for Mask or RectMask2D.
|
||||||
* **Correct positioning:** Adjusts world space particle positions correctly when changing window size for standalone platforms (Windows, MacOSX, and Linux).
|
* Support for the Trail module.
|
||||||
* **Adaptive scaling:** Provides adaptive scaling for UI (AutoScalingMode).
|
* Support for CanvasGroup alpha.
|
||||||
* **Performance optimization:** Mesh sharing group to improve performance.
|
* No allocations needed to render particles.
|
||||||
<img alt="MeshSharing.gif" src="https://user-images.githubusercontent.com/12690315/174311048-c882df81-6c34-4eba-b0aa-5645457692f1.gif" width="450"/>
|
* Compatibility with overlay, camera space, and world space.
|
||||||
* **Particle attractor:** Includes a particle attractor component.
|
* Support for Universal Render Pipeline (URP) and High Definition Render Pipeline (HDRP).
|
||||||
<img alt="ParticleAttractor.gif" src="https://user-images.githubusercontent.com/12690315/174311027-462929a4-13f0-4ec4-86ea-9c832f2eecf1.gif" width="450"/>
|
* Support for disabling `Enter Play Mode Options > Reload Domain`.
|
||||||
* **Emission position mode:** Supports relative/absolute particle emission position modes.
|
* Support for changing material property with AnimationClip (AnimatableProperty).
|
||||||
<img alt="AbsolutePosition.gif" src="https://user-images.githubusercontent.com/12690315/175751579-5a2357e8-2ecf-4afd-83c8-66e9771bde39.gif" width="450"/>
|
![AnimatableProperty.gif][AnimatableProperty.gif]
|
||||||
* **Custom view size:** Fixes min/max particle size mismatch.
|
* [4.0.0+] Support for 8+ materials.
|
||||||

|
* [4.0.0+] Correct world space particle position adjustment when changing window size for standalone platforms (Windows,
|
||||||
|
MacOSX, and Linux).
|
||||||
|
* [4.0.0+] Adaptive scaling for UI.
|
||||||
|
* [4.0.0+] Mesh sharing group to improve performance.
|
||||||
|
![MeshSharing.gif][MeshSharing.gif]
|
||||||
|
* [4.0.0+] Particle attractor component.
|
||||||
|
![ParticleAttractor.gif][ParticleAttractor.gif]
|
||||||
|
* [4.1.0+] Relative/Absolute particle position mode.
|
||||||
|
![AbsolutePosition.gif][AbsolutePosition.gif]
|
||||||
|
|
||||||
|
[AnimatableProperty.gif]: https://user-images.githubusercontent.com/12690315/53286323-2d94a980-37b0-11e9-8afb-c4a207805ff2.gif
|
||||||
|
|
||||||
|
[MeshSharing.gif]: https://user-images.githubusercontent.com/12690315/174311048-c882df81-6c34-4eba-b0aa-5645457692f1.gif
|
||||||
|
|
||||||
|
[ParticleAttractor.gif]: https://user-images.githubusercontent.com/12690315/174311027-462929a4-13f0-4ec4-86ea-9c832f2eecf1.gif
|
||||||
|
|
||||||
|
[AbsolutePosition.gif]: https://user-images.githubusercontent.com/12690315/175751579-5a2357e8-2ecf-4afd-83c8-66e9771bde39.gif
|
||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
@@ -100,86 +76,76 @@ You can render, mask, and sort your `ParticleSystems` for UI without the need fo
|
|||||||
|
|
||||||
[JMO]: https://assetstore.unity.com/publishers/1669
|
[JMO]: https://assetstore.unity.com/publishers/1669
|
||||||
|
|
||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
## ⚙ Installation
|
## ⚙ Installation
|
||||||
|
|
||||||
_This package requires **Unity 2018.3 or later**._
|
_This package requires Unity 2018.3 or later._
|
||||||
|
|
||||||
#### Install via OpenUPM
|
#### Install via OpenUPM
|
||||||
|
|
||||||
- This package is available on [OpenUPM](https://openupm.com) package registry.
|
This package is available on [OpenUPM](https://openupm.com) package registry.
|
||||||
- This is the preferred method of installation, as you can easily receive updates as they're released.
|
This is the preferred method of installation, as you can easily receive updates as they're released.
|
||||||
- If you have [openupm-cli](https://github.com/openupm/openupm-cli) installed, then run the following command in your project's directory:
|
|
||||||
```
|
|
||||||
openupm add com.coffee.ui-particle
|
|
||||||
```
|
|
||||||
- To update the package, use Package Manager UI (`Window > Package Manager`) or run the following command with `@{version}`:
|
|
||||||
```
|
|
||||||
openupm add com.coffee.ui-particle@4.9.0
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Install via UPM (with Package Manager UI)
|
If you have [openupm-cli](https://github.com/openupm/openupm-cli) installed, then run the following command in your
|
||||||
|
project's directory:
|
||||||
|
|
||||||
- Click `Window > Package Manager` to open Package Manager UI.
|
```sh
|
||||||
- Click `+ > Add package from git URL...` and input the repository URL: `https://github.com/mob-sakai/ParticleEffectForUGUI.git`
|
openupm add com.coffee.ui-particle
|
||||||

|
```
|
||||||
- To update the package, change suffix `#{version}` to the target version.
|
|
||||||
- e.g. `https://github.com/mob-sakai/ParticleEffectForUGUI.git#4.9.0`
|
|
||||||
|
|
||||||
#### Install via UPM (Manually)
|
#### Install via UPM (using Git URL)
|
||||||
|
|
||||||
- Open the `Packages/manifest.json` file in your project. Then add this package somewhere in the `dependencies` block:
|
Navigate to your project's Packages folder and open the `manifest.json` file. Then add this package somewhere in
|
||||||
```json
|
the `dependencies` block:
|
||||||
{
|
|
||||||
"dependencies": {
|
```json
|
||||||
"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git",
|
{
|
||||||
...
|
"dependencies": {
|
||||||
}
|
"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git",
|
||||||
|
...
|
||||||
}
|
}
|
||||||
```
|
}
|
||||||
|
```
|
||||||
|
|
||||||
- To update the package, change suffix `#{version}` to the target version.
|
To update the package, change suffix `#{version}` to the target version.
|
||||||
- e.g. `"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git#4.9.0",`
|
|
||||||
|
|
||||||
#### Install as Embedded Package
|
* e.g. `"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git#4.6.0",`
|
||||||
|
|
||||||
1. Download a source code zip file from [Releases](https://github.com/mob-sakai/ParticleEffectForUGUI.git/releases) and extract it.
|
Or, use [UpmGitExtension](https://github.com/mob-sakai/UpmGitExtension) to install and update the package.
|
||||||
2. Place it in your project's `Packages` directory.
|
|
||||||

|
<br><br>
|
||||||
- If you want to fix bugs or add features, install it as an embedded package.
|
|
||||||
- To update the package, you need to re-download it and replace the contents.
|
## ⚙ 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`.
|
||||||
|
-
|
||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
## 🚀 Usage
|
## 🚀 Usage
|
||||||
|
|
||||||
### Component: UIParticle
|
### UIParticle Component
|
||||||
|
|
||||||
`UIParticle` controls the ParticleSystems that are attached to its own game objects and child game objects.
|
`UIParticle` controls the ParticleSystems that are attached to its own game objects and child game objects.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- **Maskable**: Does this graphic allow maskable.
|
- **Maskable**: Does this graphic allow masking.
|
||||||
- **Scale**: Scale the rendering particles. When the `3D` toggle is enabled, 3D scale (x, y, z) is supported.
|
- **Scale**: Scale the rendering. When the `3D` toggle is enabled, 3D scale (x, y, z) is supported.
|
||||||
- **Animatable Properties**: If you want to update material properties (e.g., `_MainTex_ST`, `_Color`) in AnimationClip,
|
- **Animatable Properties**: If you want to update material properties (e.g., `_MainTex_ST`, `_Color`) in AnimationClip,
|
||||||
use this to mark as animatable.
|
use this to mark the changes.
|
||||||
- **Mesh Sharing**: Particle simulation results are shared within the same group. A large number of the same effects can
|
- **Mesh Sharing**: Particle simulation results are shared within the same group. A large number of the same effects can
|
||||||
be displayed with a small load. When the `Random` toggle is enabled, it will be grouped randomly.
|
be displayed with a small load. When the `Random` toggle is enabled, it will be grouped randomly.
|
||||||
- **None:** Disable mesh sharing.
|
|
||||||
- **Auto:** Automatically select Primary/Replica.
|
|
||||||
- **Primary:** Provides particle simulation results to the same group.
|
|
||||||
- **Primary Simulator:** Primary, but do not render the particle (simulation only).
|
|
||||||
- **Replica:** Render simulation results provided by the primary.
|
|
||||||
- **Position Mode**: Emission position mode.
|
- **Position Mode**: Emission position mode.
|
||||||
- **Absolute:** The particles will be emitted from the world position.
|
- **Absolute:** Emit from the world position of the `ParticleSystem`.
|
||||||
- **Relative:** The particles will be emitted from the scaled position.
|
- **Relative:** Emit from the scaled position of the `ParticleSystem`.
|
||||||
- **Auto Scaling Mode**: How to automatically adjust when the Canvas scale is changed by the screen size or reference resolution.
|
- **Auto Scaling**: `Transform.lossyScale` (=world scale) will be set to `(1, 1, 1)` on update. It prevents the
|
||||||
- **None:** Do nothing.
|
root-Canvas scale from affecting the hierarchy-scaled `ParticleSystem`.
|
||||||
- **Transform:** Transform.lossyScale (=world scale) will be set to (1, 1, 1).
|
|
||||||
- **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.
|
|
||||||
- **Rendering Order**: The ParticleSystem list to be rendered. You can change the order and the materials.
|
- **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
|
**NOTE:** Press the `Refresh` button to reconstruct the rendering order based on children ParticleSystem's sorting order
|
||||||
@@ -187,7 +153,7 @@ and z-position.
|
|||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
### Basic Usage
|
#### Basic Usage
|
||||||
|
|
||||||
1. Select `GameObject/UI/ParticleSystem` to create UIParticle with a ParticleSystem.
|
1. Select `GameObject/UI/ParticleSystem` to create UIParticle with a ParticleSystem.
|
||||||

|

|
||||||
@@ -196,7 +162,7 @@ and z-position.
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
### Usage with Your Existing ParticleSystem Prefab
|
#### With Your Existing ParticleSystem Prefab
|
||||||
|
|
||||||
1. Select `GameObject/UI/ParticleSystem (Empty)` to create UIParticle.
|
1. Select `GameObject/UI/ParticleSystem (Empty)` to create UIParticle.
|
||||||

|

|
||||||
@@ -205,7 +171,7 @@ and z-position.
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
### Usage with `Mask` or `RectMask2D` Component
|
#### With `Mask` or `RectMask2D` Component
|
||||||
|
|
||||||
If you want to mask particles, set a stencil-supported shader (such as `UI/UIAdditive`) to the material for
|
If you want to mask particles, set a stencil-supported shader (such as `UI/UIAdditive`) to the material for
|
||||||
ParticleSystem.
|
ParticleSystem.
|
||||||
@@ -217,7 +183,7 @@ section.
|
|||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
### Usage with Script
|
### Script usage
|
||||||
|
|
||||||
```cs
|
```cs
|
||||||
// Instantiate ParticleSystem prefab with UIParticle on runtime.
|
// Instantiate ParticleSystem prefab with UIParticle on runtime.
|
||||||
@@ -236,14 +202,14 @@ uiParticle.Stop();
|
|||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
### Component: UIParticleAttractor
|
### UIParticleAttractor component
|
||||||
|
|
||||||
`UIParticleAttractor` attracts particles generated by the specified ParticleSystem.
|
`UIParticleAttractor` attracts particles generated by the specified ParticleSystem.
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
- **Particle Systems**: Attracts particles generated by the specified ParticleSystems.
|
- **Particle System**: Attracts particles generated by the specified particle system.
|
||||||
- **Destination Radius**: Once the particle is within the radius, the particle lifetime will become 0, and `OnAttracted`
|
- **Destination Radius**: Once the particle is within the radius, the particle lifetime will become 0, and `OnAttracted`
|
||||||
will be called.
|
will be called.
|
||||||
- **Delay Rate**: Delay to start attracting. It is a percentage of the particle's start lifetime.
|
- **Delay Rate**: Delay to start attracting. It is a percentage of the particle's start lifetime.
|
||||||
@@ -257,14 +223,6 @@ uiParticle.Stop();
|
|||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
### Project Settings
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
- Click `Edit > Project Settings` to open the Project Settings window and then select `UI > UI Particle` category.
|
|
||||||
|
|
||||||
<br><br>
|
|
||||||
|
|
||||||
## 🛠 Development Note
|
## 🛠 Development Note
|
||||||
|
|
||||||
### Compares the Baking mesh approach with the conventional approach
|
### Compares the Baking mesh approach with the conventional approach
|
||||||
@@ -396,7 +354,7 @@ When improving performance, keep the following in mind:
|
|||||||
- Consider a single material, atlasing the sprites, and using `Sprite` mode in the `Texture Sheet Animation` module
|
- Consider a single material, atlasing the sprites, and using `Sprite` mode in the `Texture Sheet Animation` module
|
||||||
in the ParticleSystem.
|
in the ParticleSystem.
|
||||||
|
|
||||||
### How to Make a Custom Shader to Support `Mask` and `RectMask2D` Component
|
### How to Make a Custom Shader to Support Mask/RectMask2D Component
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Shader tips</summary>
|
<summary>Shader tips</summary>
|
||||||
|
|||||||
Binary file not shown.
@@ -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:
|
|
||||||
@@ -18,10 +18,10 @@ namespace Coffee.UIParticleInternal
|
|||||||
public static T[] GetComponentsInChildren<T>(this Component self, int depth)
|
public static T[] GetComponentsInChildren<T>(this Component self, int depth)
|
||||||
where T : Component
|
where T : Component
|
||||||
{
|
{
|
||||||
var results = InternalListPool<T>.Rent();
|
var results = ListPool<T>.Rent();
|
||||||
self.GetComponentsInChildren_Internal(results, depth);
|
self.GetComponentsInChildren_Internal(results, depth);
|
||||||
var array = results.ToArray();
|
var array = results.ToArray();
|
||||||
InternalListPool<T>.Return(ref results);
|
ListPool<T>.Return(ref results);
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
var childCount = tr.childCount;
|
var childCount = tr.childCount;
|
||||||
for (var i = 0; i < childCount; i++)
|
for (var i = 0; i < childCount; i++)
|
||||||
{
|
{
|
||||||
tr.GetChild(i).GetComponentsInChildren_Internal(results, depth - 1);
|
tr.GetChild(i).GetComponentsInChildren(results, depth - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,35 +134,6 @@ namespace Coffee.UIParticleInternal
|
|||||||
Profiler.EndSample();
|
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
|
#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
|
public static T GetComponentInParent<T>(this Component self, bool includeInactive) where T : Component
|
||||||
{
|
{
|
||||||
|
|||||||
19
Runtime/Internal/Extensions/ListExtensions.cs
Normal file
19
Runtime/Internal/Extensions/ListExtensions.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for Component class.
|
||||||
|
/// </summary>
|
||||||
|
internal static class ListExtensions
|
||||||
|
{
|
||||||
|
public static void RemoveAtFast<T>(this List<T> self, int index)
|
||||||
|
{
|
||||||
|
if (self == null) return;
|
||||||
|
|
||||||
|
var lastIndex = self.Count - 1;
|
||||||
|
self[index] = self[lastIndex];
|
||||||
|
self.RemoveAt(lastIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Runtime/Internal/Extensions/ListExtensions.cs.meta
Normal file
11
Runtime/Internal/Extensions/ListExtensions.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 833553390099d40c9b212823f0852c46
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,27 +1,11 @@
|
|||||||
using System;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
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
|
namespace Coffee.UIParticleInternal
|
||||||
{
|
{
|
||||||
internal static class Misc
|
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)
|
public static void Destroy(Object obj)
|
||||||
{
|
{
|
||||||
if (!obj) return;
|
if (!obj) return;
|
||||||
@@ -60,17 +44,5 @@ namespace Coffee.UIParticleInternal
|
|||||||
EditorUtility.SetDirty(obj);
|
EditorUtility.SetDirty(obj);
|
||||||
#endif
|
#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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 182319ecc315e4858b119764af0fbcb0
|
guid: 39ed6a6b0a72e482488bd298b2ae762e
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -17,15 +17,11 @@ namespace Coffee.UIParticleInternal
|
|||||||
Type.GetType("UnityEditor.Experimental.U2D.SpriteEditorExtension, UnityEditor")
|
Type.GetType("UnityEditor.Experimental.U2D.SpriteEditorExtension, UnityEditor")
|
||||||
?? Type.GetType("UnityEditor.U2D.SpriteEditorExtension, UnityEditor");
|
?? Type.GetType("UnityEditor.U2D.SpriteEditorExtension, UnityEditor");
|
||||||
|
|
||||||
private static readonly Func<Sprite, Texture2D> s_GetActiveAtlasTextureMethod =
|
private static readonly MethodInfo s_GetActiveAtlasTextureMethod = s_SpriteEditorExtensionType
|
||||||
(Func<Sprite, Texture2D>)Delegate.CreateDelegate(typeof(Func<Sprite, Texture2D>),
|
.GetMethod("GetActiveAtlasTexture", BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
s_SpriteEditorExtensionType
|
|
||||||
.GetMethod("GetActiveAtlasTexture", BindingFlags.Static | BindingFlags.NonPublic));
|
|
||||||
|
|
||||||
private static readonly Func<Sprite, SpriteAtlas> s_GetActiveAtlasMethod =
|
private static readonly MethodInfo s_GetActiveAtlasMethod = s_SpriteEditorExtensionType
|
||||||
(Func<Sprite, SpriteAtlas>)Delegate.CreateDelegate(typeof(Func<Sprite, SpriteAtlas>),
|
.GetMethod("GetActiveAtlas", BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
s_SpriteEditorExtensionType
|
|
||||||
.GetMethod("GetActiveAtlas", BindingFlags.Static | BindingFlags.NonPublic));
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the actual texture of a sprite in play mode or edit mode.
|
/// Get the actual texture of a sprite in play mode or edit mode.
|
||||||
@@ -34,7 +30,9 @@ namespace Coffee.UIParticleInternal
|
|||||||
{
|
{
|
||||||
if (!self) return null;
|
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;
|
return ret ? ret : self.texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +43,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
{
|
{
|
||||||
if (!self) return null;
|
if (!self) return null;
|
||||||
|
|
||||||
return s_GetActiveAtlasMethod(self);
|
return s_GetActiveAtlasMethod.Invoke(null, new object[] { self }) as SpriteAtlas;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Object = UnityEngine.Object;
|
using Object = UnityEngine.Object;
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
using System.IO;
|
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEditor.Build;
|
using UnityEditor.Build;
|
||||||
using UnityEditor.Build.Reporting;
|
using UnityEditor.Build.Reporting;
|
||||||
@@ -13,51 +13,41 @@ namespace Coffee.UIParticleInternal
|
|||||||
{
|
{
|
||||||
public abstract class PreloadedProjectSettings : ScriptableObject
|
public abstract class PreloadedProjectSettings : ScriptableObject
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
|
, IPreprocessBuildWithReport
|
||||||
{
|
{
|
||||||
private class Postprocessor : AssetPostprocessor
|
int IOrderedCallback.callbackOrder => 0;
|
||||||
|
|
||||||
|
void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report)
|
||||||
{
|
{
|
||||||
private static void OnPostprocessAllAssets(string[] _, string[] __, string[] ___, string[] ____)
|
Initialize();
|
||||||
{
|
|
||||||
Initialize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class PreprocessBuildWithReport : IPreprocessBuildWithReport
|
|
||||||
{
|
|
||||||
int IOrderedCallback.callbackOrder => 0;
|
|
||||||
|
|
||||||
void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report)
|
|
||||||
{
|
|
||||||
Initialize();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[InitializeOnLoadMethod]
|
||||||
|
[InitializeOnEnterPlayMode]
|
||||||
private static void Initialize()
|
private static void Initialize()
|
||||||
{
|
{
|
||||||
|
const BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
|
||||||
foreach (var t in TypeCache.GetTypesDerivedFrom(typeof(PreloadedProjectSettings<>)))
|
foreach (var t in TypeCache.GetTypesDerivedFrom(typeof(PreloadedProjectSettings<>)))
|
||||||
{
|
{
|
||||||
var defaultSettings = GetDefaultSettings(t);
|
var defaultSettings = GetDefaultSettings(t);
|
||||||
if (!defaultSettings)
|
if (!defaultSettings)
|
||||||
{
|
{
|
||||||
// When create a new instance, automatically set it as default settings.
|
defaultSettings = t.GetProperty("instance", flags)
|
||||||
defaultSettings = CreateInstance(t) as PreloadedProjectSettings;
|
?.GetValue(null, null) as PreloadedProjectSettings;
|
||||||
SetDefaultSettings(defaultSettings);
|
SetDefaultSettings(defaultSettings);
|
||||||
}
|
}
|
||||||
else if (GetPreloadedSettings(t).Length != 1)
|
else if (GetPreloadedSettings(t).Length != 1)
|
||||||
{
|
{
|
||||||
SetDefaultSettings(defaultSettings);
|
SetDefaultSettings(defaultSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultSettings)
|
|
||||||
{
|
|
||||||
defaultSettings.OnInitialize();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EditorApplication.QueuePlayerLoopUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static string GetDefaultName(Type type, bool nicify)
|
protected static string GetDefaultName(Type type, bool nicify)
|
||||||
{
|
{
|
||||||
var typeName = type.Name;
|
var typeName = type.Name.Replace("ProjectSettings", "");
|
||||||
return nicify
|
return nicify
|
||||||
? ObjectNames.NicifyVariableName(typeName)
|
? ObjectNames.NicifyVariableName(typeName)
|
||||||
: typeName;
|
: typeName;
|
||||||
@@ -81,8 +71,6 @@ namespace Coffee.UIParticleInternal
|
|||||||
|
|
||||||
protected static void SetDefaultSettings(PreloadedProjectSettings asset)
|
protected static void SetDefaultSettings(PreloadedProjectSettings asset)
|
||||||
{
|
{
|
||||||
if (!asset) return;
|
|
||||||
|
|
||||||
var type = asset.GetType();
|
var type = asset.GetType();
|
||||||
if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(asset)))
|
if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(asset)))
|
||||||
{
|
{
|
||||||
@@ -93,11 +81,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
|
|
||||||
var assetPath = $"Assets/ProjectSettings/{GetDefaultName(type, false)}.asset";
|
var assetPath = $"Assets/ProjectSettings/{GetDefaultName(type, false)}.asset";
|
||||||
assetPath = AssetDatabase.GenerateUniqueAssetPath(assetPath);
|
assetPath = AssetDatabase.GenerateUniqueAssetPath(assetPath);
|
||||||
if (!File.Exists(assetPath))
|
AssetDatabase.CreateAsset(asset, assetPath);
|
||||||
{
|
|
||||||
AssetDatabase.CreateAsset(asset, assetPath);
|
|
||||||
asset.OnCreateAsset();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var preloadedAssets = PlayerSettings.GetPreloadedAssets();
|
var preloadedAssets = PlayerSettings.GetPreloadedAssets();
|
||||||
@@ -111,20 +95,13 @@ namespace Coffee.UIParticleInternal
|
|||||||
|
|
||||||
AssetDatabase.Refresh();
|
AssetDatabase.Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnCreateAsset()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void OnInitialize()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
public abstract class PreloadedProjectSettings<T> : PreloadedProjectSettings
|
public abstract class PreloadedProjectSettings<T> : PreloadedProjectSettings
|
||||||
where T : PreloadedProjectSettings<T>
|
where T : PreloadedProjectSettings<T>
|
||||||
{
|
{
|
||||||
@@ -133,8 +110,6 @@ namespace Coffee.UIParticleInternal
|
|||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
private string _jsonText;
|
private string _jsonText;
|
||||||
|
|
||||||
public static bool hasInstance => s_Instance;
|
|
||||||
|
|
||||||
public static T instance
|
public static T instance
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|||||||
@@ -10,9 +10,8 @@ namespace Coffee.UIParticleInternal
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class FastActionBase<T>
|
internal class FastActionBase<T>
|
||||||
{
|
{
|
||||||
private static readonly InternalObjectPool<LinkedListNode<T>> s_NodePool =
|
private static readonly ObjectPool<LinkedListNode<T>> s_NodePool =
|
||||||
new InternalObjectPool<LinkedListNode<T>>(() => new LinkedListNode<T>(default), _ => true,
|
new ObjectPool<LinkedListNode<T>>(() => new LinkedListNode<T>(default), _ => true, x => x.Value = default);
|
||||||
x => x.Value = default);
|
|
||||||
|
|
||||||
private readonly LinkedList<T> _delegates = new LinkedList<T>();
|
private readonly LinkedList<T> _delegates = new LinkedList<T>();
|
||||||
|
|
||||||
@@ -21,7 +20,6 @@ namespace Coffee.UIParticleInternal
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Add(T rhs)
|
public void Add(T rhs)
|
||||||
{
|
{
|
||||||
if (rhs == null) return;
|
|
||||||
Profiler.BeginSample("(COF)[FastAction] Add Action");
|
Profiler.BeginSample("(COF)[FastAction] Add Action");
|
||||||
var node = s_NodePool.Rent();
|
var node = s_NodePool.Rent();
|
||||||
node.Value = rhs;
|
node.Value = rhs;
|
||||||
@@ -34,7 +32,6 @@ namespace Coffee.UIParticleInternal
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Remove(T rhs)
|
public void Remove(T rhs)
|
||||||
{
|
{
|
||||||
if (rhs == null) return;
|
|
||||||
Profiler.BeginSample("(COF)[FastAction] Remove Action");
|
Profiler.BeginSample("(COF)[FastAction] Remove Action");
|
||||||
var node = _delegates.Find(rhs);
|
var node = _delegates.Find(rhs);
|
||||||
if (node != null)
|
if (node != null)
|
||||||
@@ -66,11 +63,6 @@ namespace Coffee.UIParticleInternal
|
|||||||
node = node.Next;
|
node = node.Next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
_delegates.Clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
GetFrameCache<T>().Set((key1.GetHashCode(), key2.GetHashCode()), result);
|
GetFrameCache<T>().Set((key1.GetHashCode(), key2.GetHashCode()), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets a value in the frame cache with a specified key.
|
/// Sets a value in the frame cache with a specified key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Object = UnityEngine.Object;
|
|||||||
#if ENABLE_COFFEE_LOGGER
|
#if ENABLE_COFFEE_LOGGER
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
using Conditional = System.Diagnostics.ConditionalAttribute;
|
using Conditional = System.Diagnostics.ConditionalAttribute;
|
||||||
#endif
|
#endif
|
||||||
@@ -42,6 +43,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if !ENABLE_COFFEE_LOGGER
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
[Conditional(k_DisableSymbol)]
|
[Conditional(k_DisableSymbol)]
|
||||||
#endif
|
#endif
|
||||||
@@ -51,6 +53,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
Log_Internal(LogType.Log, tag, message, context ? context : tag as Object);
|
Log_Internal(LogType.Log, tag, message, context ? context : tag as Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if !ENABLE_COFFEE_LOGGER
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
[Conditional(k_DisableSymbol)]
|
[Conditional(k_DisableSymbol)]
|
||||||
#endif
|
#endif
|
||||||
@@ -59,6 +62,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
Log_Internal(LogType.Log, tag, message, context ? context : tag as Object);
|
Log_Internal(LogType.Log, tag, message, context ? context : tag as Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if !ENABLE_COFFEE_LOGGER
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
[Conditional(k_DisableSymbol)]
|
[Conditional(k_DisableSymbol)]
|
||||||
#endif
|
#endif
|
||||||
@@ -76,6 +80,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if !ENABLE_COFFEE_LOGGER
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
[Conditional(k_DisableSymbol)]
|
[Conditional(k_DisableSymbol)]
|
||||||
#endif
|
#endif
|
||||||
@@ -119,6 +124,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if !ENABLE_COFFEE_LOGGER
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
[Conditional(k_DisableSymbol)]
|
[Conditional(k_DisableSymbol)]
|
||||||
#endif
|
#endif
|
||||||
@@ -135,9 +141,6 @@ namespace Coffee.UIParticleInternal
|
|||||||
|
|
||||||
switch (tag)
|
switch (tag)
|
||||||
{
|
{
|
||||||
case string name:
|
|
||||||
sb.Append(name);
|
|
||||||
break;
|
|
||||||
case Type type:
|
case Type type:
|
||||||
AppendType(sb, type);
|
AppendType(sb, type);
|
||||||
break;
|
break;
|
||||||
@@ -164,6 +167,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if !ENABLE_COFFEE_LOGGER
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
[Conditional(k_DisableSymbol)]
|
[Conditional(k_DisableSymbol)]
|
||||||
#endif
|
#endif
|
||||||
@@ -202,6 +206,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if !ENABLE_COFFEE_LOGGER
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
[Conditional(k_DisableSymbol)]
|
[Conditional(k_DisableSymbol)]
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
public static void Clear()
|
private static void Clear()
|
||||||
{
|
{
|
||||||
s_Repository.Clear();
|
s_Repository.Clear();
|
||||||
}
|
}
|
||||||
@@ -55,6 +55,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds or retrieves a cached material based on the hash.
|
/// Adds or retrieves a cached material based on the hash.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -6,58 +6,15 @@ namespace Coffee.UIParticleInternal
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Object pool.
|
/// Object pool.
|
||||||
/// </summary>
|
/// </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 Func<T> _onCreate; // Delegate for creating instances
|
||||||
private readonly Action<T> _onReturn; // Delegate for returning instances to the pool
|
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 Predicate<T> _onValid; // Delegate for checking if instances are valid
|
||||||
private readonly Stack<T> _pool = new Stack<T>(32); // Object pool
|
private readonly Stack<T> _pool = new Stack<T>(32); // Object pool
|
||||||
private int _count; // Total count of created instances
|
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;
|
_onCreate = onCreate;
|
||||||
_onValid = onValid;
|
_onValid = onValid;
|
||||||
@@ -97,40 +54,15 @@ namespace Coffee.UIParticleInternal
|
|||||||
Logging.Log(this, $"An instance is released (pooled: {_pool.Count}, created: {_count}).");
|
Logging.Log(this, $"An instance is released (pooled: {_pool.Count}, created: {_count}).");
|
||||||
instance = default; // Set the reference to null.
|
instance = default; // Set the reference to null.
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Object pool for <see cref="List{T}" />.
|
/// Object pool for <see cref="List{T}" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class InternalListPool<T>
|
internal static class ListPool<T>
|
||||||
{
|
{
|
||||||
#if UNITY_2021_1_OR_NEWER
|
private static readonly ObjectPool<List<T>> s_ListPool =
|
||||||
/// <summary>
|
new ObjectPool<List<T>>(() => new List<T>(), _ => true, x => x.Clear());
|
||||||
/// 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>
|
/// <summary>
|
||||||
/// Rent an instance from the pool.
|
/// Rent an instance from the pool.
|
||||||
@@ -149,6 +81,5 @@ namespace Coffee.UIParticleInternal
|
|||||||
{
|
{
|
||||||
s_ListPool.Return(ref toRelease);
|
s_ListPool.Return(ref toRelease);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,10 @@ namespace Coffee.UIParticleInternal
|
|||||||
{
|
{
|
||||||
internal class ObjectRepository<T> where T : Object
|
internal class ObjectRepository<T> where T : Object
|
||||||
{
|
{
|
||||||
private readonly Dictionary<Hash128, Entry> _cache = new Dictionary<Hash128, Entry>(8);
|
private readonly List<Entry> _cache = new List<Entry>();
|
||||||
private readonly Dictionary<int, Hash128> _objectKey = new Dictionary<int, Hash128>(8);
|
|
||||||
private readonly string _name;
|
private readonly string _name;
|
||||||
private readonly Action<T> _onRelease;
|
private readonly Action<T> _onRelease;
|
||||||
private readonly Stack<Entry> _pool = new Stack<Entry>(8);
|
private readonly Stack<Entry> _pool = new Stack<Entry>();
|
||||||
|
|
||||||
public ObjectRepository(Action<T> onRelease = null)
|
public ObjectRepository(Action<T> onRelease = null)
|
||||||
{
|
{
|
||||||
@@ -37,33 +36,40 @@ namespace Coffee.UIParticleInternal
|
|||||||
{
|
{
|
||||||
_onRelease = onRelease;
|
_onRelease = onRelease;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
_pool.Push(new Entry());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int count => _cache.Count;
|
public int count => _cache.Count;
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
foreach (var kv in _cache)
|
for (var i = 0; i < _cache.Count; i++)
|
||||||
{
|
{
|
||||||
var entry = kv.Value;
|
var entry = _cache[i];
|
||||||
if (entry == null) continue;
|
if (entry == null) continue;
|
||||||
|
|
||||||
entry.Release(_onRelease);
|
entry.Release(_onRelease);
|
||||||
_pool.Push(entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_cache.Clear();
|
_cache.Clear();
|
||||||
_objectKey.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Valid(Hash128 hash, T obj)
|
public bool Valid(Hash128 hash, T obj)
|
||||||
{
|
{
|
||||||
return _cache.TryGetValue(hash, out var entry) && entry.storedObject == obj;
|
// Find existing entry.
|
||||||
|
Profiler.BeginSample("(COF)[ObjectRepository] Valid > Find existing entry");
|
||||||
|
for (var i = 0; i < _cache.Count; ++i)
|
||||||
|
{
|
||||||
|
var entry = _cache[i];
|
||||||
|
if (entry.hash != hash) continue;
|
||||||
|
Profiler.EndSample();
|
||||||
|
|
||||||
|
// Existing entry found.
|
||||||
|
return entry.storedObject == obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
Profiler.EndSample();
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -71,69 +77,82 @@ namespace Coffee.UIParticleInternal
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Get(Hash128 hash, ref T obj, Func<T> onCreate)
|
public void Get(Hash128 hash, ref T obj, Func<T> onCreate)
|
||||||
{
|
{
|
||||||
if (GetFromCache(hash, ref obj)) return;
|
// Find existing entry.
|
||||||
Add(hash, ref obj, onCreate());
|
Profiler.BeginSample("(COF)[ObjectRepository] Get > Find existing entry");
|
||||||
|
for (var i = 0; i < _cache.Count; ++i)
|
||||||
|
{
|
||||||
|
var entry = _cache[i];
|
||||||
|
if (entry.hash != hash) continue;
|
||||||
|
|
||||||
|
// Existing entry found.
|
||||||
|
if (entry.storedObject != obj)
|
||||||
|
{
|
||||||
|
// if the object is different, release the old one.
|
||||||
|
Release(ref obj);
|
||||||
|
++entry.reference;
|
||||||
|
obj = entry.storedObject;
|
||||||
|
Logging.Log(_name, $"Get(#{count}): {entry}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Profiler.EndSample();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Profiler.EndSample();
|
||||||
|
|
||||||
|
// Create new entry.
|
||||||
|
Profiler.BeginSample("(COF)[ObjectRepository] Get > Create new entry");
|
||||||
|
var newEntry = 0 < _pool.Count ? _pool.Pop() : new Entry();
|
||||||
|
newEntry.storedObject = onCreate();
|
||||||
|
newEntry.hash = hash;
|
||||||
|
newEntry.reference = 1;
|
||||||
|
_cache.Add(newEntry);
|
||||||
|
Logging.Log(_name, $"Get(#{count}): {newEntry}");
|
||||||
|
|
||||||
|
Release(ref obj);
|
||||||
|
obj = newEntry.storedObject;
|
||||||
|
Profiler.EndSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds or retrieves a cached object based on the hash.
|
/// Adds or retrieves a cached object based on the hash.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Get<TS>(Hash128 hash, ref T obj, Func<TS, T> onCreate, TS source)
|
public void Get<TS>(Hash128 hash, ref T obj, Func<TS, T> onCreate, TS source)
|
||||||
{
|
|
||||||
if (GetFromCache(hash, ref obj)) return;
|
|
||||||
Add(hash, ref obj, onCreate(source));
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool GetFromCache(Hash128 hash, ref T obj)
|
|
||||||
{
|
{
|
||||||
// Find existing entry.
|
// Find existing entry.
|
||||||
Profiler.BeginSample("(COF)[ObjectRepository] GetFromCache");
|
Profiler.BeginSample("(COF)[ObjectRepository] Get > Find existing entry");
|
||||||
if (_cache.TryGetValue(hash, out var entry))
|
for (var i = 0; i < _cache.Count; ++i)
|
||||||
{
|
{
|
||||||
if (!entry.storedObject)
|
var entry = _cache[i];
|
||||||
{
|
if (entry.hash != hash) continue;
|
||||||
Release(ref entry.storedObject);
|
|
||||||
Profiler.EndSample();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Existing entry found.
|
||||||
if (entry.storedObject != obj)
|
if (entry.storedObject != obj)
|
||||||
{
|
{
|
||||||
// if the object is different, release the old one.
|
// if the object is different, release the old one.
|
||||||
Release(ref obj);
|
Release(ref obj);
|
||||||
++entry.reference;
|
++entry.reference;
|
||||||
obj = entry.storedObject;
|
obj = entry.storedObject;
|
||||||
Logging.Log(_name, $"Get(total#{count}): {entry}");
|
Logging.Log(_name, $"Get(#{count}): {entry}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Profiler.EndSample();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Add(Hash128 hash, ref T obj, T newObject)
|
|
||||||
{
|
|
||||||
if (!newObject)
|
|
||||||
{
|
|
||||||
Release(ref obj);
|
|
||||||
obj = newObject;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create and add a new entry.
|
Profiler.EndSample();
|
||||||
Profiler.BeginSample("(COF)[ObjectRepository] Add");
|
|
||||||
|
// Create new entry.
|
||||||
|
Profiler.BeginSample("(COF)[ObjectRepository] Get > Create new entry");
|
||||||
var newEntry = 0 < _pool.Count ? _pool.Pop() : new Entry();
|
var newEntry = 0 < _pool.Count ? _pool.Pop() : new Entry();
|
||||||
newEntry.storedObject = newObject;
|
newEntry.storedObject = onCreate(source);
|
||||||
newEntry.hash = hash;
|
newEntry.hash = hash;
|
||||||
newEntry.reference = 1;
|
newEntry.reference = 1;
|
||||||
_cache[hash] = newEntry;
|
_cache.Add(newEntry);
|
||||||
_objectKey[newObject.GetInstanceID()] = hash;
|
Logging.Log(_name, $"Get(#{count}): {newEntry}");
|
||||||
Logging.Log(_name, $"<color=#03c700>Add</color>(total#{count}): {newEntry}");
|
|
||||||
Release(ref obj);
|
Release(ref obj);
|
||||||
obj = newObject;
|
obj = newEntry.storedObject;
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,45 +163,35 @@ namespace Coffee.UIParticleInternal
|
|||||||
{
|
{
|
||||||
if (ReferenceEquals(obj, null)) return;
|
if (ReferenceEquals(obj, null)) return;
|
||||||
|
|
||||||
// Find and release the entry.
|
|
||||||
Profiler.BeginSample("(COF)[ObjectRepository] Release");
|
Profiler.BeginSample("(COF)[ObjectRepository] Release");
|
||||||
var id = obj.GetInstanceID();
|
for (var i = 0; i < _cache.Count; i++)
|
||||||
if (_objectKey.TryGetValue(id, out var hash)
|
|
||||||
&& _cache.TryGetValue(hash, out var entry))
|
|
||||||
{
|
{
|
||||||
entry.reference--;
|
var entry = _cache[i];
|
||||||
if (entry.reference <= 0 || !entry.storedObject)
|
|
||||||
|
if (entry.storedObject != obj)
|
||||||
{
|
{
|
||||||
Remove(entry);
|
continue;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (--entry.reference <= 0)
|
||||||
{
|
{
|
||||||
Logging.Log(_name, $"Release(total#{_cache.Count}): {entry}");
|
Profiler.BeginSample("(COF)[ObjectRepository] Release > RemoveAt");
|
||||||
|
_cache.RemoveAtFast(i);
|
||||||
|
Logging.Log(_name, $"Release(#{_cache.Count}): {entry}");
|
||||||
|
entry.Release(_onRelease);
|
||||||
|
_pool.Push(entry);
|
||||||
|
Profiler.EndSample();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
Logging.Log(_name, $"Release(#{count}): {entry}");
|
||||||
{
|
break;
|
||||||
Logging.Log(_name, $"Release(total#{_cache.Count}): <color=red>Already released: {obj}</color>");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = null;
|
obj = null;
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Remove(Entry entry)
|
|
||||||
{
|
|
||||||
if (ReferenceEquals(entry, null)) return;
|
|
||||||
|
|
||||||
Profiler.BeginSample("(COF)[ObjectRepository] Remove");
|
|
||||||
_cache.Remove(entry.hash);
|
|
||||||
_objectKey.Remove(entry.storedObject.GetInstanceID());
|
|
||||||
_pool.Push(entry);
|
|
||||||
entry.reference = 0;
|
|
||||||
Logging.Log(_name, $"<color=#f29e03>Remove</color>(total#{_cache.Count}): {entry}");
|
|
||||||
entry.Release(_onRelease);
|
|
||||||
Profiler.EndSample();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Entry
|
private class Entry
|
||||||
{
|
{
|
||||||
public Hash128 hash;
|
public Hash128 hash;
|
||||||
@@ -202,7 +211,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"h{(uint)hash.GetHashCode()} (refs#{reference}), {storedObject}";
|
return $"h{(uint)hash.GetHashCode()} (#{reference}), {storedObject}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ namespace Coffee.UIParticleInternal
|
|||||||
private static readonly FastAction s_AfterCanvasRebuildAction = new FastAction();
|
private static readonly FastAction s_AfterCanvasRebuildAction = new FastAction();
|
||||||
private static readonly FastAction s_LateAfterCanvasRebuildAction = new FastAction();
|
private static readonly FastAction s_LateAfterCanvasRebuildAction = new FastAction();
|
||||||
private static readonly FastAction s_BeforeCanvasRebuildAction = 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()
|
static UIExtraCallbacks()
|
||||||
{
|
{
|
||||||
@@ -50,15 +48,6 @@ namespace Coffee.UIParticleInternal
|
|||||||
remove => s_AfterCanvasRebuildAction.Remove(value);
|
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>
|
/// <summary>
|
||||||
/// Initializes the UIExtraCallbacks to ensure proper event handling.
|
/// Initializes the UIExtraCallbacks to ensure proper event handling.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -75,12 +64,11 @@ namespace Coffee.UIParticleInternal
|
|||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
[InitializeOnLoadMethod]
|
[InitializeOnLoadMethod]
|
||||||
#endif
|
#else
|
||||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||||
|
#endif
|
||||||
private static void InitializeOnLoad()
|
private static void InitializeOnLoad()
|
||||||
{
|
{
|
||||||
Canvas.willRenderCanvases -= OnAfterCanvasRebuild;
|
|
||||||
s_IsInitializedAfterCanvasRebuild = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -88,17 +76,6 @@ namespace Coffee.UIParticleInternal
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private static void OnBeforeCanvasRebuild()
|
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();
|
s_BeforeCanvasRebuildAction.Invoke();
|
||||||
InitializeAfterCanvasRebuild();
|
InitializeAfterCanvasRebuild();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,12 @@ using System.Collections.Generic;
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Coffee.UIParticleInternal;
|
using Coffee.UIParticleInternal;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.EventSystems;
|
||||||
using UnityEngine.Rendering;
|
using UnityEngine.Rendering;
|
||||||
using UnityEngine.Serialization;
|
using UnityEngine.Serialization;
|
||||||
using UnityEngine.UI;
|
|
||||||
using Random = UnityEngine.Random;
|
using Random = UnityEngine.Random;
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("Coffee.UIParticle.Editor")]
|
[assembly: InternalsVisibleTo("Coffee.UIParticle.Editor")]
|
||||||
[assembly: InternalsVisibleTo("Coffee.UIParticle.PerformanceDemo")]
|
|
||||||
[assembly: InternalsVisibleTo("Coffee.UIParticle.Demo")]
|
|
||||||
|
|
||||||
namespace Coffee.UIExtensions
|
namespace Coffee.UIExtensions
|
||||||
{
|
{
|
||||||
@@ -20,7 +18,7 @@ namespace Coffee.UIExtensions
|
|||||||
[ExecuteAlways]
|
[ExecuteAlways]
|
||||||
[RequireComponent(typeof(RectTransform))]
|
[RequireComponent(typeof(RectTransform))]
|
||||||
[RequireComponent(typeof(CanvasRenderer))]
|
[RequireComponent(typeof(CanvasRenderer))]
|
||||||
public class UIParticle : MaskableGraphic, ISerializationCallbackReceiver
|
public class UIParticle : UIBehaviour, ISerializationCallbackReceiver
|
||||||
{
|
{
|
||||||
public enum AutoScalingMode
|
public enum AutoScalingMode
|
||||||
{
|
{
|
||||||
@@ -60,12 +58,12 @@ namespace Coffee.UIExtensions
|
|||||||
[Obsolete]
|
[Obsolete]
|
||||||
internal bool m_AbsoluteMode;
|
internal bool m_AbsoluteMode;
|
||||||
|
|
||||||
[Tooltip("Scale the rendering particles. When the `3D` toggle is enabled, 3D scale (x, y, z) is supported.")]
|
[Tooltip("Particle effect scale")]
|
||||||
[SerializeField]
|
[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, " +
|
[Tooltip("Animatable material properties.\n" +
|
||||||
"use this to mark as animatable.")]
|
"If you want to change the material properties of the ParticleSystem in Animation, enable it.")]
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
internal AnimatableProperty[] m_AnimatableProperties = new AnimatableProperty[0];
|
internal AnimatableProperty[] m_AnimatableProperties = new AnimatableProperty[0];
|
||||||
|
|
||||||
@@ -73,13 +71,12 @@ namespace Coffee.UIExtensions
|
|||||||
[SerializeField]
|
[SerializeField]
|
||||||
private List<ParticleSystem> m_Particles = new List<ParticleSystem>();
|
private List<ParticleSystem> m_Particles = new List<ParticleSystem>();
|
||||||
|
|
||||||
[Tooltip("Particle simulation results are shared within the same group. " +
|
[Tooltip("Mesh sharing.\n" +
|
||||||
"A large number of the same effects can be displayed with a small load.\n" +
|
"None: disable mesh sharing.\n" +
|
||||||
"None: Disable mesh sharing.\n" +
|
"Auto: automatically select Primary/Replica.\n" +
|
||||||
"Auto: Automatically select Primary/Replica.\n" +
|
"Primary: provides particle simulation results to the same group.\n" +
|
||||||
"Primary: Provides particle simulation results to the same group.\n" +
|
|
||||||
"Primary Simulator: Primary, but do not render the particle (simulation only).\n" +
|
"Primary Simulator: Primary, but do not render the particle (simulation only).\n" +
|
||||||
"Replica: Render simulation results provided by the primary.")]
|
"Replica: render simulation results provided by the primary.")]
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
private MeshSharing m_MeshSharing = MeshSharing.None;
|
private MeshSharing m_MeshSharing = MeshSharing.None;
|
||||||
|
|
||||||
@@ -91,53 +88,67 @@ namespace Coffee.UIExtensions
|
|||||||
[SerializeField]
|
[SerializeField]
|
||||||
private int m_GroupMaxId;
|
private int m_GroupMaxId;
|
||||||
|
|
||||||
[Tooltip("Emission position mode.\n" +
|
[Tooltip("Relative: The particles will be emitted from the scaled position of ParticleSystem.\n" +
|
||||||
"Relative: The particles will be emitted from the scaled position.\n" +
|
"Absolute: The particles will be emitted from the world position of ParticleSystem.")]
|
||||||
"Absolute: The particles will be emitted from the world position.")]
|
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
private PositionMode m_PositionMode = PositionMode.Relative;
|
private PositionMode m_PositionMode = PositionMode.Relative;
|
||||||
|
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
|
[Tooltip("Prevent the root-Canvas scale from affecting the hierarchy-scaled ParticleSystem.")]
|
||||||
[Obsolete]
|
[Obsolete]
|
||||||
internal bool m_AutoScaling;
|
internal bool m_AutoScaling;
|
||||||
|
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
[Tooltip(
|
[Tooltip("Transform: Transform.lossyScale (=world scale) will be set to (1, 1, 1)." +
|
||||||
"How to automatically adjust when the Canvas scale is changed by the screen size or reference resolution.\n" +
|
"UIParticle: UIParticle.scale will be adjusted.")]
|
||||||
"None: Do nothing.\n" +
|
|
||||||
"Transform: Transform.lossyScale (=world scale) will be set to (1, 1, 1).\n" +
|
|
||||||
"UIParticle: UIParticle.scale will be adjusted.")]
|
|
||||||
private AutoScalingMode m_AutoScalingMode = AutoScalingMode.Transform;
|
private AutoScalingMode m_AutoScalingMode = AutoScalingMode.Transform;
|
||||||
|
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
[Tooltip("Use a custom view.\n" +
|
private bool m_Maskable = true;
|
||||||
"Use this if the particles are not displayed correctly due to min/max particle size.")]
|
|
||||||
private bool m_UseCustomView;
|
|
||||||
|
|
||||||
[SerializeField]
|
|
||||||
[Tooltip("Custom view size.\n" +
|
|
||||||
"Change the bake view size.")]
|
|
||||||
private float m_CustomViewSize = 10;
|
|
||||||
|
|
||||||
private readonly List<UIParticleRenderer> _renderers = new List<UIParticleRenderer>();
|
private readonly List<UIParticleRenderer> _renderers = new List<UIParticleRenderer>();
|
||||||
private Camera _bakeCamera;
|
private Canvas _canvas;
|
||||||
private int _groupId;
|
private int _groupId;
|
||||||
private bool _isScaleStored;
|
private Camera _bakeCamera;
|
||||||
private Vector3 _storedScale;
|
|
||||||
private DrivenRectTransformTracker _tracker;
|
private DrivenRectTransformTracker _tracker;
|
||||||
|
private Vector3 _storedScale;
|
||||||
|
private bool _isScaleStored;
|
||||||
|
|
||||||
/// <summary>
|
public RectTransform rectTransform => transform as RectTransform;
|
||||||
/// Should this graphic be considered a target for ray-casting?
|
|
||||||
/// </summary>
|
public Canvas canvas
|
||||||
public override bool raycastTarget
|
|
||||||
{
|
{
|
||||||
get => false;
|
get
|
||||||
set { }
|
{
|
||||||
|
if (_canvas) return _canvas;
|
||||||
|
|
||||||
|
var tr = transform;
|
||||||
|
while (tr && !_canvas)
|
||||||
|
{
|
||||||
|
if (tr.TryGetComponent(out _canvas)) return _canvas;
|
||||||
|
tr = tr.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Particle simulation results are shared within the same group.
|
/// Does this graphic allow masking.
|
||||||
/// A large number of the same effects can be displayed with a small load.
|
/// </summary>
|
||||||
|
public bool maskable
|
||||||
|
{
|
||||||
|
get => m_Maskable;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == m_Maskable) return;
|
||||||
|
m_Maskable = value;
|
||||||
|
UpdateRendererMaterial();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mesh sharing.
|
||||||
/// None: disable mesh sharing.
|
/// None: disable mesh sharing.
|
||||||
/// Auto: automatically select Primary/Replica.
|
/// Auto: automatically select Primary/Replica.
|
||||||
/// Primary: provides particle simulation results to the same group.
|
/// Primary: provides particle simulation results to the same group.
|
||||||
@@ -180,9 +191,9 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Emission position mode.
|
/// Particle position mode.
|
||||||
/// Relative: The particles will be emitted from the scaled position.
|
/// Relative: The particles will be emitted from the scaled position of the ParticleSystem.
|
||||||
/// Absolute: The particles will be emitted from the world position.
|
/// Absolute: The particles will be emitted from the world position of the ParticleSystem.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PositionMode positionMode
|
public PositionMode positionMode
|
||||||
{
|
{
|
||||||
@@ -195,7 +206,6 @@ namespace Coffee.UIExtensions
|
|||||||
/// Relative: The particles will be emitted from the scaled position of the ParticleSystem.
|
/// Relative: The particles will be emitted from the scaled position of the ParticleSystem.
|
||||||
/// Absolute: The particles will be emitted from the world position of the ParticleSystem.
|
/// Absolute: The particles will be emitted from the world position of the ParticleSystem.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Obsolete("The absoluteMode is now obsolete. Please use the autoScalingMode instead.", false)]
|
|
||||||
public bool absoluteMode
|
public bool absoluteMode
|
||||||
{
|
{
|
||||||
get => m_PositionMode == PositionMode.Absolute;
|
get => m_PositionMode == PositionMode.Absolute;
|
||||||
@@ -213,12 +223,8 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How to automatically adjust when the Canvas scale is changed by the screen size or reference resolution.
|
/// Auto scaling mode.
|
||||||
/// <para/>
|
|
||||||
/// None: Do nothing.
|
|
||||||
/// <para/>
|
|
||||||
/// Transform: Transform.lossyScale (=world scale) will be set to (1, 1, 1).
|
/// Transform: Transform.lossyScale (=world scale) will be set to (1, 1, 1).
|
||||||
/// <para/>
|
|
||||||
/// UIParticle: UIParticle.scale will be adjusted.
|
/// UIParticle: UIParticle.scale will be adjusted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public AutoScalingMode autoScalingMode
|
public AutoScalingMode autoScalingMode
|
||||||
@@ -237,26 +243,6 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Use a custom view.
|
|
||||||
/// Use this if the particles are not displayed correctly due to min/max particle size.
|
|
||||||
/// </summary>
|
|
||||||
public bool useCustomView
|
|
||||||
{
|
|
||||||
get => m_UseCustomView;
|
|
||||||
set => m_UseCustomView = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Custom view size.
|
|
||||||
/// Change the bake view size.
|
|
||||||
/// </summary>
|
|
||||||
public float customViewSize
|
|
||||||
{
|
|
||||||
get => m_CustomViewSize;
|
|
||||||
set => m_CustomViewSize = Mathf.Max(0.1f, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal bool useMeshSharing => m_MeshSharing != MeshSharing.None;
|
internal bool useMeshSharing => m_MeshSharing != MeshSharing.None;
|
||||||
|
|
||||||
internal bool isPrimary =>
|
internal bool isPrimary =>
|
||||||
@@ -302,6 +288,22 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
public List<ParticleSystem> particles => m_Particles;
|
public List<ParticleSystem> particles => m_Particles;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get all base materials to render.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<Material> materials
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
for (var i = 0; i < _renderers.Count; i++)
|
||||||
|
{
|
||||||
|
var r = _renderers[i];
|
||||||
|
if (!r || !r.material) continue;
|
||||||
|
yield return r.material;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Paused.
|
/// Paused.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -309,15 +311,15 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
public Vector3 parentScale { get; private set; }
|
public Vector3 parentScale { get; private set; }
|
||||||
|
|
||||||
public Vector3 canvasScale { get; private set; }
|
private Vector3 canvasScale { get; set; }
|
||||||
|
|
||||||
protected override void OnEnable()
|
protected override void OnEnable()
|
||||||
{
|
{
|
||||||
_isScaleStored = false;
|
_isScaleStored = false;
|
||||||
ResetGroupId();
|
ResetGroupId();
|
||||||
UIParticleUpdater.Register(this);
|
UIParticleUpdater.Register(this);
|
||||||
RegisterDirtyMaterialCallback(UpdateRendererMaterial);
|
|
||||||
|
|
||||||
|
//
|
||||||
if (0 < particles.Count)
|
if (0 < particles.Count)
|
||||||
{
|
{
|
||||||
RefreshParticles(particles);
|
RefreshParticles(particles);
|
||||||
@@ -327,7 +329,7 @@ namespace Coffee.UIExtensions
|
|||||||
RefreshParticles();
|
RefreshParticles();
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnEnable();
|
UpdateRendererMaterial();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -344,9 +346,15 @@ namespace Coffee.UIExtensions
|
|||||||
_isScaleStored = false;
|
_isScaleStored = false;
|
||||||
UIParticleUpdater.Unregister(this);
|
UIParticleUpdater.Unregister(this);
|
||||||
_renderers.ForEach(r => r.Reset());
|
_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>
|
/// <summary>
|
||||||
@@ -356,6 +364,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()
|
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -446,21 +462,6 @@ namespace Coffee.UIExtensions
|
|||||||
isPaused = true;
|
isPaused = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get all base materials to render.
|
|
||||||
/// </summary>
|
|
||||||
public void GetMaterials(List<Material> result)
|
|
||||||
{
|
|
||||||
if (result == null) return;
|
|
||||||
|
|
||||||
for (var i = 0; i < _renderers.Count; i++)
|
|
||||||
{
|
|
||||||
var r = _renderers[i];
|
|
||||||
if (!r || !r.material) continue;
|
|
||||||
result.Add(r.material);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Refresh UIParticle using the ParticleSystem instance.
|
/// Refresh UIParticle using the ParticleSystem instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -480,9 +481,6 @@ namespace Coffee.UIExtensions
|
|||||||
for (var i = 0; i < childCount; i++)
|
for (var i = 0; i < childCount; i++)
|
||||||
{
|
{
|
||||||
var go = transform.GetChild(i).gameObject;
|
var go = transform.GetChild(i).gameObject;
|
||||||
if (go.TryGetComponent<Camera>(out var cam) && cam == _bakeCamera) continue;
|
|
||||||
if (go.TryGetComponent<UIParticleRenderer>(out var _)) continue;
|
|
||||||
|
|
||||||
go.SetActive(false);
|
go.SetActive(false);
|
||||||
if (destroyOldParticles)
|
if (destroyOldParticles)
|
||||||
{
|
{
|
||||||
@@ -577,14 +575,12 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
var ps = particleSystems[i];
|
var ps = particleSystems[i];
|
||||||
if (!ps) continue;
|
if (!ps) continue;
|
||||||
|
GetRenderer(j++).Set(this, ps, false);
|
||||||
var mainEmitter = ps.GetMainEmitter(particleSystems);
|
|
||||||
GetRenderer(j++).Set(this, ps, false, mainEmitter);
|
|
||||||
|
|
||||||
// If the trail is enabled, set it additionally.
|
// If the trail is enabled, set it additionally.
|
||||||
if (ps.trails.enabled)
|
if (ps.trails.enabled)
|
||||||
{
|
{
|
||||||
GetRenderer(j++).Set(this, ps, true, mainEmitter);
|
GetRenderer(j++).Set(this, ps, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -606,12 +602,8 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
var currentScale = transform.localScale;
|
var currentScale = transform.localScale;
|
||||||
if (!_isScaleStored)
|
_storedScale = currentScale;
|
||||||
{
|
_isScaleStored = true;
|
||||||
_storedScale = currentScale.IsVisible() ? currentScale : Vector3.one;
|
|
||||||
_isScaleStored = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
_tracker.Add(this, rectTransform, DrivenTransformProperties.Scale);
|
_tracker.Add(this, rectTransform, DrivenTransformProperties.Scale);
|
||||||
var newScale = parentScale.Inverse();
|
var newScale = parentScale.Inverse();
|
||||||
if (currentScale != newScale)
|
if (currentScale != newScale)
|
||||||
@@ -650,17 +642,6 @@ namespace Coffee.UIExtensions
|
|||||||
: Random.Range(m_GroupId, m_GroupMaxId + 1);
|
: 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()
|
private void UpdateRendererMaterial()
|
||||||
{
|
{
|
||||||
for (var i = 0; i < _renderers.Count; i++)
|
for (var i = 0; i < _renderers.Count; i++)
|
||||||
@@ -690,16 +671,7 @@ namespace Coffee.UIExtensions
|
|||||||
private Camera GetBakeCamera()
|
private Camera GetBakeCamera()
|
||||||
{
|
{
|
||||||
if (!canvas) return Camera.main;
|
if (!canvas) return Camera.main;
|
||||||
if (!useCustomView && canvas.renderMode != RenderMode.ScreenSpaceOverlay && canvas.rootCanvas.worldCamera)
|
if (_bakeCamera) return _bakeCamera;
|
||||||
{
|
|
||||||
return canvas.rootCanvas.worldCamera;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_bakeCamera)
|
|
||||||
{
|
|
||||||
_bakeCamera.orthographicSize = useCustomView ? customViewSize : 10;
|
|
||||||
return _bakeCamera;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find existing baking camera.
|
// Find existing baking camera.
|
||||||
var childCount = transform.childCount;
|
var childCount = transform.childCount;
|
||||||
@@ -716,7 +688,10 @@ namespace Coffee.UIExtensions
|
|||||||
// Create baking camera.
|
// Create baking camera.
|
||||||
if (!_bakeCamera)
|
if (!_bakeCamera)
|
||||||
{
|
{
|
||||||
var go = new GameObject("[generated] UIParticle BakingCamera");
|
var go = new GameObject("[generated] UIParticle BakingCamera")
|
||||||
|
{
|
||||||
|
hideFlags = HideFlags.HideAndDontSave
|
||||||
|
};
|
||||||
go.SetActive(false);
|
go.SetActive(false);
|
||||||
go.transform.SetParent(transform, false);
|
go.transform.SetParent(transform, false);
|
||||||
_bakeCamera = go.AddComponent<Camera>();
|
_bakeCamera = go.AddComponent<Camera>();
|
||||||
@@ -724,7 +699,7 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
// Setup baking camera.
|
// Setup baking camera.
|
||||||
_bakeCamera.enabled = false;
|
_bakeCamera.enabled = false;
|
||||||
_bakeCamera.orthographicSize = useCustomView ? customViewSize : 10;
|
_bakeCamera.orthographicSize = 1000;
|
||||||
_bakeCamera.transform.SetPositionAndRotation(new Vector3(0, 0, -1000), Quaternion.identity);
|
_bakeCamera.transform.SetPositionAndRotation(new Vector3(0, 0, -1000), Quaternion.identity);
|
||||||
_bakeCamera.orthographic = true;
|
_bakeCamera.orthographic = true;
|
||||||
_bakeCamera.farClipPlane = 2000f;
|
_bakeCamera.farClipPlane = 2000f;
|
||||||
@@ -735,9 +710,6 @@ namespace Coffee.UIExtensions
|
|||||||
_bakeCamera.renderingPath = RenderingPath.Forward;
|
_bakeCamera.renderingPath = RenderingPath.Forward;
|
||||||
_bakeCamera.useOcclusionCulling = false;
|
_bakeCamera.useOcclusionCulling = false;
|
||||||
|
|
||||||
_bakeCamera.gameObject.SetActive(false);
|
|
||||||
_bakeCamera.gameObject.hideFlags = UIParticleProjectSettings.globalHideFlags;
|
|
||||||
|
|
||||||
return _bakeCamera;
|
return _bakeCamera;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using Coffee.UIParticleInternal;
|
using Coffee.UIParticleInternal;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Events;
|
using UnityEngine.Events;
|
||||||
@@ -7,7 +6,7 @@ using UnityEngine.Events;
|
|||||||
namespace Coffee.UIExtensions
|
namespace Coffee.UIExtensions
|
||||||
{
|
{
|
||||||
[ExecuteAlways]
|
[ExecuteAlways]
|
||||||
public class UIParticleAttractor : MonoBehaviour, ISerializationCallbackReceiver
|
public class UIParticleAttractor : MonoBehaviour
|
||||||
{
|
{
|
||||||
public enum Movement
|
public enum Movement
|
||||||
{
|
{
|
||||||
@@ -23,12 +22,8 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
[HideInInspector]
|
|
||||||
private ParticleSystem m_ParticleSystem;
|
private ParticleSystem m_ParticleSystem;
|
||||||
|
|
||||||
[SerializeField]
|
|
||||||
private List<ParticleSystem> m_ParticleSystems = new List<ParticleSystem>();
|
|
||||||
|
|
||||||
[Range(0.1f, 10f)]
|
[Range(0.1f, 10f)]
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
private float m_DestinationRadius = 1;
|
private float m_DestinationRadius = 1;
|
||||||
@@ -50,7 +45,7 @@ namespace Coffee.UIExtensions
|
|||||||
[SerializeField]
|
[SerializeField]
|
||||||
private UnityEvent m_OnAttracted;
|
private UnityEvent m_OnAttracted;
|
||||||
|
|
||||||
private List<UIParticle> _uiParticles = new List<UIParticle>();
|
private UIParticle _uiParticle;
|
||||||
|
|
||||||
public float destinationRadius
|
public float destinationRadius
|
||||||
{
|
{
|
||||||
@@ -89,46 +84,25 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The target ParticleSystems to attract. Use <see cref="AddParticleSystem"/> and
|
/// The target ParticleSystem to attract.
|
||||||
/// <see cref="RemoveParticleSystem"/> to modify the list.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IReadOnlyList<ParticleSystem> particleSystems => m_ParticleSystems;
|
#if UNITY_EDITOR
|
||||||
|
public new ParticleSystem particleSystem
|
||||||
public void AddParticleSystem(ParticleSystem ps)
|
#else
|
||||||
|
public ParticleSystem particleSystem
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
if (m_ParticleSystems == null)
|
get => m_ParticleSystem;
|
||||||
|
set
|
||||||
{
|
{
|
||||||
m_ParticleSystems = new List<ParticleSystem>();
|
m_ParticleSystem = value;
|
||||||
|
ApplyParticleSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
var i = m_ParticleSystems.IndexOf(ps);
|
|
||||||
if (0 <= i) return; // Already added: skip
|
|
||||||
|
|
||||||
m_ParticleSystems.Add(ps);
|
|
||||||
_uiParticles.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveParticleSystem(ParticleSystem ps)
|
|
||||||
{
|
|
||||||
if (m_ParticleSystems == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var i = m_ParticleSystems.IndexOf(ps);
|
|
||||||
if (i < 0) return; // Not found. skip
|
|
||||||
|
|
||||||
m_ParticleSystems.RemoveAt(i);
|
|
||||||
_uiParticles.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Awake()
|
|
||||||
{
|
|
||||||
UpgradeIfNeeded();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEnable()
|
private void OnEnable()
|
||||||
{
|
{
|
||||||
|
ApplyParticleSystem();
|
||||||
UIParticleUpdater.Register(this);
|
UIParticleUpdater.Register(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,96 +113,85 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
private void OnDestroy()
|
private void OnDestroy()
|
||||||
{
|
{
|
||||||
_uiParticles = null;
|
_uiParticle = null;
|
||||||
m_ParticleSystems = null;
|
m_ParticleSystem = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Attract()
|
internal void Attract()
|
||||||
{
|
{
|
||||||
// Collect UIParticle if needed (same size as m_ParticleSystems)
|
if (m_ParticleSystem == null) return;
|
||||||
CollectUIParticlesIfNeeded();
|
|
||||||
|
|
||||||
for (var particleIndex = 0; particleIndex < m_ParticleSystems.Count; particleIndex++)
|
var count = m_ParticleSystem.particleCount;
|
||||||
|
if (count == 0) return;
|
||||||
|
|
||||||
|
var particles = ParticleSystemExtensions.GetParticleArray(count);
|
||||||
|
m_ParticleSystem.GetParticles(particles, count);
|
||||||
|
|
||||||
|
var dstPos = GetDestinationPosition();
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
var particleSystem = m_ParticleSystems[particleIndex];
|
// Attracted
|
||||||
|
var p = particles[i];
|
||||||
// Skip: The ParticleSystem is not active
|
if (0f < p.remainingLifetime && Vector3.Distance(p.position, dstPos) < m_DestinationRadius)
|
||||||
if (particleSystem == null || !particleSystem.gameObject.activeInHierarchy) continue;
|
|
||||||
|
|
||||||
// Skip: No active particles
|
|
||||||
var count = particleSystem.particleCount;
|
|
||||||
if (count == 0) continue;
|
|
||||||
|
|
||||||
var particles = ParticleSystemExtensions.GetParticleArray(count);
|
|
||||||
particleSystem.GetParticles(particles, count);
|
|
||||||
|
|
||||||
var uiParticle = _uiParticles[particleIndex];
|
|
||||||
var dstPos = GetDestinationPosition(uiParticle, particleSystem);
|
|
||||||
for (var i = 0; i < count; i++)
|
|
||||||
{
|
{
|
||||||
// Attracted
|
p.remainingLifetime = 0f;
|
||||||
var p = particles[i];
|
particles[i] = p;
|
||||||
if (0f < p.remainingLifetime && Vector3.Distance(p.position, dstPos) < m_DestinationRadius)
|
|
||||||
|
if (m_OnAttracted != null)
|
||||||
{
|
{
|
||||||
p.remainingLifetime = 0f;
|
try
|
||||||
particles[i] = p;
|
|
||||||
|
|
||||||
if (m_OnAttracted != null)
|
|
||||||
{
|
{
|
||||||
try
|
m_OnAttracted.Invoke();
|
||||||
{
|
}
|
||||||
m_OnAttracted.Invoke();
|
catch (Exception e)
|
||||||
}
|
{
|
||||||
catch (Exception e)
|
Debug.LogException(e);
|
||||||
{
|
|
||||||
Debug.LogException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calc attracting time
|
continue;
|
||||||
var delayTime = p.startLifetime * m_DelayRate;
|
|
||||||
var duration = p.startLifetime - delayTime;
|
|
||||||
var time = Mathf.Max(0, p.startLifetime - p.remainingLifetime - delayTime);
|
|
||||||
|
|
||||||
// Delay
|
|
||||||
if (time <= 0) continue;
|
|
||||||
|
|
||||||
// Attract
|
|
||||||
p.position = GetAttractedPosition(p.position, dstPos, duration, time);
|
|
||||||
p.velocity *= 0.5f;
|
|
||||||
particles[i] = p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
particleSystem.SetParticles(particles, count);
|
// Calc attracting time
|
||||||
|
var delayTime = p.startLifetime * m_DelayRate;
|
||||||
|
var duration = p.startLifetime - delayTime;
|
||||||
|
var time = Mathf.Max(0, p.startLifetime - p.remainingLifetime - delayTime);
|
||||||
|
|
||||||
|
// Delay
|
||||||
|
if (time <= 0) continue;
|
||||||
|
|
||||||
|
// Attract
|
||||||
|
p.position = GetAttractedPosition(p.position, dstPos, duration, time);
|
||||||
|
p.velocity *= 0.5f;
|
||||||
|
particles[i] = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_ParticleSystem.SetParticles(particles, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector3 GetDestinationPosition(UIParticle uiParticle, ParticleSystem particleSystem)
|
private Vector3 GetDestinationPosition()
|
||||||
{
|
{
|
||||||
var isUI = uiParticle && uiParticle.enabled;
|
var isUI = _uiParticle && _uiParticle.enabled;
|
||||||
var psPos = particleSystem.transform.position;
|
var psPos = m_ParticleSystem.transform.position;
|
||||||
var attractorPos = transform.position;
|
var attractorPos = transform.position;
|
||||||
var dstPos = attractorPos;
|
var dstPos = attractorPos;
|
||||||
var isLocalSpace = particleSystem.IsLocalSpace();
|
var isLocalSpace = m_ParticleSystem.IsLocalSpace();
|
||||||
|
|
||||||
if (isLocalSpace)
|
if (isLocalSpace)
|
||||||
{
|
{
|
||||||
dstPos = particleSystem.transform.InverseTransformPoint(dstPos);
|
dstPos = m_ParticleSystem.transform.InverseTransformPoint(dstPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isUI)
|
if (isUI)
|
||||||
{
|
{
|
||||||
var inverseScale = uiParticle.parentScale.Inverse();
|
var inverseScale = _uiParticle.parentScale.Inverse();
|
||||||
var scale3d = uiParticle.scale3DForCalc;
|
var scale3d = _uiParticle.scale3DForCalc;
|
||||||
dstPos = dstPos.GetScaled(inverseScale, scale3d.Inverse());
|
dstPos = dstPos.GetScaled(inverseScale, scale3d.Inverse());
|
||||||
|
|
||||||
// Relative mode
|
// Relative mode
|
||||||
if (uiParticle.positionMode == UIParticle.PositionMode.Relative)
|
if (_uiParticle.positionMode == UIParticle.PositionMode.Relative)
|
||||||
{
|
{
|
||||||
var diff = uiParticle.transform.position - psPos;
|
var diff = _uiParticle.transform.position - psPos;
|
||||||
diff.Scale(scale3d - inverseScale);
|
diff.Scale(scale3d - inverseScale);
|
||||||
diff.Scale(scale3d.Inverse());
|
diff.Scale(scale3d.Inverse());
|
||||||
dstPos += diff;
|
dstPos += diff;
|
||||||
@@ -274,59 +237,25 @@ namespace Coffee.UIExtensions
|
|||||||
return Vector3.MoveTowards(current, target, speed);
|
return Vector3.MoveTowards(current, target, speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CollectUIParticlesIfNeeded()
|
private void ApplyParticleSystem()
|
||||||
{
|
{
|
||||||
if (m_ParticleSystems.Count == 0 || _uiParticles.Count != 0) return;
|
_uiParticle = null;
|
||||||
|
if (m_ParticleSystem == null)
|
||||||
// Expand capacity
|
|
||||||
if (_uiParticles.Capacity < m_ParticleSystems.Capacity)
|
|
||||||
{
|
{
|
||||||
_uiParticles.Capacity = m_ParticleSystems.Capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find UIParticle that controls the ParticleSystem
|
|
||||||
for (var i = 0; i < m_ParticleSystems.Count; i++)
|
|
||||||
{
|
|
||||||
var ps = m_ParticleSystems[i];
|
|
||||||
if (ps == null)
|
|
||||||
{
|
|
||||||
_uiParticles.Add(null);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var uiParticle = ps.GetComponentInParent<UIParticle>(true);
|
|
||||||
_uiParticles.Add(uiParticle.particles.Contains(ps) ? uiParticle : null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
private void OnValidate()
|
if (Application.isPlaying)
|
||||||
{
|
|
||||||
_uiParticles.Clear();
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
|
||||||
{
|
|
||||||
UpgradeIfNeeded();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ISerializationCallbackReceiver.OnAfterDeserialize()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpgradeIfNeeded()
|
|
||||||
{
|
|
||||||
// Multiple ParticleSystems support: from 'm_ParticleSystem' to 'm_ParticleSystems'
|
|
||||||
if (m_ParticleSystem != null)
|
|
||||||
{
|
|
||||||
if (!m_ParticleSystems.Contains(m_ParticleSystem))
|
|
||||||
{
|
{
|
||||||
m_ParticleSystems.Add(m_ParticleSystem);
|
Debug.LogError("No particle system attached to particle attractor script", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ParticleSystem = null;
|
return;
|
||||||
Debug.Log($"Upgraded!");
|
}
|
||||||
|
|
||||||
|
_uiParticle = m_ParticleSystem.GetComponentInParent<UIParticle>(true);
|
||||||
|
if (_uiParticle && !_uiParticle.particles.Contains(m_ParticleSystem))
|
||||||
|
{
|
||||||
|
_uiParticle = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ MonoImporter:
|
|||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
defaultReferences: []
|
defaultReferences: []
|
||||||
executionOrder: 0
|
executionOrder: 0
|
||||||
icon: {fileID: 2800000, guid: 5f0675613942149309588d556e33d990, type: 3}
|
icon: {instanceID: 0}
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
assetBundleVariant:
|
assetBundleVariant:
|
||||||
|
|||||||
@@ -17,18 +17,6 @@ namespace Coffee.UIExtensions
|
|||||||
set => instance.m_EnableLinearToGamma = value;
|
set => instance.m_EnableLinearToGamma = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Header("Editor")]
|
|
||||||
[Tooltip("Hide the automatically generated objects.\n" +
|
|
||||||
" - UIParticleRenderer\n" +
|
|
||||||
" - UIParticle BakingCamera")]
|
|
||||||
[SerializeField]
|
|
||||||
private bool m_HideGeneratedObjects = true;
|
|
||||||
|
|
||||||
public static HideFlags globalHideFlags => instance.m_HideGeneratedObjects
|
|
||||||
? HideFlags.DontSave | HideFlags.NotEditable | HideFlags.HideInHierarchy | HideFlags.HideInInspector
|
|
||||||
: HideFlags.DontSave | HideFlags.NotEditable;
|
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
[SettingsProvider]
|
[SettingsProvider]
|
||||||
private static SettingsProvider CreateSettingsProvider()
|
private static SettingsProvider CreateSettingsProvider()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ MonoImporter:
|
|||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
defaultReferences: []
|
defaultReferences: []
|
||||||
executionOrder: 0
|
executionOrder: 0
|
||||||
icon: {fileID: 2800000, guid: 5f0675613942149309588d556e33d990, type: 3}
|
icon: {instanceID: 0}
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
assetBundleVariant:
|
assetBundleVariant:
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#elif UNITY_2022_3_OR_NEWER
|
#elif UNITY_2022_3_OR_NEWER
|
||||||
#define PS_BAKE_API_V2
|
#define PS_BAKE_API_V2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Coffee.UIParticleInternal;
|
using Coffee.UIParticleInternal;
|
||||||
@@ -24,10 +25,10 @@ namespace Coffee.UIExtensions
|
|||||||
private static readonly CombineInstance[] s_CombineInstances = { new CombineInstance() };
|
private static readonly CombineInstance[] s_CombineInstances = { new CombineInstance() };
|
||||||
private static readonly List<Material> s_Materials = new List<Material>(2);
|
private static readonly List<Material> s_Materials = new List<Material>(2);
|
||||||
private static MaterialPropertyBlock s_Mpb;
|
private static MaterialPropertyBlock s_Mpb;
|
||||||
|
private static readonly List<UIParticleRenderer> s_Renderers = new List<UIParticleRenderer>(8);
|
||||||
private static readonly Vector3[] s_Corners = new Vector3[4];
|
private static readonly Vector3[] s_Corners = new Vector3[4];
|
||||||
private bool _delay;
|
private bool _delay;
|
||||||
private int _index;
|
private int _index;
|
||||||
private bool _isPrevStored;
|
|
||||||
private bool _isTrail;
|
private bool _isTrail;
|
||||||
private Bounds _lastBounds;
|
private Bounds _lastBounds;
|
||||||
private Material _materialForRendering;
|
private Material _materialForRendering;
|
||||||
@@ -37,10 +38,10 @@ namespace Coffee.UIExtensions
|
|||||||
private float _prevCanvasScale;
|
private float _prevCanvasScale;
|
||||||
private Vector3 _prevPsPos;
|
private Vector3 _prevPsPos;
|
||||||
private Vector3 _prevScale;
|
private Vector3 _prevScale;
|
||||||
|
private bool _isPrevStored;
|
||||||
private Vector2Int _prevScreenSize;
|
private Vector2Int _prevScreenSize;
|
||||||
private bool _preWarm;
|
private bool _preWarm;
|
||||||
private ParticleSystemRenderer _renderer;
|
private ParticleSystemRenderer _renderer;
|
||||||
private ParticleSystem _mainEmitter;
|
|
||||||
|
|
||||||
public override Texture mainTexture => _isTrail ? null : _particleSystem.GetTextureForSprite();
|
public override Texture mainTexture => _isTrail ? null : _particleSystem.GetTextureForSprite();
|
||||||
|
|
||||||
@@ -113,7 +114,6 @@ namespace Coffee.UIExtensions
|
|||||||
_parent = null;
|
_parent = null;
|
||||||
_particleSystem = null;
|
_particleSystem = null;
|
||||||
_renderer = null;
|
_renderer = null;
|
||||||
_mainEmitter = null;
|
|
||||||
if (0 <= index)
|
if (0 <= index)
|
||||||
{
|
{
|
||||||
_index = index;
|
_index = index;
|
||||||
@@ -138,7 +138,6 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
base.OnEnable();
|
base.OnEnable();
|
||||||
|
|
||||||
hideFlags = UIParticleProjectSettings.globalHideFlags;
|
|
||||||
if (!s_CombineInstances[0].mesh)
|
if (!s_CombineInstances[0].mesh)
|
||||||
{
|
{
|
||||||
s_CombineInstances[0].mesh = new Mesh
|
s_CombineInstances[0].mesh = new Mesh
|
||||||
@@ -163,7 +162,7 @@ namespace Coffee.UIExtensions
|
|||||||
// Create renderer object.
|
// Create renderer object.
|
||||||
var go = new GameObject("[generated] UIParticleRenderer", typeof(UIParticleRenderer))
|
var go = new GameObject("[generated] UIParticleRenderer", typeof(UIParticleRenderer))
|
||||||
{
|
{
|
||||||
hideFlags = UIParticleProjectSettings.globalHideFlags,
|
hideFlags = HideFlags.HideAndDontSave,
|
||||||
layer = parent.gameObject.layer
|
layer = parent.gameObject.layer
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -203,6 +202,7 @@ namespace Coffee.UIExtensions
|
|||||||
return modifiedMaterial;
|
return modifiedMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
var hash = new Hash128(
|
var hash = new Hash128(
|
||||||
modifiedMaterial ? (uint)modifiedMaterial.GetInstanceID() : 0,
|
modifiedMaterial ? (uint)modifiedMaterial.GetInstanceID() : 0,
|
||||||
texture ? (uint)texture.GetInstanceID() : 0,
|
texture ? (uint)texture.GetInstanceID() : 0,
|
||||||
@@ -225,7 +225,7 @@ namespace Coffee.UIExtensions
|
|||||||
return _modifiedMaterial;
|
return _modifiedMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Set(UIParticle parent, ParticleSystem ps, bool isTrail, ParticleSystem mainEmitter)
|
public void Set(UIParticle parent, ParticleSystem ps, bool isTrail)
|
||||||
{
|
{
|
||||||
_parent = parent;
|
_parent = parent;
|
||||||
maskable = parent.maskable;
|
maskable = parent.maskable;
|
||||||
@@ -248,7 +248,10 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
ps.TryGetComponent(out _renderer);
|
ps.TryGetComponent(out _renderer);
|
||||||
_renderer.enabled = false;
|
_renderer.enabled = false;
|
||||||
|
|
||||||
|
//_emitter = emitter;
|
||||||
_isTrail = isTrail;
|
_isTrail = isTrail;
|
||||||
|
|
||||||
_renderer.GetSharedMaterials(s_Materials);
|
_renderer.GetSharedMaterials(s_Materials);
|
||||||
material = s_Materials[isTrail ? 1 : 0];
|
material = s_Materials[isTrail ? 1 : 0];
|
||||||
s_Materials.Clear();
|
s_Materials.Clear();
|
||||||
@@ -265,7 +268,6 @@ namespace Coffee.UIExtensions
|
|||||||
_prevScreenSize = new Vector2Int(Screen.width, Screen.height);
|
_prevScreenSize = new Vector2Int(Screen.width, Screen.height);
|
||||||
_prevCanvasScale = canvas ? canvas.scaleFactor : 1f;
|
_prevCanvasScale = canvas ? canvas.scaleFactor : 1f;
|
||||||
_delay = true;
|
_delay = true;
|
||||||
_mainEmitter = mainEmitter;
|
|
||||||
|
|
||||||
canvasRenderer.SetTexture(null);
|
canvasRenderer.SetTexture(null);
|
||||||
|
|
||||||
@@ -303,7 +305,7 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
// Simulate particles.
|
// Simulate particles.
|
||||||
Profiler.BeginSample("[UIParticle] Bake Mesh > Simulate Particles");
|
Profiler.BeginSample("[UIParticle] Bake Mesh > Simulate Particles");
|
||||||
if (!_isTrail && _parent.canSimulate && !_mainEmitter)
|
if (!_isTrail && _parent.canSimulate)
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
if (!Application.isPlaying)
|
if (!Application.isPlaying)
|
||||||
@@ -421,16 +423,17 @@ namespace Coffee.UIExtensions
|
|||||||
workerMesh.LinearToGamma();
|
workerMesh.LinearToGamma();
|
||||||
}
|
}
|
||||||
|
|
||||||
var components = InternalListPool<Component>.Rent();
|
var components = ListPool<Component>.Rent();
|
||||||
GetComponents(typeof(IMeshModifier), components);
|
GetComponents(typeof(IMeshModifier), components);
|
||||||
|
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
for (var i = 0; i < components.Count; i++)
|
for (var i = 0; i < components.Count; i++)
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0618 // Type or member is obsolete
|
|
||||||
((IMeshModifier)components[i]).ModifyMesh(workerMesh);
|
((IMeshModifier)components[i]).ModifyMesh(workerMesh);
|
||||||
#pragma warning restore CS0618 // Type or member is obsolete
|
|
||||||
}
|
}
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
|
|
||||||
InternalListPool<Component>.Return(ref components);
|
ListPool<Component>.Return(ref components);
|
||||||
}
|
}
|
||||||
|
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
@@ -442,25 +445,22 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
// Get grouped renderers.
|
// Get grouped renderers.
|
||||||
Profiler.BeginSample("[UIParticleRenderer] Set Mesh");
|
Profiler.BeginSample("[UIParticleRenderer] Set Mesh");
|
||||||
var renderers = InternalListPool<UIParticleRenderer>.Rent();
|
s_Renderers.Clear();
|
||||||
if (_parent.useMeshSharing)
|
if (_parent.useMeshSharing)
|
||||||
{
|
{
|
||||||
UIParticleUpdater.GetGroupedRenderers(_parent.groupId, _index, renderers);
|
UIParticleUpdater.GetGroupedRenderers(_parent.groupId, _index, s_Renderers);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < renderers.Count; i++)
|
for (var i = 0; i < s_Renderers.Count; i++)
|
||||||
{
|
{
|
||||||
var r = renderers[i];
|
if (s_Renderers[i] == this) continue;
|
||||||
if (r == this) continue;
|
|
||||||
|
|
||||||
r.canvasRenderer.SetMesh(workerMesh);
|
s_Renderers[i].canvasRenderer.SetMesh(workerMesh);
|
||||||
r._lastBounds = _lastBounds;
|
s_Renderers[i]._lastBounds = _lastBounds;
|
||||||
r.canvasRenderer.materialCount = 1;
|
s_Renderers[i].canvasRenderer.materialCount = 1;
|
||||||
r.canvasRenderer.SetMaterial(materialForRendering, 0);
|
s_Renderers[i].canvasRenderer.SetMaterial(materialForRendering, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalListPool<UIParticleRenderer>.Return(ref renderers);
|
|
||||||
|
|
||||||
if (_parent.canRender)
|
if (_parent.canRender)
|
||||||
{
|
{
|
||||||
canvasRenderer.SetMesh(workerMesh);
|
canvasRenderer.SetMesh(workerMesh);
|
||||||
@@ -471,6 +471,8 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
|
|
||||||
|
s_Renderers.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SetMaterialDirty()
|
public override void SetMaterialDirty()
|
||||||
@@ -542,30 +544,6 @@ namespace Coffee.UIExtensions
|
|||||||
return Matrix4x4.Translate(psPos)
|
return Matrix4x4.Translate(psPos)
|
||||||
* Matrix4x4.Scale(scale);
|
* Matrix4x4.Scale(scale);
|
||||||
case ParticleSystemSimulationSpace.World:
|
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);
|
return Matrix4x4.Scale(scale);
|
||||||
case ParticleSystemSimulationSpace.Custom:
|
case ParticleSystemSimulationSpace.Custom:
|
||||||
return Matrix4x4.Translate(_particleSystem.main.customSimulationSpace.position.GetScaled(scale))
|
return Matrix4x4.Translate(_particleSystem.main.customSimulationSpace.position.GetScaled(scale))
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ MonoImporter:
|
|||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
defaultReferences: []
|
defaultReferences: []
|
||||||
executionOrder: 0
|
executionOrder: 0
|
||||||
icon: {fileID: 2800000, guid: 5f0675613942149309588d556e33d990, type: 3}
|
icon: {instanceID: 0}
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
assetBundleVariant:
|
assetBundleVariant:
|
||||||
|
|||||||
@@ -40,26 +40,13 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
[InitializeOnLoadMethod]
|
[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
|
#else
|
||||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||||
|
#endif
|
||||||
private static void InitializeOnLoad()
|
private static void InitializeOnLoad()
|
||||||
{
|
{
|
||||||
UIExtraCallbacks.onAfterCanvasRebuild += Refresh;
|
UIExtraCallbacks.onAfterCanvasRebuild += Refresh;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
private static void Refresh()
|
private static void Refresh()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -171,30 +171,5 @@ namespace Coffee.UIParticleInternal
|
|||||||
action.Invoke(p);
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using Coffee.UIParticleInternal;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Serialization;
|
using UnityEngine.Serialization;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
@@ -52,7 +51,7 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
|
|
||||||
public void EnableAnimations(bool flag)
|
public void EnableAnimations(bool flag)
|
||||||
{
|
{
|
||||||
foreach (var animator in Misc.FindObjectsOfType<Animator>())
|
foreach (var animator in FindObjectsOfType<Animator>())
|
||||||
{
|
{
|
||||||
animator.enabled = flag;
|
animator.enabled = flag;
|
||||||
}
|
}
|
||||||
@@ -80,7 +79,7 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
|
|
||||||
public void UIParticle_Scale(float scale)
|
public void UIParticle_Scale(float scale)
|
||||||
{
|
{
|
||||||
foreach (var uip in Misc.FindObjectsOfType<UIParticle>())
|
foreach (var uip in FindObjectsOfType<UIParticle>())
|
||||||
{
|
{
|
||||||
uip.scale = scale;
|
uip.scale = scale;
|
||||||
}
|
}
|
||||||
@@ -88,7 +87,7 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
|
|
||||||
public void ParticleSystem_WorldSpaseSimulation(bool flag)
|
public void ParticleSystem_WorldSpaseSimulation(bool flag)
|
||||||
{
|
{
|
||||||
foreach (var p in Misc.FindObjectsOfType<ParticleSystem>())
|
foreach (var p in FindObjectsOfType<ParticleSystem>())
|
||||||
{
|
{
|
||||||
var main = p.main;
|
var main = p.main;
|
||||||
main.simulationSpace = flag
|
main.simulationSpace = flag
|
||||||
@@ -124,7 +123,7 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
|
|
||||||
public void ParticleSystem_SetScale(float scale)
|
public void ParticleSystem_SetScale(float scale)
|
||||||
{
|
{
|
||||||
foreach (var ps in Misc.FindObjectsOfType<ParticleSystem>())
|
foreach (var ps in FindObjectsOfType<ParticleSystem>())
|
||||||
{
|
{
|
||||||
ps.transform.localScale = new Vector3(scale, scale, scale);
|
ps.transform.localScale = new Vector3(scale, scale, scale);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,12 +42,12 @@ TextureImporter:
|
|||||||
compressionQuality: 50
|
compressionQuality: 50
|
||||||
spriteMode: 1
|
spriteMode: 1
|
||||||
spriteExtrude: 1
|
spriteExtrude: 1
|
||||||
spriteMeshType: 0
|
spriteMeshType: 1
|
||||||
alignment: 0
|
alignment: 0
|
||||||
spritePivot: {x: 0.5, y: 0.5}
|
spritePivot: {x: 0.5, y: 0.5}
|
||||||
spritePixelsToUnits: 100
|
spritePixelsToUnits: 100
|
||||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
spriteGenerateFallbackPhysicsShape: 0
|
spriteGenerateFallbackPhysicsShape: 1
|
||||||
alphaUsage: 1
|
alphaUsage: 1
|
||||||
alphaIsTransparency: 1
|
alphaIsTransparency: 1
|
||||||
spriteTessellationDetail: -1
|
spriteTessellationDetail: -1
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ TextureImporter:
|
|||||||
generateCubemap: 6
|
generateCubemap: 6
|
||||||
cubemapConvolution: 0
|
cubemapConvolution: 0
|
||||||
seamlessCubemap: 0
|
seamlessCubemap: 0
|
||||||
textureFormat: 4
|
textureFormat: 1
|
||||||
maxTextureSize: 2048
|
maxTextureSize: 2048
|
||||||
textureSettings:
|
textureSettings:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -42,12 +42,12 @@ TextureImporter:
|
|||||||
compressionQuality: 50
|
compressionQuality: 50
|
||||||
spriteMode: 1
|
spriteMode: 1
|
||||||
spriteExtrude: 1
|
spriteExtrude: 1
|
||||||
spriteMeshType: 0
|
spriteMeshType: 1
|
||||||
alignment: 0
|
alignment: 0
|
||||||
spritePivot: {x: 0.5, y: 0.5}
|
spritePivot: {x: 0.5, y: 0.5}
|
||||||
spritePixelsToUnits: 100
|
spritePixelsToUnits: 100
|
||||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
spriteGenerateFallbackPhysicsShape: 0
|
spriteGenerateFallbackPhysicsShape: 1
|
||||||
alphaUsage: 1
|
alphaUsage: 1
|
||||||
alphaIsTransparency: 1
|
alphaIsTransparency: 1
|
||||||
spriteTessellationDetail: -1
|
spriteTessellationDetail: -1
|
||||||
|
|||||||
@@ -42,12 +42,12 @@ TextureImporter:
|
|||||||
compressionQuality: 50
|
compressionQuality: 50
|
||||||
spriteMode: 1
|
spriteMode: 1
|
||||||
spriteExtrude: 1
|
spriteExtrude: 1
|
||||||
spriteMeshType: 0
|
spriteMeshType: 1
|
||||||
alignment: 0
|
alignment: 0
|
||||||
spritePivot: {x: 0.5, y: 0.5}
|
spritePivot: {x: 0.5, y: 0.5}
|
||||||
spritePixelsToUnits: 100
|
spritePixelsToUnits: 100
|
||||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
spriteGenerateFallbackPhysicsShape: 0
|
spriteGenerateFallbackPhysicsShape: 1
|
||||||
alphaUsage: 0
|
alphaUsage: 0
|
||||||
alphaIsTransparency: 1
|
alphaIsTransparency: 1
|
||||||
spriteTessellationDetail: -1
|
spriteTessellationDetail: -1
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ TextureImporter:
|
|||||||
generateCubemap: 6
|
generateCubemap: 6
|
||||||
cubemapConvolution: 0
|
cubemapConvolution: 0
|
||||||
seamlessCubemap: 0
|
seamlessCubemap: 0
|
||||||
textureFormat: 4
|
textureFormat: -1
|
||||||
maxTextureSize: 2048
|
maxTextureSize: 2048
|
||||||
textureSettings:
|
textureSettings:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -42,12 +42,12 @@ TextureImporter:
|
|||||||
compressionQuality: 50
|
compressionQuality: 50
|
||||||
spriteMode: 1
|
spriteMode: 1
|
||||||
spriteExtrude: 1
|
spriteExtrude: 1
|
||||||
spriteMeshType: 0
|
spriteMeshType: 1
|
||||||
alignment: 0
|
alignment: 0
|
||||||
spritePivot: {x: 0.5, y: 0.5}
|
spritePivot: {x: 0.5, y: 0.5}
|
||||||
spritePixelsToUnits: 100
|
spritePixelsToUnits: 100
|
||||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
spriteGenerateFallbackPhysicsShape: 0
|
spriteGenerateFallbackPhysicsShape: 1
|
||||||
alphaUsage: 1
|
alphaUsage: 1
|
||||||
alphaIsTransparency: 1
|
alphaIsTransparency: 1
|
||||||
spriteTessellationDetail: -1
|
spriteTessellationDetail: -1
|
||||||
|
|||||||
@@ -40,10 +40,7 @@
|
|||||||
Lighting Off
|
Lighting Off
|
||||||
ZWrite Off
|
ZWrite Off
|
||||||
ZTest [unity_GUIZTestMode]
|
ZTest [unity_GUIZTestMode]
|
||||||
Fog
|
Fog { Mode Off }
|
||||||
{
|
|
||||||
Mode Off
|
|
||||||
}
|
|
||||||
Blend One One
|
Blend One One
|
||||||
|
|
||||||
ColorMask [_ColorMask]
|
ColorMask [_ColorMask]
|
||||||
@@ -64,18 +61,18 @@
|
|||||||
|
|
||||||
struct appdata_t
|
struct appdata_t
|
||||||
{
|
{
|
||||||
float4 vertex : POSITION;
|
float4 vertex : POSITION;
|
||||||
float4 color : COLOR;
|
float4 color : COLOR;
|
||||||
float2 texcoord : TEXCOORD0;
|
float2 texcoord : TEXCOORD0;
|
||||||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||||
};
|
};
|
||||||
|
|
||||||
struct v2f
|
struct v2f
|
||||||
{
|
{
|
||||||
float4 vertex : SV_POSITION;
|
float4 vertex : SV_POSITION;
|
||||||
fixed4 color : COLOR;
|
fixed4 color : COLOR;
|
||||||
float2 texcoord : TEXCOORD0;
|
float2 texcoord : TEXCOORD0;
|
||||||
float4 worldPosition : TEXCOORD1;
|
float4 worldPosition : TEXCOORD1;
|
||||||
UNITY_VERTEX_OUTPUT_STEREO
|
UNITY_VERTEX_OUTPUT_STEREO
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "com.coffee.ui-particle",
|
"name": "com.coffee.ui-particle",
|
||||||
"displayName": "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.",
|
"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.7",
|
"version": "5.0.0-preview.3",
|
||||||
"unity": "2018.2",
|
"unity": "2018.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
Reference in New Issue
Block a user