You've already forked ParticleEffectForUGUI
mirror of
https://github.com/mob-sakai/ParticleEffectForUGUI.git
synced 2026-05-15 20:50:08 +00:00
Compare commits
12 Commits
v4.8.1
...
develop-ne
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09ccb0d47c | ||
|
|
819de92b20 | ||
|
|
1628290db7 | ||
|
|
d33bde10d2 | ||
|
|
29e30a3f1b | ||
|
|
ae838587cb | ||
|
|
de5c617d12 | ||
|
|
15f9d92567 | ||
|
|
55fb8a0076 | ||
|
|
e6d8e43966 | ||
|
|
10a7fb4b7b | ||
|
|
3834780fdb |
@@ -46,7 +46,11 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
|
|
||||||
if (!flag)
|
if (!flag)
|
||||||
{
|
{
|
||||||
|
#if UNITY_2023_1_OR_NEWER
|
||||||
|
foreach (var ps in FindObjectsByType<ParticleSystem>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
||||||
|
#else
|
||||||
foreach (var ps in FindObjectsOfType<ParticleSystem>())
|
foreach (var ps in FindObjectsOfType<ParticleSystem>())
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
ps.Play(false);
|
ps.Play(false);
|
||||||
}
|
}
|
||||||
@@ -75,7 +79,11 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
|
|
||||||
public void ParticleSystem_SetScale(float scale)
|
public void ParticleSystem_SetScale(float scale)
|
||||||
{
|
{
|
||||||
|
#if UNITY_2023_1_OR_NEWER
|
||||||
|
foreach (var ps in FindObjectsByType<ParticleSystem>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
||||||
|
#else
|
||||||
foreach (var ps in FindObjectsOfType<ParticleSystem>())
|
foreach (var ps in FindObjectsOfType<ParticleSystem>())
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
ps.transform.localScale = new Vector3(scale, scale, scale);
|
ps.transform.localScale = new Vector3(scale, scale, scale);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,15 +14,15 @@ MonoBehaviour:
|
|||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
m_NanoMonitorEnabled: 1
|
m_NanoMonitorEnabled: 1
|
||||||
m_BootSceneNameRegex: .*
|
m_BootSceneNameRegex: .*
|
||||||
m_DevelopmentBuildOnly: 1
|
m_DevelopmentBuildOnly: 0
|
||||||
m_EnabledInEditor: 1
|
m_EnabledInEditor: 1
|
||||||
m_AlwaysIncludeAssembly: 1
|
m_AlwaysIncludeAssembly: 1
|
||||||
m_InstantiateOnLoad: 1
|
m_InstantiateOnLoad: 1
|
||||||
m_Prefab: {fileID: 7211429669315726685, guid: b73940fc30a2f4eb9a73783e9c1f8da6,
|
m_Prefab: {fileID: 7211429669315726685, guid: b73940fc30a2f4eb9a73783e9c1f8da6,
|
||||||
type: 3}
|
type: 3}
|
||||||
m_Opened: 1
|
|
||||||
m_Interval: 0.5
|
m_Interval: 0.5
|
||||||
m_Anchor: 1
|
m_Anchor: 0
|
||||||
|
m_Width: 750
|
||||||
m_CustomMonitorItems:
|
m_CustomMonitorItems:
|
||||||
- m_Format: Screen:{0}x{1}
|
- m_Format: Screen:{0}x{1}
|
||||||
m_Arg0:
|
m_Arg0:
|
||||||
@@ -31,3 +31,10 @@ MonoBehaviour:
|
|||||||
m_Path: UnityEngine.Screen, UnityEngine.CoreModule;height
|
m_Path: UnityEngine.Screen, UnityEngine.CoreModule;height
|
||||||
m_Arg2:
|
m_Arg2:
|
||||||
m_Path:
|
m_Path:
|
||||||
|
- m_Format: UIParticles:{0} Materials:{1}
|
||||||
|
m_Arg0:
|
||||||
|
m_Path: Coffee.UIExtensions.UIParticleUpdater, Coffee.UIParticle;uiParticleCount
|
||||||
|
m_Arg1:
|
||||||
|
m_Path: Coffee.UIParticleInternal.MaterialRepository, Coffee.UIParticle;count
|
||||||
|
m_Arg2:
|
||||||
|
m_Path:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,20 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!114 &11400000
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 0}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 94e8c16a26d334eafa227ee444387432, type: 3}
|
|
||||||
m_Name: SimpleSceneNavigator
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
m_NavigatorEnabled: 1
|
|
||||||
m_EnabledInEditor: 1
|
|
||||||
m_AlwaysIncludeAssembly: 1
|
|
||||||
m_InstantiateOnLoad: 1
|
|
||||||
m_Prefab: {fileID: 7211429669315726685, guid: 46deb9632f6a14713b8460bd01e879c9,
|
|
||||||
type: 3}
|
|
||||||
@@ -1,513 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!1 &3877588430955763108
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 3877588430955763111}
|
|
||||||
- component: {fileID: 3877588430955763105}
|
|
||||||
- component: {fileID: 3877588430955763110}
|
|
||||||
m_Layer: 5
|
|
||||||
m_Name: Text
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!224 &3877588430955763111
|
|
||||||
RectTransform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3877588430955763108}
|
|
||||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
|
||||||
m_Children: []
|
|
||||||
m_Father: {fileID: 3877588431231610297}
|
|
||||||
m_RootOrder: 0
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
m_AnchorMin: {x: 0, y: 0}
|
|
||||||
m_AnchorMax: {x: 1, y: 1}
|
|
||||||
m_AnchoredPosition: {x: 0, y: 0}
|
|
||||||
m_SizeDelta: {x: 0, y: 0}
|
|
||||||
m_Pivot: {x: 0.5, y: 0.5}
|
|
||||||
--- !u!222 &3877588430955763105
|
|
||||||
CanvasRenderer:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3877588430955763108}
|
|
||||||
m_CullTransparentMesh: 0
|
|
||||||
--- !u!114 &3877588430955763110
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3877588430955763108}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
m_Material: {fileID: 0}
|
|
||||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
|
||||||
m_RaycastTarget: 1
|
|
||||||
m_Maskable: 1
|
|
||||||
m_OnCullStateChanged:
|
|
||||||
m_PersistentCalls:
|
|
||||||
m_Calls: []
|
|
||||||
m_FontData:
|
|
||||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
|
||||||
m_FontSize: 14
|
|
||||||
m_FontStyle: 0
|
|
||||||
m_BestFit: 0
|
|
||||||
m_MinSize: 10
|
|
||||||
m_MaxSize: 40
|
|
||||||
m_Alignment: 4
|
|
||||||
m_AlignByGeometry: 0
|
|
||||||
m_RichText: 1
|
|
||||||
m_HorizontalOverflow: 1
|
|
||||||
m_VerticalOverflow: 1
|
|
||||||
m_LineSpacing: 1
|
|
||||||
m_Text: '>>'
|
|
||||||
--- !u!1 &3877588431231610301
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 3877588431231610297}
|
|
||||||
- component: {fileID: 3877588431231610302}
|
|
||||||
- component: {fileID: 3877588431231610303}
|
|
||||||
- component: {fileID: 3877588431231610300}
|
|
||||||
m_Layer: 5
|
|
||||||
m_Name: Button - >>
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!224 &3877588431231610297
|
|
||||||
RectTransform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3877588431231610301}
|
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
|
||||||
m_Children:
|
|
||||||
- {fileID: 3877588430955763111}
|
|
||||||
m_Father: {fileID: 7211429669315725985}
|
|
||||||
m_RootOrder: 1
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
m_AnchorMin: {x: 1, y: 1}
|
|
||||||
m_AnchorMax: {x: 1, y: 1}
|
|
||||||
m_AnchoredPosition: {x: 0, y: 0}
|
|
||||||
m_SizeDelta: {x: 30, y: 30}
|
|
||||||
m_Pivot: {x: 1, y: 1}
|
|
||||||
--- !u!222 &3877588431231610302
|
|
||||||
CanvasRenderer:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3877588431231610301}
|
|
||||||
m_CullTransparentMesh: 0
|
|
||||||
--- !u!114 &3877588431231610303
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3877588431231610301}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
m_Material: {fileID: 0}
|
|
||||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
|
||||||
m_RaycastTarget: 1
|
|
||||||
m_Maskable: 1
|
|
||||||
m_OnCullStateChanged:
|
|
||||||
m_PersistentCalls:
|
|
||||||
m_Calls: []
|
|
||||||
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
m_Type: 1
|
|
||||||
m_PreserveAspect: 0
|
|
||||||
m_FillCenter: 1
|
|
||||||
m_FillMethod: 4
|
|
||||||
m_FillAmount: 1
|
|
||||||
m_FillClockwise: 1
|
|
||||||
m_FillOrigin: 0
|
|
||||||
m_UseSpriteMesh: 0
|
|
||||||
m_PixelsPerUnitMultiplier: 1
|
|
||||||
--- !u!114 &3877588431231610300
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3877588431231610301}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
m_Navigation:
|
|
||||||
m_Mode: 3
|
|
||||||
m_SelectOnUp: {fileID: 0}
|
|
||||||
m_SelectOnDown: {fileID: 0}
|
|
||||||
m_SelectOnLeft: {fileID: 0}
|
|
||||||
m_SelectOnRight: {fileID: 0}
|
|
||||||
m_Transition: 1
|
|
||||||
m_Colors:
|
|
||||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
|
||||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
|
||||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
|
||||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
|
||||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
|
||||||
m_ColorMultiplier: 1
|
|
||||||
m_FadeDuration: 0.1
|
|
||||||
m_SpriteState:
|
|
||||||
m_HighlightedSprite: {fileID: 0}
|
|
||||||
m_PressedSprite: {fileID: 0}
|
|
||||||
m_SelectedSprite: {fileID: 0}
|
|
||||||
m_DisabledSprite: {fileID: 0}
|
|
||||||
m_AnimationTriggers:
|
|
||||||
m_NormalTrigger: Normal
|
|
||||||
m_HighlightedTrigger: Highlighted
|
|
||||||
m_PressedTrigger: Pressed
|
|
||||||
m_SelectedTrigger: Selected
|
|
||||||
m_DisabledTrigger: Disabled
|
|
||||||
m_Interactable: 1
|
|
||||||
m_TargetGraphic: {fileID: 3877588431231610303}
|
|
||||||
m_OnClick:
|
|
||||||
m_PersistentCalls:
|
|
||||||
m_Calls: []
|
|
||||||
--- !u!1 &3877588432219069602
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 3877588432219069614}
|
|
||||||
- component: {fileID: 3877588432219069615}
|
|
||||||
- component: {fileID: 3877588432219069612}
|
|
||||||
- component: {fileID: 3877588432219069613}
|
|
||||||
m_Layer: 5
|
|
||||||
m_Name: Button - <<
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!224 &3877588432219069614
|
|
||||||
RectTransform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3877588432219069602}
|
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
|
||||||
m_Children:
|
|
||||||
- {fileID: 1738594088889562266}
|
|
||||||
m_Father: {fileID: 7211429669315725985}
|
|
||||||
m_RootOrder: 0
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
m_AnchorMin: {x: 0, y: 1}
|
|
||||||
m_AnchorMax: {x: 0, y: 1}
|
|
||||||
m_AnchoredPosition: {x: 0, y: 0}
|
|
||||||
m_SizeDelta: {x: 30, y: 30}
|
|
||||||
m_Pivot: {x: 0, y: 1}
|
|
||||||
--- !u!222 &3877588432219069615
|
|
||||||
CanvasRenderer:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3877588432219069602}
|
|
||||||
m_CullTransparentMesh: 0
|
|
||||||
--- !u!114 &3877588432219069612
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3877588432219069602}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
m_Material: {fileID: 0}
|
|
||||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
|
||||||
m_RaycastTarget: 1
|
|
||||||
m_Maskable: 1
|
|
||||||
m_OnCullStateChanged:
|
|
||||||
m_PersistentCalls:
|
|
||||||
m_Calls: []
|
|
||||||
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
m_Type: 1
|
|
||||||
m_PreserveAspect: 0
|
|
||||||
m_FillCenter: 1
|
|
||||||
m_FillMethod: 4
|
|
||||||
m_FillAmount: 1
|
|
||||||
m_FillClockwise: 1
|
|
||||||
m_FillOrigin: 0
|
|
||||||
m_UseSpriteMesh: 0
|
|
||||||
m_PixelsPerUnitMultiplier: 1
|
|
||||||
--- !u!114 &3877588432219069613
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3877588432219069602}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
m_Navigation:
|
|
||||||
m_Mode: 3
|
|
||||||
m_SelectOnUp: {fileID: 0}
|
|
||||||
m_SelectOnDown: {fileID: 0}
|
|
||||||
m_SelectOnLeft: {fileID: 0}
|
|
||||||
m_SelectOnRight: {fileID: 0}
|
|
||||||
m_Transition: 1
|
|
||||||
m_Colors:
|
|
||||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
|
||||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
|
||||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
|
||||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
|
||||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
|
||||||
m_ColorMultiplier: 1
|
|
||||||
m_FadeDuration: 0.1
|
|
||||||
m_SpriteState:
|
|
||||||
m_HighlightedSprite: {fileID: 0}
|
|
||||||
m_PressedSprite: {fileID: 0}
|
|
||||||
m_SelectedSprite: {fileID: 0}
|
|
||||||
m_DisabledSprite: {fileID: 0}
|
|
||||||
m_AnimationTriggers:
|
|
||||||
m_NormalTrigger: Normal
|
|
||||||
m_HighlightedTrigger: Highlighted
|
|
||||||
m_PressedTrigger: Pressed
|
|
||||||
m_SelectedTrigger: Selected
|
|
||||||
m_DisabledTrigger: Disabled
|
|
||||||
m_Interactable: 1
|
|
||||||
m_TargetGraphic: {fileID: 3877588432219069612}
|
|
||||||
m_OnClick:
|
|
||||||
m_PersistentCalls:
|
|
||||||
m_Calls: []
|
|
||||||
--- !u!1 &7211429669315726685
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 7211429669315725985}
|
|
||||||
- component: {fileID: 7211429669315726686}
|
|
||||||
- component: {fileID: 7211429669315726687}
|
|
||||||
- component: {fileID: 7143702096253919615}
|
|
||||||
- component: {fileID: 3330778306119167604}
|
|
||||||
m_Layer: 5
|
|
||||||
m_Name: SimpleSceneNavigator
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!224 &7211429669315725985
|
|
||||||
RectTransform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 7211429669315726685}
|
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
|
||||||
m_LocalScale: {x: 0, y: 0, z: 0}
|
|
||||||
m_Children:
|
|
||||||
- {fileID: 3877588432219069614}
|
|
||||||
- {fileID: 3877588431231610297}
|
|
||||||
m_Father: {fileID: 0}
|
|
||||||
m_RootOrder: 0
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
m_AnchorMin: {x: 0, y: 0}
|
|
||||||
m_AnchorMax: {x: 0, y: 0}
|
|
||||||
m_AnchoredPosition: {x: 0, y: 0}
|
|
||||||
m_SizeDelta: {x: 0, y: 0}
|
|
||||||
m_Pivot: {x: 0, y: 0}
|
|
||||||
--- !u!223 &7211429669315726686
|
|
||||||
Canvas:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 7211429669315726685}
|
|
||||||
m_Enabled: 1
|
|
||||||
serializedVersion: 3
|
|
||||||
m_RenderMode: 0
|
|
||||||
m_Camera: {fileID: 0}
|
|
||||||
m_PlaneDistance: 100
|
|
||||||
m_PixelPerfect: 0
|
|
||||||
m_ReceivesEvents: 1
|
|
||||||
m_OverrideSorting: 0
|
|
||||||
m_OverridePixelPerfect: 0
|
|
||||||
m_SortingBucketNormalizedSize: 0
|
|
||||||
m_AdditionalShaderChannelsFlag: 0
|
|
||||||
m_SortingLayerID: 0
|
|
||||||
m_SortingOrder: 32000
|
|
||||||
m_TargetDisplay: 0
|
|
||||||
--- !u!114 &7211429669315726687
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 7211429669315726685}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
m_UiScaleMode: 1
|
|
||||||
m_ReferencePixelsPerUnit: 100
|
|
||||||
m_ScaleFactor: 1
|
|
||||||
m_ReferenceResolution: {x: 600, y: 40}
|
|
||||||
m_ScreenMatchMode: 0
|
|
||||||
m_MatchWidthOrHeight: 0
|
|
||||||
m_PhysicalUnit: 3
|
|
||||||
m_FallbackScreenDPI: 96
|
|
||||||
m_DefaultSpriteDPI: 96
|
|
||||||
m_DynamicPixelsPerUnit: 1
|
|
||||||
--- !u!114 &7143702096253919615
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 7211429669315726685}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
m_IgnoreReversedGraphics: 1
|
|
||||||
m_BlockingObjects: 0
|
|
||||||
m_BlockingMask:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Bits: 4294967295
|
|
||||||
--- !u!114 &3330778306119167604
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 7211429669315726685}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: e7db36469bd2a46658ff432d65cb62ca, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
m_PrevButton: {fileID: 3877588432219069613}
|
|
||||||
m_NextButton: {fileID: 3877588431231610300}
|
|
||||||
m_PrevName: {fileID: 0}
|
|
||||||
m_NextName: {fileID: 0}
|
|
||||||
--- !u!1 &8570858711609111474
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 1738594088889562266}
|
|
||||||
- component: {fileID: 5485386222362727379}
|
|
||||||
- component: {fileID: 3877588430751452752}
|
|
||||||
m_Layer: 5
|
|
||||||
m_Name: Text
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!224 &1738594088889562266
|
|
||||||
RectTransform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 8570858711609111474}
|
|
||||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
|
||||||
m_Children: []
|
|
||||||
m_Father: {fileID: 3877588432219069614}
|
|
||||||
m_RootOrder: 0
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
m_AnchorMin: {x: 0, y: 0}
|
|
||||||
m_AnchorMax: {x: 1, y: 1}
|
|
||||||
m_AnchoredPosition: {x: 0, y: 0}
|
|
||||||
m_SizeDelta: {x: 0, y: 0}
|
|
||||||
m_Pivot: {x: 0.5, y: 0.5}
|
|
||||||
--- !u!222 &5485386222362727379
|
|
||||||
CanvasRenderer:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 8570858711609111474}
|
|
||||||
m_CullTransparentMesh: 0
|
|
||||||
--- !u!114 &3877588430751452752
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 8570858711609111474}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
m_Material: {fileID: 0}
|
|
||||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
|
||||||
m_RaycastTarget: 1
|
|
||||||
m_Maskable: 1
|
|
||||||
m_OnCullStateChanged:
|
|
||||||
m_PersistentCalls:
|
|
||||||
m_Calls: []
|
|
||||||
m_FontData:
|
|
||||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
|
||||||
m_FontSize: 14
|
|
||||||
m_FontStyle: 0
|
|
||||||
m_BestFit: 0
|
|
||||||
m_MinSize: 10
|
|
||||||
m_MaxSize: 40
|
|
||||||
m_Alignment: 4
|
|
||||||
m_AlignByGeometry: 0
|
|
||||||
m_RichText: 1
|
|
||||||
m_HorizontalOverflow: 1
|
|
||||||
m_VerticalOverflow: 1
|
|
||||||
m_LineSpacing: 1
|
|
||||||
m_Text: <<
|
|
||||||
15
Assets/ProjectSettings/UIParticle.asset
Normal file
15
Assets/ProjectSettings/UIParticle.asset
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: f22a23b9d98e440478697f4adf30e61c, type: 3}
|
||||||
|
m_Name: UIParticle
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_LinearToGamma: 1
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: be3e05903ef7041d39b3ef8ecdd47f08
|
guid: e8e7744b163af4869b07b8f192c810ed
|
||||||
NativeFormatImporter:
|
NativeFormatImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
mainObjectFileID: 11400000
|
mainObjectFileID: 11400000
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"com.unity.ide.rider": "3.0.31",
|
"com.unity.ide.rider": "3.0.31",
|
||||||
|
"com.coffee.development": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/Development",
|
||||||
|
"com.coffee.nano-monitor": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/NanoMonitor",
|
||||||
|
"com.coffee.sub-asset-editor": "https://github.com/mob-sakai/SubAssetEditor.git",
|
||||||
"com.unity.test-framework": "1.1.33",
|
"com.unity.test-framework": "1.1.33",
|
||||||
"com.unity.modules.animation": "1.0.0",
|
"com.unity.modules.animation": "1.0.0",
|
||||||
"com.unity.modules.physics": "1.0.0"
|
"com.unity.modules.physics": "1.0.0"
|
||||||
|
|||||||
@@ -1,5 +1,28 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"com.coffee.development": {
|
||||||
|
"version": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/Development",
|
||||||
|
"depth": 0,
|
||||||
|
"source": "git",
|
||||||
|
"dependencies": {},
|
||||||
|
"hash": "c51e4514c9ab944915a639433ee52342e55a644e"
|
||||||
|
},
|
||||||
|
"com.coffee.nano-monitor": {
|
||||||
|
"version": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/NanoMonitor",
|
||||||
|
"depth": 0,
|
||||||
|
"source": "git",
|
||||||
|
"dependencies": {
|
||||||
|
"com.unity.ugui": "1.0.0"
|
||||||
|
},
|
||||||
|
"hash": "c51e4514c9ab944915a639433ee52342e55a644e"
|
||||||
|
},
|
||||||
|
"com.coffee.sub-asset-editor": {
|
||||||
|
"version": "https://github.com/mob-sakai/SubAssetEditor.git",
|
||||||
|
"depth": 0,
|
||||||
|
"source": "git",
|
||||||
|
"dependencies": {},
|
||||||
|
"hash": "01464178eec1e4dbe741c11c9baeb94a151c99ee"
|
||||||
|
},
|
||||||
"com.coffee.ui-particle": {
|
"com.coffee.ui-particle": {
|
||||||
"version": "file:src",
|
"version": "file:src",
|
||||||
"depth": 0,
|
"depth": 0,
|
||||||
|
|||||||
1
Packages/src/.coffee.internal.sed
Normal file
1
Packages/src/.coffee.internal.sed
Normal file
@@ -0,0 +1 @@
|
|||||||
|
s/Coffee.Internal/Coffee.UIParticleInternal/g
|
||||||
@@ -1,3 +1,10 @@
|
|||||||
|
# [4.9.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.8.1...v4.9.0) (2024-07-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* ParticleAttractor supports multiple ParticleSystems ([3834780](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/3834780fdb43443fe6e1ef89df54d26a24d62a91))
|
||||||
|
|
||||||
## [4.8.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.8.0...v4.8.1) (2024-06-27)
|
## [4.8.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.8.0...v4.8.1) (2024-06-27)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,21 +2,23 @@ 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.Profiling;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using Coffee.UIParticleExtensions;
|
|
||||||
#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;
|
||||||
|
|
||||||
#elif UNITY_2018_3_OR_NEWER
|
#elif UNITY_2018_3_OR_NEWER
|
||||||
using UnityEditor.Experimental.SceneManagement;
|
using UnityEditor.Experimental.SceneManagement;
|
||||||
#endif
|
#endif
|
||||||
@@ -25,7 +27,7 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
[CustomEditor(typeof(UIParticle))]
|
[CustomEditor(typeof(UIParticle))]
|
||||||
[CanEditMultipleObjects]
|
[CanEditMultipleObjects]
|
||||||
internal class UIParticleEditor : GraphicEditor
|
internal class UIParticleEditor : Editor
|
||||||
{
|
{
|
||||||
//################################
|
//################################
|
||||||
// Constant or Static Members.
|
// Constant or Static Members.
|
||||||
@@ -80,10 +82,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");
|
||||||
@@ -436,9 +436,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();
|
||||||
|
|||||||
@@ -1,28 +1,62 @@
|
|||||||
# <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)
|
# <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 -->
|
||||||
|
|
||||||
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.txt)
|
[](https://github.com/mob-sakai/ParticleEffectForUGUI/blob/main/LICENSE.md)
|
||||||

|

|
||||||
|

|
||||||
|

|
||||||

|

|
||||||
[](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) | [🎮 Demo](#-demo) | [⚙ Installation](#-installation) | [🚀 Usage](#-usage) | [🛠 Development Note](#-development-note) | [🤝 Contributing](#-contributing) >>
|
<< [📝 Description](#-description-) | [📌 Key Features](#-key-features) | [🎮 Demo](#-demo) | [⚙ Installation](#-installation) | [🔄 Upgrading to 5.x](#-upgrading-from-3x4x-to-5x) | [🚀 Usage](#-usage) | [🛠 Development Note](#-development-note) | [🤝 Contributing](#-contributing) >>
|
||||||
|
|
||||||
|
## 📝 Description <!-- omit in toc -->
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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)
|
||||||
|
- [🔄 Upgrading from 3.x/4.x to 5.x](#-upgrading-from-3x4x-to-5x)
|
||||||
|
- [Breaking Changes](#breaking-changes)
|
||||||
|
- [🚀 Usage](#-usage)
|
||||||
|
- [Component: UIParticle](#component-uiparticle)
|
||||||
|
- [Basic Usage](#basic-usage)
|
||||||
|
- [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)
|
||||||
|
- [🛠 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>
|
||||||
|
|
||||||
## 📝 Description
|
## 📌 Key Features
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
* **Easy to use:** The package is ready to use out of the box.
|
* **Easy to use:** The package is ready to use out of the box.
|
||||||
* **Sortable:** Sort particle effects and other UI elements by sibling index.
|
* **Sortable:** Sort particle effects and other UI elements by sibling index.
|
||||||
@@ -83,16 +117,16 @@ _This package requires **Unity 2018.3 or later**._
|
|||||||
```
|
```
|
||||||
- To update the package, use Package Manager UI (`Window > Package Manager`) or run the following command with `@{version}`:
|
- 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.8.0
|
openupm add com.coffee.ui-particle@4.9.0
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Install via UPM (with Package Manager UI)
|
#### Install via UPM (with Package Manager UI)
|
||||||
|
|
||||||
- Click `Window > Package Manager` to open Package Manager UI.
|
- Click `Window > Package Manager` to open Package Manager UI.
|
||||||
- Click `+ > Add package from git URL...` and input the repository URL: `https://github.com/mob-sakai/ParticleEffectForUGUI.git`
|
- Click `+ > Add package from git URL...` and input the repository URL: `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. `https://github.com/mob-sakai/ParticleEffectForUGUI.git#4.8.0`
|
- e.g. `https://github.com/mob-sakai/ParticleEffectForUGUI.git#4.9.0`
|
||||||
|
|
||||||
#### Install via UPM (Manually)
|
#### Install via UPM (Manually)
|
||||||
|
|
||||||
@@ -107,7 +141,7 @@ _This package requires **Unity 2018.3 or later**._
|
|||||||
```
|
```
|
||||||
|
|
||||||
- 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.8.0",`
|
- e.g. `"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git#4.9.0",`
|
||||||
|
|
||||||
#### Install as Embedded Package
|
#### Install as Embedded Package
|
||||||
|
|
||||||
@@ -119,9 +153,20 @@ _This package requires **Unity 2018.3 or later**._
|
|||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
|
## 🔄 Upgrading from 3.x/4.x to 5.x
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
- The default value of `UIParticle.scale` has been changed from `10` to `1`.
|
||||||
|
- `UIParticle` no longer inherits from `MaskableGraphic`.
|
||||||
|
- Add project settings for UIParticle
|
||||||
|
- enableLinearToGamma: Enables LinearToGamma during mesh baking
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
|
||||||
## 🚀 Usage
|
## 🚀 Usage
|
||||||
|
|
||||||
### UIParticle Component
|
### Component: UIParticle
|
||||||
|
|
||||||
`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.
|
||||||
|
|
||||||
@@ -154,7 +199,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.
|
||||||

|

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

|

|
||||||
@@ -172,7 +217,7 @@ and z-position.
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
#### With `Mask` or `RectMask2D` Component
|
### Usage 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.
|
||||||
@@ -184,7 +229,7 @@ section.
|
|||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
### Script usage
|
### Usage with Script
|
||||||
|
|
||||||
```cs
|
```cs
|
||||||
// Instantiate ParticleSystem prefab with UIParticle on runtime.
|
// Instantiate ParticleSystem prefab with UIParticle on runtime.
|
||||||
@@ -203,14 +248,14 @@ uiParticle.Stop();
|
|||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
### UIParticleAttractor component
|
### Component: UIParticleAttractor
|
||||||
|
|
||||||
`UIParticleAttractor` attracts particles generated by the specified ParticleSystem.
|
`UIParticleAttractor` attracts particles generated by the specified ParticleSystem.
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
- **Particle System**: Attracts particles generated by the specified particle system.
|
- **Particle Systems**: Attracts particles generated by the specified ParticleSystems.
|
||||||
- **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.
|
||||||
@@ -355,7 +400,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/RectMask2D Component
|
### How to Make a Custom Shader to Support `Mask` and `RectMask2D` Component
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Shader tips</summary>
|
<summary>Shader tips</summary>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 46deb9632f6a14713b8460bd01e879c9
|
guid: 53aa3f36032944b3fb1455e774c52396
|
||||||
PrefabImporter:
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
8
Packages/src/Runtime/Internal/Extensions.meta
Normal file
8
Packages/src/Runtime/Internal/Extensions.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8cf8018dee45a4c42a19eec890eaa5b1
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
134
Packages/src/Runtime/Internal/Extensions/CanvasExtensions.cs
Normal file
134
Packages/src/Runtime/Internal/Extensions/CanvasExtensions.cs
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
#if UNITY_2021_3_0 || UNITY_2021_3_1 || UNITY_2021_3_2 || UNITY_2021_3_3 || UNITY_2021_3_4 || UNITY_2021_3_5 || UNITY_2021_3_6 || UNITY_2021_3_7 || UNITY_2021_3_8 || UNITY_2021_3_9
|
||||||
|
#elif UNITY_2021_3_10 || UNITY_2021_3_11 || UNITY_2021_3_12 || UNITY_2021_3_13 || UNITY_2021_3_14 || UNITY_2021_3_15 || UNITY_2021_3_16 || UNITY_2021_3_17 || UNITY_2021_3_18 || UNITY_2021_3_19
|
||||||
|
#elif UNITY_2021_3_20 || UNITY_2021_3_21 || UNITY_2021_3_22 || UNITY_2021_3_23 || UNITY_2021_3_24 || UNITY_2021_3_25 || UNITY_2021_3_26 || UNITY_2021_3_27 || UNITY_2021_3_28 || UNITY_2021_3_29
|
||||||
|
#elif UNITY_2021_3_30 || UNITY_2021_3_31 || UNITY_2021_3_32 || UNITY_2021_3_33
|
||||||
|
#elif UNITY_2022_2_0 || UNITY_2022_2_1 || UNITY_2022_2_2 || UNITY_2022_2_3 || UNITY_2022_2_4 || UNITY_2022_2_5 || UNITY_2022_2_6 || UNITY_2022_2_7 || UNITY_2022_2_8 || UNITY_2022_2_9
|
||||||
|
#elif UNITY_2022_2_10 || UNITY_2022_2_11 || UNITY_2022_2_12 || UNITY_2022_2_13 || UNITY_2022_2_14
|
||||||
|
#elif UNITY_2021_3 || UNITY_2022_2 || UNITY_2022_3 || UNITY_2023_2_OR_NEWER
|
||||||
|
#define CANVAS_SUPPORT_ALWAYS_GAMMA
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Profiling;
|
||||||
|
#if UNITY_MODULE_VR
|
||||||
|
using UnityEngine.XR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
internal static class CanvasExtensions
|
||||||
|
{
|
||||||
|
public static bool ShouldGammaToLinearInShader(this Canvas canvas)
|
||||||
|
{
|
||||||
|
return QualitySettings.activeColorSpace == ColorSpace.Linear &&
|
||||||
|
#if CANVAS_SUPPORT_ALWAYS_GAMMA
|
||||||
|
canvas.vertexColorAlwaysGammaSpace;
|
||||||
|
#else
|
||||||
|
false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ShouldGammaToLinearInMesh(this Canvas canvas)
|
||||||
|
{
|
||||||
|
return QualitySettings.activeColorSpace == ColorSpace.Linear &&
|
||||||
|
#if CANVAS_SUPPORT_ALWAYS_GAMMA
|
||||||
|
!canvas.vertexColorAlwaysGammaSpace;
|
||||||
|
#else
|
||||||
|
true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsStereoCanvas(this Canvas canvas)
|
||||||
|
{
|
||||||
|
#if UNITY_MODULE_VR
|
||||||
|
if (FrameCache.TryGet<bool>(canvas, nameof(IsStereoCanvas), out var stereo)) return stereo;
|
||||||
|
|
||||||
|
stereo =
|
||||||
|
canvas != null && canvas.renderMode != RenderMode.ScreenSpaceOverlay && canvas.worldCamera != null
|
||||||
|
&& XRSettings.enabled && !string.IsNullOrEmpty(XRSettings.loadedDeviceName);
|
||||||
|
FrameCache.Set(canvas, nameof(IsStereoCanvas), stereo);
|
||||||
|
return stereo;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the view-projection matrix for a Canvas.
|
||||||
|
/// </summary>
|
||||||
|
public static void GetViewProjectionMatrix(this Canvas canvas, out Matrix4x4 vpMatrix)
|
||||||
|
{
|
||||||
|
canvas.GetViewProjectionMatrix(Camera.MonoOrStereoscopicEye.Mono, out vpMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the view-projection matrix for a Canvas.
|
||||||
|
/// </summary>
|
||||||
|
public static void GetViewProjectionMatrix(this Canvas canvas, Camera.MonoOrStereoscopicEye eye,
|
||||||
|
out Matrix4x4 vpMatrix)
|
||||||
|
{
|
||||||
|
if (FrameCache.TryGet(canvas, nameof(GetViewProjectionMatrix), out vpMatrix)) return;
|
||||||
|
|
||||||
|
canvas.GetViewProjectionMatrix(eye, out var viewMatrix, out var projectionMatrix);
|
||||||
|
vpMatrix = viewMatrix * projectionMatrix;
|
||||||
|
FrameCache.Set(canvas, nameof(GetViewProjectionMatrix), vpMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the view and projection matrices for a Canvas.
|
||||||
|
/// </summary>
|
||||||
|
public static void GetViewProjectionMatrix(this Canvas canvas, out Matrix4x4 vMatrix, out Matrix4x4 pMatrix)
|
||||||
|
{
|
||||||
|
canvas.GetViewProjectionMatrix(Camera.MonoOrStereoscopicEye.Mono, out vMatrix, out pMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the view and projection matrices for a Canvas.
|
||||||
|
/// </summary>
|
||||||
|
public static void GetViewProjectionMatrix(this Canvas canvas, Camera.MonoOrStereoscopicEye eye,
|
||||||
|
out Matrix4x4 vMatrix, out Matrix4x4 pMatrix)
|
||||||
|
{
|
||||||
|
if (FrameCache.TryGet(canvas, "GetViewMatrix", (int)eye, out vMatrix) &&
|
||||||
|
FrameCache.TryGet(canvas, "GetProjectionMatrix", (int)eye, out pMatrix))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get view and projection matrices.
|
||||||
|
Profiler.BeginSample("(COF)[CanvasExt] GetViewProjectionMatrix");
|
||||||
|
var rootCanvas = canvas.rootCanvas;
|
||||||
|
var cam = rootCanvas.worldCamera;
|
||||||
|
if (rootCanvas && rootCanvas.renderMode != RenderMode.ScreenSpaceOverlay && cam)
|
||||||
|
{
|
||||||
|
if (eye == Camera.MonoOrStereoscopicEye.Mono)
|
||||||
|
{
|
||||||
|
vMatrix = cam.worldToCameraMatrix;
|
||||||
|
pMatrix = GL.GetGPUProjectionMatrix(cam.projectionMatrix, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pMatrix = cam.GetStereoProjectionMatrix((Camera.StereoscopicEye)eye);
|
||||||
|
vMatrix = cam.GetStereoViewMatrix((Camera.StereoscopicEye)eye);
|
||||||
|
pMatrix = GL.GetGPUProjectionMatrix(pMatrix, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var pos = rootCanvas.transform.position;
|
||||||
|
vMatrix = Matrix4x4.TRS(
|
||||||
|
new Vector3(-pos.x, -pos.y, -1000),
|
||||||
|
Quaternion.identity,
|
||||||
|
new Vector3(1, 1, -1f));
|
||||||
|
pMatrix = Matrix4x4.TRS(
|
||||||
|
new Vector3(0, 0, -1),
|
||||||
|
Quaternion.identity,
|
||||||
|
new Vector3(1 / pos.x, 1 / pos.y, -2 / 10000f));
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameCache.Set(canvas, "GetViewMatrix", (int)eye, vMatrix);
|
||||||
|
FrameCache.Set(canvas, "GetProjectionMatrix", (int)eye, pMatrix);
|
||||||
|
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: b0beae5bb1cb142b9ab90dc0d371f026
|
guid: 9dd767b8c0f95478386e7d5079cd44df
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Profiling;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
internal static class Color32Extensions
|
||||||
|
{
|
||||||
|
private static readonly List<Color32> s_Colors = new List<Color32>();
|
||||||
|
private static byte[] s_LinearToGammaLut;
|
||||||
|
private static byte[] s_GammaToLinearLut;
|
||||||
|
|
||||||
|
public static byte LinearToGamma(this byte self)
|
||||||
|
{
|
||||||
|
if (s_LinearToGammaLut == null)
|
||||||
|
{
|
||||||
|
s_LinearToGammaLut = new byte[256];
|
||||||
|
for (var i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
s_LinearToGammaLut[i] = (byte)(Mathf.LinearToGammaSpace(i / 255f) * 255f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_LinearToGammaLut[self];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte GammaToLinear(this byte self)
|
||||||
|
{
|
||||||
|
if (s_GammaToLinearLut == null)
|
||||||
|
{
|
||||||
|
s_GammaToLinearLut = new byte[256];
|
||||||
|
for (var i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
s_GammaToLinearLut[i] = (byte)(Mathf.GammaToLinearSpace(i / 255f) * 255f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_GammaToLinearLut[self];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LinearToGamma(this Mesh self)
|
||||||
|
{
|
||||||
|
Profiler.BeginSample("(COF)[ColorExt] LinearToGamma (Mesh)");
|
||||||
|
self.GetColors(s_Colors);
|
||||||
|
var count = s_Colors.Count;
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var c = s_Colors[i];
|
||||||
|
c.r = c.r.LinearToGamma();
|
||||||
|
c.g = c.g.LinearToGamma();
|
||||||
|
c.b = c.b.LinearToGamma();
|
||||||
|
s_Colors[i] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.SetColors(s_Colors);
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GammaToLinear(this Mesh self)
|
||||||
|
{
|
||||||
|
Profiler.BeginSample("(COF)[ColorExt] GammaToLinear (Mesh)");
|
||||||
|
self.GetColors(s_Colors);
|
||||||
|
var count = s_Colors.Count;
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var c = s_Colors[i];
|
||||||
|
c.r = c.r.GammaToLinear();
|
||||||
|
c.g = c.g.GammaToLinear();
|
||||||
|
c.b = c.b.GammaToLinear();
|
||||||
|
s_Colors[i] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.SetColors(s_Colors);
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: d188d31b140094ebc84a9caafbc7ac71
|
guid: 0ef431b9df32c410ea5fa46be81def6b
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
198
Packages/src/Runtime/Internal/Extensions/ComponentExtensions.cs
Normal file
198
Packages/src/Runtime/Internal/Extensions/ComponentExtensions.cs
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Profiling;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for Component class.
|
||||||
|
/// </summary>
|
||||||
|
internal static class ComponentExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get components in children of a specific type in the hierarchy of a GameObject.
|
||||||
|
/// </summary>
|
||||||
|
public static T[] GetComponentsInChildren<T>(this Component self, int depth)
|
||||||
|
where T : Component
|
||||||
|
{
|
||||||
|
var results = ListPool<T>.Rent();
|
||||||
|
self.GetComponentsInChildren_Internal(results, depth);
|
||||||
|
var array = results.ToArray();
|
||||||
|
ListPool<T>.Return(ref results);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get components in children of a specific type in the hierarchy of a GameObject.
|
||||||
|
/// </summary>
|
||||||
|
public static void GetComponentsInChildren<T>(this Component self, List<T> results, int depth)
|
||||||
|
where T : Component
|
||||||
|
{
|
||||||
|
results.Clear();
|
||||||
|
self.GetComponentsInChildren_Internal(results, depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GetComponentsInChildren_Internal<T>(this Component self, List<T> results, int depth)
|
||||||
|
where T : Component
|
||||||
|
{
|
||||||
|
if (!self || results == null || depth < 0) return;
|
||||||
|
|
||||||
|
var tr = self.transform;
|
||||||
|
if (tr.TryGetComponent<T>(out var t))
|
||||||
|
{
|
||||||
|
results.Add(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (depth - 1 < 0) return;
|
||||||
|
var childCount = tr.childCount;
|
||||||
|
for (var i = 0; i < childCount; i++)
|
||||||
|
{
|
||||||
|
tr.GetChild(i).GetComponentsInChildren_Internal(results, depth - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get or add a component of a specific type to a GameObject.
|
||||||
|
/// </summary>
|
||||||
|
public static T GetOrAddComponent<T>(this Component self) where T : Component
|
||||||
|
{
|
||||||
|
if (!self) return null;
|
||||||
|
return self.TryGetComponent<T>(out var component)
|
||||||
|
? component
|
||||||
|
: self.gameObject.AddComponent<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the root component of a specific type in the hierarchy of a GameObject.
|
||||||
|
/// </summary>
|
||||||
|
public static T GetRootComponent<T>(this Component self) where T : Component
|
||||||
|
{
|
||||||
|
T component = null;
|
||||||
|
var transform = self.transform;
|
||||||
|
while (transform)
|
||||||
|
{
|
||||||
|
if (transform.TryGetComponent<T>(out var c))
|
||||||
|
{
|
||||||
|
component = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
transform = transform.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a component of a specific type in the parent hierarchy of a GameObject.
|
||||||
|
/// </summary>
|
||||||
|
public static T GetComponentInParent<T>(this Component self, bool includeSelf, Transform stopAfter,
|
||||||
|
Predicate<T> valid)
|
||||||
|
where T : Component
|
||||||
|
{
|
||||||
|
var tr = includeSelf ? self.transform : self.transform.parent;
|
||||||
|
while (tr)
|
||||||
|
{
|
||||||
|
if (tr.TryGetComponent<T>(out var c) && valid(c)) return c;
|
||||||
|
if (tr == stopAfter) return null;
|
||||||
|
tr = tr.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a component of a specific type to the children of a GameObject.
|
||||||
|
/// </summary>
|
||||||
|
public static void AddComponentOnChildren<T>(this Component self, HideFlags hideFlags, bool includeSelf)
|
||||||
|
where T : Component
|
||||||
|
{
|
||||||
|
if (self == null) return;
|
||||||
|
|
||||||
|
Profiler.BeginSample("(COF)[ComponentExt] AddComponentOnChildren > Self");
|
||||||
|
if (includeSelf && !self.TryGetComponent<T>(out _))
|
||||||
|
{
|
||||||
|
var c = self.gameObject.AddComponent<T>();
|
||||||
|
c.hideFlags = hideFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
var c = child.gameObject.AddComponent<T>();
|
||||||
|
c.hideFlags = hideFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !UNITY_2021_2_OR_NEWER && !UNITY_2020_3_45 && !UNITY_2020_3_46 && !UNITY_2020_3_47 && !UNITY_2020_3_48
|
||||||
|
public static T GetComponentInParent<T>(this Component self, bool includeInactive) where T : Component
|
||||||
|
{
|
||||||
|
if (!self) return null;
|
||||||
|
if (!includeInactive) return self.GetComponentInParent<T>();
|
||||||
|
|
||||||
|
var current = self.transform;
|
||||||
|
while (current)
|
||||||
|
{
|
||||||
|
if (current.TryGetComponent<T>(out var c)) return c;
|
||||||
|
current = current.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
/// <summary>
|
||||||
|
/// Verify whether it can be converted to the specified component.
|
||||||
|
/// </summary>
|
||||||
|
internal static bool CanConvertTo<T>(this Object context) where T : MonoBehaviour
|
||||||
|
{
|
||||||
|
return context && context.GetType() != typeof(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert to the specified component.
|
||||||
|
/// </summary>
|
||||||
|
internal static void ConvertTo<T>(this Object context) where T : MonoBehaviour
|
||||||
|
{
|
||||||
|
var target = context as MonoBehaviour;
|
||||||
|
if (target == null) return;
|
||||||
|
|
||||||
|
var so = new SerializedObject(target);
|
||||||
|
so.Update();
|
||||||
|
|
||||||
|
var oldEnable = target.enabled;
|
||||||
|
target.enabled = false;
|
||||||
|
|
||||||
|
// Find MonoScript of the specified component.
|
||||||
|
foreach (var script in Resources.FindObjectsOfTypeAll<MonoScript>())
|
||||||
|
{
|
||||||
|
if (script.GetClass() != typeof(T))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set 'm_Script' to convert.
|
||||||
|
so.FindProperty("m_Script").objectReferenceValue = script;
|
||||||
|
so.ApplyModifiedProperties();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (so.targetObject is MonoBehaviour mb)
|
||||||
|
{
|
||||||
|
mb.enabled = oldEnable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8455ee485a5ee4cacbdf558f66af65fb
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
19
Packages/src/Runtime/Internal/Extensions/ListExtensions.cs
Normal file
19
Packages/src/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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 833553390099d40c9b212823f0852c46
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
48
Packages/src/Runtime/Internal/Extensions/Misc.cs
Normal file
48
Packages/src/Runtime/Internal/Extensions/Misc.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
internal static class Misc
|
||||||
|
{
|
||||||
|
public static void Destroy(Object obj)
|
||||||
|
{
|
||||||
|
if (!obj) return;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (!Application.isPlaying)
|
||||||
|
{
|
||||||
|
Object.DestroyImmediate(obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
Object.Destroy(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DestroyImmediate(Object obj)
|
||||||
|
{
|
||||||
|
if (!obj) return;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (Application.isEditor)
|
||||||
|
{
|
||||||
|
Object.DestroyImmediate(obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
Object.Destroy(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Conditional("UNITY_EDITOR")]
|
||||||
|
public static void SetDirty(Object obj)
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (!obj) return;
|
||||||
|
EditorUtility.SetDirty(obj);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Packages/src/Runtime/Internal/Extensions/Misc.cs.meta
Normal file
11
Packages/src/Runtime/Internal/Extensions/Misc.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 39ed6a6b0a72e482488bd298b2ae762e
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
58
Packages/src/Runtime/Internal/Extensions/SpriteExtensions.cs
Normal file
58
Packages/src/Runtime/Internal/Extensions/SpriteExtensions.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.U2D;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
using System.Reflection;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for Sprite class.
|
||||||
|
/// </summary>
|
||||||
|
internal static class SpriteExtensions
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
private static readonly Type s_SpriteEditorExtensionType =
|
||||||
|
Type.GetType("UnityEditor.Experimental.U2D.SpriteEditorExtension, UnityEditor")
|
||||||
|
?? Type.GetType("UnityEditor.U2D.SpriteEditorExtension, UnityEditor");
|
||||||
|
|
||||||
|
private static readonly MethodInfo s_GetActiveAtlasTextureMethod = s_SpriteEditorExtensionType
|
||||||
|
.GetMethod("GetActiveAtlasTexture", BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
private static readonly MethodInfo s_GetActiveAtlasMethod = s_SpriteEditorExtensionType
|
||||||
|
.GetMethod("GetActiveAtlas", BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the actual texture of a sprite in play mode or edit mode.
|
||||||
|
/// </summary>
|
||||||
|
public static Texture2D GetActualTexture(this Sprite self)
|
||||||
|
{
|
||||||
|
if (!self) return null;
|
||||||
|
|
||||||
|
if (Application.isPlaying) return self.texture;
|
||||||
|
|
||||||
|
var ret = s_GetActiveAtlasTextureMethod.Invoke(null, new object[] { self }) as Texture2D;
|
||||||
|
return ret ? ret : self.texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the active sprite atlas of a sprite in play mode or edit mode.
|
||||||
|
/// </summary>
|
||||||
|
public static SpriteAtlas GetActiveAtlas(this Sprite self)
|
||||||
|
{
|
||||||
|
if (!self) return null;
|
||||||
|
|
||||||
|
return s_GetActiveAtlasMethod.Invoke(null, new object[] { self }) as SpriteAtlas;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/// <summary>
|
||||||
|
/// Get the actual texture of a sprite in play mode.
|
||||||
|
/// </summary>
|
||||||
|
internal static Texture2D GetActualTexture(this Sprite self)
|
||||||
|
{
|
||||||
|
return self ? self.texture : null;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a7a2e11131111447cb7fc0394a14da65
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
internal static class Vector3Extensions
|
||||||
|
{
|
||||||
|
public static Vector3 Inverse(this Vector3 self)
|
||||||
|
{
|
||||||
|
self.x = Mathf.Approximately(self.x, 0) ? 1 : 1 / self.x;
|
||||||
|
self.y = Mathf.Approximately(self.y, 0) ? 1 : 1 / self.y;
|
||||||
|
self.z = Mathf.Approximately(self.z, 0) ? 1 : 1 / self.z;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 GetScaled(this Vector3 self, Vector3 other1)
|
||||||
|
{
|
||||||
|
self.Scale(other1);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 GetScaled(this Vector3 self, Vector3 other1, Vector3 other2)
|
||||||
|
{
|
||||||
|
self.Scale(other1);
|
||||||
|
self.Scale(other2);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 GetScaled(this Vector3 self, Vector3 other1, Vector3 other2, Vector3 other3)
|
||||||
|
{
|
||||||
|
self.Scale(other1);
|
||||||
|
self.Scale(other2);
|
||||||
|
self.Scale(other3);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsVisible(this Vector3 self)
|
||||||
|
{
|
||||||
|
return 0 < Mathf.Abs(self.x * self.y * self.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsVisible2D(this Vector3 self)
|
||||||
|
{
|
||||||
|
return 0 < Mathf.Abs(self.x * self.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6a7b5fb989e4b48c8bc7ecce834060f5
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Packages/src/Runtime/Internal/ProjectSettings.meta
Normal file
8
Packages/src/Runtime/Internal/ProjectSettings.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 398e06c9985ad4291a95f0749c2927fb
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,219 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEngine;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Build;
|
||||||
|
using UnityEditor.Build.Reporting;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
public abstract class PreloadedProjectSettings : ScriptableObject
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
{
|
||||||
|
private class PreprocessBuildWithReport : IPreprocessBuildWithReport
|
||||||
|
{
|
||||||
|
int IOrderedCallback.callbackOrder => 0;
|
||||||
|
|
||||||
|
void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report)
|
||||||
|
{
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[InitializeOnLoadMethod]
|
||||||
|
[InitializeOnEnterPlayMode]
|
||||||
|
private static void Initialize()
|
||||||
|
{
|
||||||
|
const BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
|
||||||
|
foreach (var t in TypeCache.GetTypesDerivedFrom(typeof(PreloadedProjectSettings<>)))
|
||||||
|
{
|
||||||
|
var defaultSettings = GetDefaultSettings(t);
|
||||||
|
if (!defaultSettings)
|
||||||
|
{
|
||||||
|
defaultSettings = t.GetProperty("instance", flags)
|
||||||
|
?.GetValue(null, null) as PreloadedProjectSettings;
|
||||||
|
SetDefaultSettings(defaultSettings);
|
||||||
|
}
|
||||||
|
else if (GetPreloadedSettings(t).Length != 1)
|
||||||
|
{
|
||||||
|
SetDefaultSettings(defaultSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorApplication.QueuePlayerLoopUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static string GetDefaultName(Type type, bool nicify)
|
||||||
|
{
|
||||||
|
var typeName = type.Name.Replace("ProjectSettings", "");
|
||||||
|
return nicify
|
||||||
|
? ObjectNames.NicifyVariableName(typeName)
|
||||||
|
: typeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object[] GetPreloadedSettings(Type type)
|
||||||
|
{
|
||||||
|
return PlayerSettings.GetPreloadedAssets()
|
||||||
|
.Where(x => x && x.GetType() == type)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static PreloadedProjectSettings GetDefaultSettings(Type type)
|
||||||
|
{
|
||||||
|
return GetPreloadedSettings(type).FirstOrDefault() as PreloadedProjectSettings
|
||||||
|
?? AssetDatabase.FindAssets($"t:{nameof(PreloadedProjectSettings)}")
|
||||||
|
.Select(AssetDatabase.GUIDToAssetPath)
|
||||||
|
.Select(AssetDatabase.LoadAssetAtPath<PreloadedProjectSettings>)
|
||||||
|
.FirstOrDefault(x => x && x.GetType() == type);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void SetDefaultSettings(PreloadedProjectSettings asset)
|
||||||
|
{
|
||||||
|
var type = asset.GetType();
|
||||||
|
if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(asset)))
|
||||||
|
{
|
||||||
|
if (!AssetDatabase.IsValidFolder("Assets/ProjectSettings"))
|
||||||
|
{
|
||||||
|
AssetDatabase.CreateFolder("Assets", "ProjectSettings");
|
||||||
|
}
|
||||||
|
|
||||||
|
var assetPath = $"Assets/ProjectSettings/{GetDefaultName(type, false)}.asset";
|
||||||
|
assetPath = AssetDatabase.GenerateUniqueAssetPath(assetPath);
|
||||||
|
AssetDatabase.CreateAsset(asset, assetPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
var preloadedAssets = PlayerSettings.GetPreloadedAssets();
|
||||||
|
var projectSettings = GetPreloadedSettings(type);
|
||||||
|
PlayerSettings.SetPreloadedAssets(preloadedAssets
|
||||||
|
.Where(x => x)
|
||||||
|
.Except(projectSettings.Except(new[] { asset }))
|
||||||
|
.Append(asset)
|
||||||
|
.Distinct()
|
||||||
|
.ToArray());
|
||||||
|
|
||||||
|
AssetDatabase.Refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class PreloadedProjectSettings<T> : PreloadedProjectSettings
|
||||||
|
where T : PreloadedProjectSettings<T>
|
||||||
|
{
|
||||||
|
private static T s_Instance;
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
private string _jsonText;
|
||||||
|
|
||||||
|
public static T instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (s_Instance) return s_Instance;
|
||||||
|
|
||||||
|
s_Instance = GetDefaultSettings(typeof(T)) as T;
|
||||||
|
if (s_Instance) return s_Instance;
|
||||||
|
|
||||||
|
s_Instance = CreateInstance<T>();
|
||||||
|
if (!s_Instance)
|
||||||
|
{
|
||||||
|
s_Instance = null;
|
||||||
|
return s_Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetDefaultSettings(s_Instance);
|
||||||
|
return s_Instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPlayModeStateChanged(PlayModeStateChange state)
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case PlayModeStateChange.ExitingEditMode:
|
||||||
|
_jsonText = EditorJsonUtility.ToJson(this);
|
||||||
|
break;
|
||||||
|
case PlayModeStateChange.ExitingPlayMode:
|
||||||
|
if (_jsonText != null)
|
||||||
|
{
|
||||||
|
EditorJsonUtility.FromJsonOverwrite(_jsonText, this);
|
||||||
|
_jsonText = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
public static T instance => s_Instance ? s_Instance : s_Instance = CreateInstance<T>();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This function is called when the object becomes enabled and active.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnEnable()
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
var isDefaultSettings = !s_Instance || s_Instance == this || GetDefaultSettings(typeof(T)) == this;
|
||||||
|
if (!isDefaultSettings)
|
||||||
|
{
|
||||||
|
DestroyImmediate(this, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (s_Instance) return;
|
||||||
|
s_Instance = this as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This function is called when the behaviour becomes disabled.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnDisable()
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
|
||||||
|
#endif
|
||||||
|
if (s_Instance != this) return;
|
||||||
|
|
||||||
|
s_Instance = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
protected sealed class PreloadedProjectSettingsProvider : SettingsProvider
|
||||||
|
{
|
||||||
|
private Editor _editor;
|
||||||
|
private PreloadedProjectSettings<T> _target;
|
||||||
|
|
||||||
|
public PreloadedProjectSettingsProvider(string path) : base(path, SettingsScope.Project)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnGUI(string searchContext)
|
||||||
|
{
|
||||||
|
if (!_target)
|
||||||
|
{
|
||||||
|
if (_editor)
|
||||||
|
{
|
||||||
|
DestroyImmediate(_editor);
|
||||||
|
_editor = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_target = instance;
|
||||||
|
_editor = Editor.CreateEditor(_target);
|
||||||
|
}
|
||||||
|
|
||||||
|
_editor.OnInspectorGUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 790ea008741dc411497c8794745319eb
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Packages/src/Runtime/Internal/Utilities.meta
Normal file
8
Packages/src/Runtime/Internal/Utilities.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1b2877595f27c4a70a426991d515434f
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
88
Packages/src/Runtime/Internal/Utilities/FastAction.cs
Executable file
88
Packages/src/Runtime/Internal/Utilities/FastAction.cs
Executable file
@@ -0,0 +1,88 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Profiling;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for a fast action.
|
||||||
|
/// </summary>
|
||||||
|
internal class FastActionBase<T>
|
||||||
|
{
|
||||||
|
private static readonly ObjectPool<LinkedListNode<T>> s_NodePool =
|
||||||
|
new ObjectPool<LinkedListNode<T>>(() => new LinkedListNode<T>(default), _ => true, x => x.Value = default);
|
||||||
|
|
||||||
|
private readonly LinkedList<T> _delegates = new LinkedList<T>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a delegate to the action.
|
||||||
|
/// </summary>
|
||||||
|
public void Add(T rhs)
|
||||||
|
{
|
||||||
|
if (rhs == null) return;
|
||||||
|
Profiler.BeginSample("(COF)[FastAction] Add Action");
|
||||||
|
var node = s_NodePool.Rent();
|
||||||
|
node.Value = rhs;
|
||||||
|
_delegates.AddLast(node);
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a delegate from the action.
|
||||||
|
/// </summary>
|
||||||
|
public void Remove(T rhs)
|
||||||
|
{
|
||||||
|
if (rhs == null) return;
|
||||||
|
Profiler.BeginSample("(COF)[FastAction] Remove Action");
|
||||||
|
var node = _delegates.Find(rhs);
|
||||||
|
if (node != null)
|
||||||
|
{
|
||||||
|
_delegates.Remove(node);
|
||||||
|
s_NodePool.Return(ref node);
|
||||||
|
}
|
||||||
|
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the action with a callback function.
|
||||||
|
/// </summary>
|
||||||
|
protected void Invoke(Action<T> callback)
|
||||||
|
{
|
||||||
|
var node = _delegates.First;
|
||||||
|
while (node != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
callback(node.Value);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.LogException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
node = node.Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_delegates.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A fast action without parameters.
|
||||||
|
/// </summary>
|
||||||
|
internal class FastAction : FastActionBase<Action>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invoke all the registered delegates.
|
||||||
|
/// </summary>
|
||||||
|
public void Invoke()
|
||||||
|
{
|
||||||
|
Invoke(action => action.Invoke());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Packages/src/Runtime/Internal/Utilities/FastAction.cs.meta
Normal file
11
Packages/src/Runtime/Internal/Utilities/FastAction.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a7c8c268a827b4787a8e050f1fe95ad5
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
102
Packages/src/Runtime/Internal/Utilities/FrameCache.cs
Normal file
102
Packages/src/Runtime/Internal/Utilities/FrameCache.cs
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
internal static class FrameCache
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<Type, IFrameCache> s_Caches = new Dictionary<Type, IFrameCache>();
|
||||||
|
|
||||||
|
static FrameCache()
|
||||||
|
{
|
||||||
|
s_Caches.Clear();
|
||||||
|
UIExtraCallbacks.onLateAfterCanvasRebuild += ClearAllCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
|
private static void Clear()
|
||||||
|
{
|
||||||
|
s_Caches.Clear();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to retrieve a value from the frame cache with a specified key.
|
||||||
|
/// </summary>
|
||||||
|
public static bool TryGet<T>(object key1, string key2, out T result)
|
||||||
|
{
|
||||||
|
return GetFrameCache<T>().TryGet((key1.GetHashCode(), key2.GetHashCode()), out result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to retrieve a value from the frame cache with a specified key.
|
||||||
|
/// </summary>
|
||||||
|
public static bool TryGet<T>(object key1, string key2, int key3, out T result)
|
||||||
|
{
|
||||||
|
return GetFrameCache<T>().TryGet((key1.GetHashCode(), key2.GetHashCode() + key3), out result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets a value in the frame cache with a specified key.
|
||||||
|
/// </summary>
|
||||||
|
public static void Set<T>(object key1, string key2, T result)
|
||||||
|
{
|
||||||
|
GetFrameCache<T>().Set((key1.GetHashCode(), key2.GetHashCode()), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets a value in the frame cache with a specified key.
|
||||||
|
/// </summary>
|
||||||
|
public static void Set<T>(object key1, string key2, int key3, T result)
|
||||||
|
{
|
||||||
|
GetFrameCache<T>().Set((key1.GetHashCode(), key2.GetHashCode() + key3), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ClearAllCache()
|
||||||
|
{
|
||||||
|
foreach (var cache in s_Caches.Values)
|
||||||
|
{
|
||||||
|
cache.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FrameCacheContainer<T> GetFrameCache<T>()
|
||||||
|
{
|
||||||
|
var t = typeof(T);
|
||||||
|
if (s_Caches.TryGetValue(t, out var frameCache)) return frameCache as FrameCacheContainer<T>;
|
||||||
|
|
||||||
|
frameCache = new FrameCacheContainer<T>();
|
||||||
|
s_Caches.Add(t, frameCache);
|
||||||
|
|
||||||
|
return (FrameCacheContainer<T>)frameCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface IFrameCache
|
||||||
|
{
|
||||||
|
void Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FrameCacheContainer<T> : IFrameCache
|
||||||
|
{
|
||||||
|
private readonly Dictionary<(int, int), T> _caches = new Dictionary<(int, int), T>();
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_caches.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGet((int, int) key, out T result)
|
||||||
|
{
|
||||||
|
return _caches.TryGetValue(key, out result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set((int, int) key, T result)
|
||||||
|
{
|
||||||
|
_caches[key] = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Packages/src/Runtime/Internal/Utilities/FrameCache.cs.meta
Normal file
11
Packages/src/Runtime/Internal/Utilities/FrameCache.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5f129e3b07ffb4d3bbb4cc5f6bd94087
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
262
Packages/src/Runtime/Internal/Utilities/Logging.cs
Normal file
262
Packages/src/Runtime/Internal/Utilities/Logging.cs
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
#if ENABLE_COFFEE_LOGGER
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
#else
|
||||||
|
using Conditional = System.Diagnostics.ConditionalAttribute;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
internal static class Logging
|
||||||
|
{
|
||||||
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
|
private const string k_DisableSymbol = "DISABLE_COFFEE_LOGGER";
|
||||||
|
|
||||||
|
[Conditional(k_DisableSymbol)]
|
||||||
|
#endif
|
||||||
|
private static void Log_Internal(LogType type, object tag, object message, Object context)
|
||||||
|
{
|
||||||
|
#if ENABLE_COFFEE_LOGGER
|
||||||
|
AppendTag(s_Sb, tag);
|
||||||
|
s_Sb.Append(message);
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case LogType.Error:
|
||||||
|
case LogType.Assert:
|
||||||
|
case LogType.Exception:
|
||||||
|
Debug.LogError(s_Sb, context);
|
||||||
|
break;
|
||||||
|
case LogType.Warning:
|
||||||
|
Debug.LogWarning(s_Sb, context);
|
||||||
|
break;
|
||||||
|
case LogType.Log:
|
||||||
|
Debug.Log(s_Sb, context);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_Sb.Length = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
|
[Conditional(k_DisableSymbol)]
|
||||||
|
#endif
|
||||||
|
public static void LogIf(bool enable, object tag, object message, Object context = null)
|
||||||
|
{
|
||||||
|
if (!enable) return;
|
||||||
|
Log_Internal(LogType.Log, tag, message, context ? context : tag as Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
|
[Conditional(k_DisableSymbol)]
|
||||||
|
#endif
|
||||||
|
public static void Log(object tag, object message, Object context = null)
|
||||||
|
{
|
||||||
|
Log_Internal(LogType.Log, tag, message, context ? context : tag as Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
|
[Conditional(k_DisableSymbol)]
|
||||||
|
#endif
|
||||||
|
public static void LogWarning(object tag, object message, Object context = null)
|
||||||
|
{
|
||||||
|
Log_Internal(LogType.Warning, tag, message, context ? context : tag as Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogError(object tag, object message, Object context = null)
|
||||||
|
{
|
||||||
|
#if ENABLE_COFFEE_LOGGER
|
||||||
|
Log_Internal(LogType.Error, tag, message, context ? context : tag as Object);
|
||||||
|
#else
|
||||||
|
Debug.LogError($"{tag}: {message}", context);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
|
[Conditional(k_DisableSymbol)]
|
||||||
|
#endif
|
||||||
|
public static void LogMulticast(Type type, string fieldName, object instance = null, string message = null)
|
||||||
|
{
|
||||||
|
#if ENABLE_COFFEE_LOGGER
|
||||||
|
AppendTag(s_Sb, instance ?? type);
|
||||||
|
|
||||||
|
var handler = type
|
||||||
|
.GetField(fieldName,
|
||||||
|
BindingFlags.Static | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic)
|
||||||
|
?.GetValue(instance);
|
||||||
|
|
||||||
|
var list = ((MulticastDelegate)handler)?.GetInvocationList() ?? Array.Empty<Delegate>();
|
||||||
|
s_Sb.Append("<color=orange>");
|
||||||
|
s_Sb.Append(type.Name);
|
||||||
|
s_Sb.Append(".");
|
||||||
|
s_Sb.Append(fieldName);
|
||||||
|
s_Sb.Append(" has ");
|
||||||
|
s_Sb.Append(list.Length);
|
||||||
|
s_Sb.Append(" callbacks");
|
||||||
|
if (message != null)
|
||||||
|
{
|
||||||
|
s_Sb.Append(" (");
|
||||||
|
s_Sb.Append(message);
|
||||||
|
s_Sb.Append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
s_Sb.Append(":</color>");
|
||||||
|
|
||||||
|
for (var i = 0; i < list.Length; i++)
|
||||||
|
{
|
||||||
|
s_Sb.Append("\n - ");
|
||||||
|
s_Sb.Append(list[i].Method.DeclaringType?.Name);
|
||||||
|
s_Sb.Append(".");
|
||||||
|
s_Sb.Append(list[i].Method.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log(s_Sb);
|
||||||
|
s_Sb.Length = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
|
[Conditional(k_DisableSymbol)]
|
||||||
|
#endif
|
||||||
|
private static void AppendTag(StringBuilder sb, object tag)
|
||||||
|
{
|
||||||
|
#if ENABLE_COFFEE_LOGGER
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sb.Append("f");
|
||||||
|
sb.Append(Time.frameCount);
|
||||||
|
sb.Append(":<color=#");
|
||||||
|
AppendReadableCode(sb, tag);
|
||||||
|
sb.Append("><b>[");
|
||||||
|
|
||||||
|
switch (tag)
|
||||||
|
{
|
||||||
|
case string name:
|
||||||
|
sb.Append(name);
|
||||||
|
break;
|
||||||
|
case Type type:
|
||||||
|
AppendType(sb, type);
|
||||||
|
break;
|
||||||
|
case Object uObject:
|
||||||
|
AppendType(sb, tag.GetType());
|
||||||
|
sb.Append(" #");
|
||||||
|
sb.Append(uObject.name);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
AppendType(sb, tag.GetType());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append("]</b></color> ");
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
sb.Append("f");
|
||||||
|
sb.Append(Time.frameCount);
|
||||||
|
sb.Append(":<b>[");
|
||||||
|
sb.Append(tag);
|
||||||
|
sb.Append("]</b> ");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
|
[Conditional(k_DisableSymbol)]
|
||||||
|
#endif
|
||||||
|
private static void AppendType(StringBuilder sb, Type type)
|
||||||
|
{
|
||||||
|
#if ENABLE_COFFEE_LOGGER
|
||||||
|
if (s_TypeNameCache.TryGetValue(type, out var name))
|
||||||
|
{
|
||||||
|
sb.Append(name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// New type found
|
||||||
|
var start = sb.Length;
|
||||||
|
if (0 < start && sb[start - 1] == '<' && (type.Name == "Material" || type.Name == "Color"))
|
||||||
|
{
|
||||||
|
sb.Append('@');
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append(type.Name);
|
||||||
|
if (type.IsGenericType)
|
||||||
|
{
|
||||||
|
sb.Length -= 2;
|
||||||
|
sb.Append("<");
|
||||||
|
foreach (var gType in type.GetGenericArguments())
|
||||||
|
{
|
||||||
|
AppendType(sb, gType);
|
||||||
|
sb.Append(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Length -= 2;
|
||||||
|
sb.Append(">");
|
||||||
|
}
|
||||||
|
|
||||||
|
s_TypeNameCache.Add(type, sb.ToString(start, sb.Length - start));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
|
[Conditional(k_DisableSymbol)]
|
||||||
|
#endif
|
||||||
|
private static void AppendReadableCode(StringBuilder sb, object tag)
|
||||||
|
{
|
||||||
|
#if ENABLE_COFFEE_LOGGER
|
||||||
|
int hash;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch (tag)
|
||||||
|
{
|
||||||
|
case string text:
|
||||||
|
hash = text.GetHashCode();
|
||||||
|
break;
|
||||||
|
case Type type:
|
||||||
|
type = type.IsGenericType ? type.GetGenericTypeDefinition() : type;
|
||||||
|
hash = type.FullName?.GetHashCode() ?? 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
hash = tag.GetType().FullName?.GetHashCode() ?? 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
sb.Append("FFFFFF");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash = hash & (s_Codes.Length - 1);
|
||||||
|
if (s_Codes[hash] == null)
|
||||||
|
{
|
||||||
|
var hue = hash / (float)s_Codes.Length;
|
||||||
|
var modifier = 1f - Mathf.Clamp01(Mathf.Abs(hue - 0.65f) / 0.2f);
|
||||||
|
var saturation = 0.7f + modifier * -0.2f;
|
||||||
|
var value = 0.8f + modifier * 0.3f;
|
||||||
|
s_Codes[hash] = ColorUtility.ToHtmlStringRGB(Color.HSVToRGB(hue, saturation, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append(s_Codes[hash]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_COFFEE_LOGGER
|
||||||
|
private static readonly StringBuilder s_Sb = new StringBuilder();
|
||||||
|
private static readonly string[] s_Codes = new string[64];
|
||||||
|
private static readonly Dictionary<Type, string> s_TypeNameCache = new Dictionary<Type, string>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Packages/src/Runtime/Internal/Utilities/Logging.cs.meta
Normal file
11
Packages/src/Runtime/Internal/Utilities/Logging.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8255313895da84e7cbdc876be3795334
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Profiling;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides functionality to manage materials.
|
||||||
|
/// </summary>
|
||||||
|
internal static class MaterialRepository
|
||||||
|
{
|
||||||
|
private static readonly ObjectRepository<Material> s_Repository = new ObjectRepository<Material>();
|
||||||
|
|
||||||
|
public static int count => s_Repository.count;
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
|
private static void Clear()
|
||||||
|
{
|
||||||
|
s_Repository.Clear();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a cached material based on the hash.
|
||||||
|
/// </summary>
|
||||||
|
public static bool Valid(Hash128 hash, Material material)
|
||||||
|
{
|
||||||
|
Profiler.BeginSample("(COF)[MaterialRegistry] Valid");
|
||||||
|
var ret = s_Repository.Valid(hash, material);
|
||||||
|
Profiler.EndSample();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds or retrieves a cached material based on the hash.
|
||||||
|
/// </summary>
|
||||||
|
public static void Get(Hash128 hash, ref Material material, Func<Material> onCreate)
|
||||||
|
{
|
||||||
|
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
||||||
|
s_Repository.Get(hash, ref material, onCreate);
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds or retrieves a cached material based on the hash.
|
||||||
|
/// </summary>
|
||||||
|
public static void Get(Hash128 hash, ref Material material, string shaderName)
|
||||||
|
{
|
||||||
|
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
||||||
|
s_Repository.Get(hash, ref material, x => new Material(Shader.Find(x))
|
||||||
|
{
|
||||||
|
hideFlags = HideFlags.DontSave | HideFlags.NotEditable
|
||||||
|
}, shaderName);
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds or retrieves a cached material based on the hash.
|
||||||
|
/// </summary>
|
||||||
|
public static void Get(Hash128 hash, ref Material material, string shaderName, string[] keywords)
|
||||||
|
{
|
||||||
|
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
||||||
|
s_Repository.Get(hash, ref material, x => new Material(Shader.Find(x.shaderName))
|
||||||
|
{
|
||||||
|
hideFlags = HideFlags.DontSave | HideFlags.NotEditable,
|
||||||
|
shaderKeywords = x.keywords
|
||||||
|
}, (shaderName, keywords));
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds or retrieves a cached material based on the hash.
|
||||||
|
/// </summary>
|
||||||
|
public static void Get<T>(Hash128 hash, ref Material material, Func<T, Material> onCreate, T source)
|
||||||
|
{
|
||||||
|
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
||||||
|
s_Repository.Get(hash, ref material, onCreate, source);
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a soft mask material from the cache.
|
||||||
|
/// </summary>
|
||||||
|
public static void Release(ref Material material)
|
||||||
|
{
|
||||||
|
Profiler.BeginSample("(COF)[MaterialRepository] Release");
|
||||||
|
s_Repository.Release(ref material);
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 702912f2ee2ec49bb8003a64151ae4f7
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
85
Packages/src/Runtime/Internal/Utilities/ObjectPool.cs
Normal file
85
Packages/src/Runtime/Internal/Utilities/ObjectPool.cs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Object pool.
|
||||||
|
/// </summary>
|
||||||
|
internal class ObjectPool<T>
|
||||||
|
{
|
||||||
|
private readonly Func<T> _onCreate; // Delegate for creating instances
|
||||||
|
private readonly Action<T> _onReturn; // Delegate for returning instances to the pool
|
||||||
|
private readonly Predicate<T> _onValid; // Delegate for checking if instances are valid
|
||||||
|
private readonly Stack<T> _pool = new Stack<T>(32); // Object pool
|
||||||
|
private int _count; // Total count of created instances
|
||||||
|
|
||||||
|
public ObjectPool(Func<T> onCreate, Predicate<T> onValid, Action<T> onReturn)
|
||||||
|
{
|
||||||
|
_onCreate = onCreate;
|
||||||
|
_onValid = onValid;
|
||||||
|
_onReturn = onReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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.Count)
|
||||||
|
{
|
||||||
|
var instance = _pool.Pop();
|
||||||
|
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.Count}, created: {++_count}).");
|
||||||
|
return _onCreate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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 || _pool.Contains(instance)) return; // Ignore if already pooled or null.
|
||||||
|
|
||||||
|
_onReturn(instance); // Return the instance to the pool.
|
||||||
|
_pool.Push(instance);
|
||||||
|
Logging.Log(this, $"An instance is released (pooled: {_pool.Count}, created: {_count}).");
|
||||||
|
instance = default; // Set the reference to null.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Object pool for <see cref="List{T}" />.
|
||||||
|
/// </summary>
|
||||||
|
internal static class ListPool<T>
|
||||||
|
{
|
||||||
|
private static readonly ObjectPool<List<T>> s_ListPool =
|
||||||
|
new ObjectPool<List<T>>(() => new List<T>(), _ => true, x => x.Clear());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rent an instance from the pool.
|
||||||
|
/// When you no longer need it, return it with <see cref="Return" />.
|
||||||
|
/// </summary>
|
||||||
|
public static List<T> Rent()
|
||||||
|
{
|
||||||
|
return s_ListPool.Rent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
s_ListPool.Return(ref toRelease);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Packages/src/Runtime/Internal/Utilities/ObjectPool.cs.meta
Normal file
11
Packages/src/Runtime/Internal/Utilities/ObjectPool.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 632cb1ba34e6a4e80b55a32bb63ca369
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
209
Packages/src/Runtime/Internal/Utilities/ObjectRepository.cs
Normal file
209
Packages/src/Runtime/Internal/Utilities/ObjectRepository.cs
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Profiling;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
internal class ObjectRepository<T> where T : Object
|
||||||
|
{
|
||||||
|
private readonly Dictionary<Hash128, Entry> _cache = new Dictionary<Hash128, Entry>(8);
|
||||||
|
private readonly Dictionary<int, Hash128> _objectKey = new Dictionary<int, Hash128>(8);
|
||||||
|
private readonly string _name;
|
||||||
|
private readonly Action<T> _onRelease;
|
||||||
|
private readonly Stack<Entry> _pool = new Stack<Entry>(8);
|
||||||
|
|
||||||
|
public ObjectRepository(Action<T> onRelease = null)
|
||||||
|
{
|
||||||
|
_name = $"{typeof(T).Name}Repository";
|
||||||
|
if (onRelease == null)
|
||||||
|
{
|
||||||
|
_onRelease = x =>
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (!Application.isPlaying)
|
||||||
|
{
|
||||||
|
Object.DestroyImmediate(x, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
Object.Destroy(x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_onRelease = onRelease;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
_pool.Push(new Entry());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int count => _cache.Count;
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
foreach (var kv in _cache)
|
||||||
|
{
|
||||||
|
var entry = kv.Value;
|
||||||
|
if (entry == null) continue;
|
||||||
|
|
||||||
|
entry.Release(_onRelease);
|
||||||
|
_pool.Push(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
_cache.Clear();
|
||||||
|
_objectKey.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Valid(Hash128 hash, T obj)
|
||||||
|
{
|
||||||
|
return _cache.TryGetValue(hash, out var entry) && entry.storedObject == obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds or retrieves a cached object based on the hash.
|
||||||
|
/// </summary>
|
||||||
|
public void Get(Hash128 hash, ref T obj, Func<T> onCreate)
|
||||||
|
{
|
||||||
|
if (GetFromCache(hash, ref obj)) return;
|
||||||
|
Add(hash, ref obj, onCreate());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds or retrieves a cached object based on the hash.
|
||||||
|
/// </summary>
|
||||||
|
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.
|
||||||
|
Profiler.BeginSample("(COF)[ObjectRepository] GetFromCache");
|
||||||
|
if (_cache.TryGetValue(hash, out var entry))
|
||||||
|
{
|
||||||
|
if (!entry.storedObject)
|
||||||
|
{
|
||||||
|
Release(ref entry.storedObject);
|
||||||
|
Profiler.EndSample();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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(total#{count}): {entry}");
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and add a new entry.
|
||||||
|
Profiler.BeginSample("(COF)[ObjectRepository] Add");
|
||||||
|
var newEntry = 0 < _pool.Count ? _pool.Pop() : new Entry();
|
||||||
|
newEntry.storedObject = newObject;
|
||||||
|
newEntry.hash = hash;
|
||||||
|
newEntry.reference = 1;
|
||||||
|
_cache[hash] = newEntry;
|
||||||
|
_objectKey[newObject.GetInstanceID()] = hash;
|
||||||
|
Logging.Log(_name, $"<color=#03c700>Add</color>(total#{count}): {newEntry}");
|
||||||
|
Release(ref obj);
|
||||||
|
obj = newObject;
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Release a object.
|
||||||
|
/// </summary>
|
||||||
|
public void Release(ref T obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(obj, null)) return;
|
||||||
|
|
||||||
|
// Find and release the entry.
|
||||||
|
Profiler.BeginSample("(COF)[ObjectRepository] Release");
|
||||||
|
var id = obj.GetInstanceID();
|
||||||
|
if (_objectKey.TryGetValue(id, out var hash)
|
||||||
|
&& _cache.TryGetValue(hash, out var entry))
|
||||||
|
{
|
||||||
|
entry.reference--;
|
||||||
|
if (entry.reference <= 0 || !entry.storedObject)
|
||||||
|
{
|
||||||
|
Remove(entry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Log(_name, $"Release(total#{_cache.Count}): {entry}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Log(_name, $"Release(total#{_cache.Count}): <color=red>Already released: {obj}</color>");
|
||||||
|
}
|
||||||
|
|
||||||
|
obj = null;
|
||||||
|
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
|
||||||
|
{
|
||||||
|
public Hash128 hash;
|
||||||
|
public int reference;
|
||||||
|
public T storedObject;
|
||||||
|
|
||||||
|
public void Release(Action<T> onRelease)
|
||||||
|
{
|
||||||
|
reference = 0;
|
||||||
|
if (storedObject)
|
||||||
|
{
|
||||||
|
onRelease?.Invoke(storedObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
storedObject = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"h{(uint)hash.GetHashCode()} (refs#{reference}), {storedObject}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a713d67bdb31e45e296e5f18460717e2
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
93
Packages/src/Runtime/Internal/Utilities/UIExtraCallbacks.cs
Executable file
93
Packages/src/Runtime/Internal/Utilities/UIExtraCallbacks.cs
Executable file
@@ -0,0 +1,93 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides additional callbacks related to canvas and UI system.
|
||||||
|
/// </summary>
|
||||||
|
internal static class UIExtraCallbacks
|
||||||
|
{
|
||||||
|
private static bool s_IsInitializedAfterCanvasRebuild;
|
||||||
|
private static readonly FastAction s_AfterCanvasRebuildAction = new FastAction();
|
||||||
|
private static readonly FastAction s_LateAfterCanvasRebuildAction = new FastAction();
|
||||||
|
private static readonly FastAction s_BeforeCanvasRebuildAction = new FastAction();
|
||||||
|
|
||||||
|
static UIExtraCallbacks()
|
||||||
|
{
|
||||||
|
Canvas.willRenderCanvases += OnBeforeCanvasRebuild;
|
||||||
|
Logging.LogMulticast(typeof(Canvas), "willRenderCanvases", message: "ctor");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event that occurs after canvas rebuilds.
|
||||||
|
/// </summary>
|
||||||
|
public static event Action onLateAfterCanvasRebuild
|
||||||
|
{
|
||||||
|
add => s_LateAfterCanvasRebuildAction.Add(value);
|
||||||
|
remove => s_LateAfterCanvasRebuildAction.Remove(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event that occurs before canvas rebuilds.
|
||||||
|
/// </summary>
|
||||||
|
public static event Action onBeforeCanvasRebuild
|
||||||
|
{
|
||||||
|
add => s_BeforeCanvasRebuildAction.Add(value);
|
||||||
|
remove => s_BeforeCanvasRebuildAction.Remove(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event that occurs after canvas rebuilds.
|
||||||
|
/// </summary>
|
||||||
|
public static event Action onAfterCanvasRebuild
|
||||||
|
{
|
||||||
|
add => s_AfterCanvasRebuildAction.Add(value);
|
||||||
|
remove => s_AfterCanvasRebuildAction.Remove(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the UIExtraCallbacks to ensure proper event handling.
|
||||||
|
/// </summary>
|
||||||
|
private static void InitializeAfterCanvasRebuild()
|
||||||
|
{
|
||||||
|
if (s_IsInitializedAfterCanvasRebuild) return;
|
||||||
|
s_IsInitializedAfterCanvasRebuild = true;
|
||||||
|
|
||||||
|
CanvasUpdateRegistry.IsRebuildingLayout();
|
||||||
|
Canvas.willRenderCanvases += OnAfterCanvasRebuild;
|
||||||
|
Logging.LogMulticast(typeof(Canvas), "willRenderCanvases",
|
||||||
|
message: "InitializeAfterCanvasRebuild");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
[InitializeOnLoadMethod]
|
||||||
|
#endif
|
||||||
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||||
|
private static void InitializeOnLoad()
|
||||||
|
{
|
||||||
|
Canvas.willRenderCanvases -= OnAfterCanvasRebuild;
|
||||||
|
s_IsInitializedAfterCanvasRebuild = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Callback method called before canvas rebuilds.
|
||||||
|
/// </summary>
|
||||||
|
private static void OnBeforeCanvasRebuild()
|
||||||
|
{
|
||||||
|
s_BeforeCanvasRebuildAction.Invoke();
|
||||||
|
InitializeAfterCanvasRebuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Callback method called after canvas rebuilds.
|
||||||
|
/// </summary>
|
||||||
|
private static void OnAfterCanvasRebuild()
|
||||||
|
{
|
||||||
|
s_AfterCanvasRebuildAction.Invoke();
|
||||||
|
s_LateAfterCanvasRebuildAction.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9ea318e6e3e6c46aa97c72e28230bdc9
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Coffee.UIParticleExtensions
|
|
||||||
{
|
|
||||||
internal class ModifiedMaterial
|
|
||||||
{
|
|
||||||
private static readonly List<MatEntry> s_Entries = new List<MatEntry>();
|
|
||||||
|
|
||||||
public static Material Add(Material baseMat, Texture texture, int id, int props)
|
|
||||||
{
|
|
||||||
MatEntry e;
|
|
||||||
for (var i = 0; i < s_Entries.Count; i++)
|
|
||||||
{
|
|
||||||
e = s_Entries[i];
|
|
||||||
if (e.baseMat != baseMat || e.texture != texture || e.id != id || e.props != props) continue;
|
|
||||||
++e.count;
|
|
||||||
return e.customMat;
|
|
||||||
}
|
|
||||||
|
|
||||||
e = new MatEntry
|
|
||||||
{
|
|
||||||
count = 1,
|
|
||||||
baseMat = baseMat,
|
|
||||||
texture = texture,
|
|
||||||
id = id,
|
|
||||||
props = props,
|
|
||||||
customMat = new Material(baseMat)
|
|
||||||
{
|
|
||||||
name = $"{baseMat.name}_{id}",
|
|
||||||
hideFlags = HideFlags.DontSave | HideFlags.NotEditable,
|
|
||||||
mainTexture = texture ? texture : baseMat.mainTexture
|
|
||||||
}
|
|
||||||
};
|
|
||||||
s_Entries.Add(e);
|
|
||||||
//Debug.LogFormat(">>>> ModifiedMaterial.Add -> count = count:{0}, mat:{1}, tex:{2}, id:{3}", s_Entries.Count, baseMat, texture, id);
|
|
||||||
return e.customMat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Remove(Material customMat)
|
|
||||||
{
|
|
||||||
if (!customMat) return;
|
|
||||||
|
|
||||||
for (var i = 0; i < s_Entries.Count; ++i)
|
|
||||||
{
|
|
||||||
var e = s_Entries[i];
|
|
||||||
if (e.customMat != customMat) continue;
|
|
||||||
if (--e.count == 0)
|
|
||||||
{
|
|
||||||
//Debug.LogFormat(">>>> ModifiedMaterial.Remove -> count:{0}, mat:{1}, tex:{2}, id:{3}", s_Entries.Count - 1, e.customMat, e.texture, e.id);
|
|
||||||
Misc.DestroyImmediate(e.customMat);
|
|
||||||
e.customMat = null;
|
|
||||||
e.baseMat = null;
|
|
||||||
e.texture = null;
|
|
||||||
s_Entries.RemoveAt(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class MatEntry
|
|
||||||
{
|
|
||||||
public Material baseMat;
|
|
||||||
public int count;
|
|
||||||
public Material customMat;
|
|
||||||
public int id;
|
|
||||||
public int props;
|
|
||||||
public Texture texture;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Coffee.UIParticleExtensions;
|
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")]
|
||||||
@@ -18,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,7 +60,7 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
[Tooltip("Scale the rendering particles. When the `3D` toggle is enabled, 3D scale (x, y, z) is supported.")]
|
[Tooltip("Scale the rendering particles. When the `3D` toggle is enabled, 3D scale (x, y, z) is supported.")]
|
||||||
[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("If you want to update material properties (e.g. _MainTex_ST, _Color) in AnimationClip, " +
|
||||||
"use this to mark as animatable.")]
|
"use this to mark as animatable.")]
|
||||||
@@ -117,6 +117,9 @@ namespace Coffee.UIExtensions
|
|||||||
"Change the bake view size.")]
|
"Change the bake view size.")]
|
||||||
private float m_CustomViewSize = 10;
|
private float m_CustomViewSize = 10;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private bool m_Maskable = true;
|
||||||
|
|
||||||
private readonly List<UIParticleRenderer> _renderers = new List<UIParticleRenderer>();
|
private readonly List<UIParticleRenderer> _renderers = new List<UIParticleRenderer>();
|
||||||
private Camera _bakeCamera;
|
private Camera _bakeCamera;
|
||||||
private Canvas _canvas;
|
private Canvas _canvas;
|
||||||
@@ -125,13 +128,37 @@ namespace Coffee.UIExtensions
|
|||||||
private Vector3 _storedScale;
|
private Vector3 _storedScale;
|
||||||
private DrivenRectTransformTracker _tracker;
|
private DrivenRectTransformTracker _tracker;
|
||||||
|
|
||||||
/// <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>
|
||||||
|
/// Does this graphic allow masking.
|
||||||
|
/// </summary>
|
||||||
|
public bool maskable
|
||||||
|
{
|
||||||
|
get => m_Maskable;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == m_Maskable) return;
|
||||||
|
m_Maskable = value;
|
||||||
|
UpdateRendererMaterial();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -308,15 +335,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);
|
||||||
@@ -326,7 +353,7 @@ namespace Coffee.UIExtensions
|
|||||||
RefreshParticles();
|
RefreshParticles();
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnEnable();
|
UpdateRendererMaterial();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -343,9 +370,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>
|
||||||
@@ -360,6 +393,7 @@ namespace Coffee.UIExtensions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected override void OnTransformParentChanged()
|
protected override void OnTransformParentChanged()
|
||||||
{
|
{
|
||||||
|
_canvas = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
||||||
@@ -654,17 +688,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++)
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using Coffee.UIParticleExtensions;
|
using System.Collections.Generic;
|
||||||
|
using Coffee.UIParticleInternal;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Events;
|
using UnityEngine.Events;
|
||||||
|
|
||||||
namespace Coffee.UIExtensions
|
namespace Coffee.UIExtensions
|
||||||
{
|
{
|
||||||
[ExecuteAlways]
|
[ExecuteAlways]
|
||||||
public class UIParticleAttractor : MonoBehaviour
|
public class UIParticleAttractor : MonoBehaviour, ISerializationCallbackReceiver
|
||||||
{
|
{
|
||||||
public enum Movement
|
public enum Movement
|
||||||
{
|
{
|
||||||
@@ -22,8 +23,12 @@ 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;
|
||||||
@@ -45,7 +50,7 @@ namespace Coffee.UIExtensions
|
|||||||
[SerializeField]
|
[SerializeField]
|
||||||
private UnityEvent m_OnAttracted;
|
private UnityEvent m_OnAttracted;
|
||||||
|
|
||||||
private UIParticle _uiParticle;
|
private List<UIParticle> _uiParticles = new List<UIParticle>();
|
||||||
|
|
||||||
public float destinationRadius
|
public float destinationRadius
|
||||||
{
|
{
|
||||||
@@ -84,25 +89,46 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The target ParticleSystem to attract.
|
/// The target ParticleSystems to attract. Use <see cref="AddParticleSystem"/> and
|
||||||
|
/// <see cref="RemoveParticleSystem"/> to modify the list.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#if UNITY_EDITOR
|
public IReadOnlyList<ParticleSystem> particleSystems => m_ParticleSystems;
|
||||||
public new ParticleSystem particleSystem
|
|
||||||
#else
|
public void AddParticleSystem(ParticleSystem ps)
|
||||||
public ParticleSystem particleSystem
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
get => m_ParticleSystem;
|
if (m_ParticleSystems == null)
|
||||||
set
|
|
||||||
{
|
{
|
||||||
m_ParticleSystem = value;
|
m_ParticleSystems = new List<ParticleSystem>();
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,35 +139,45 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
private void OnDestroy()
|
private void OnDestroy()
|
||||||
{
|
{
|
||||||
_uiParticle = null;
|
_uiParticles = null;
|
||||||
m_ParticleSystem = null;
|
m_ParticleSystems = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Attract()
|
internal void Attract()
|
||||||
{
|
{
|
||||||
if (m_ParticleSystem == null) return;
|
// Collect UIParticle if needed (same size as m_ParticleSystems)
|
||||||
|
CollectUIParticlesIfNeeded();
|
||||||
|
|
||||||
var count = m_ParticleSystem.particleCount;
|
for (var particleIndex = 0; particleIndex < this.m_ParticleSystems.Count; particleIndex++)
|
||||||
if (count == 0) return;
|
{
|
||||||
|
var particleSystem = m_ParticleSystems[particleIndex];
|
||||||
|
|
||||||
|
// Skip: The ParticleSystem is not active
|
||||||
|
if (particleSystem == null || !particleSystem.gameObject.activeInHierarchy) continue;
|
||||||
|
|
||||||
|
// Skip: No active particles
|
||||||
|
var count = particleSystem.particleCount;
|
||||||
|
if (count == 0) continue;
|
||||||
|
|
||||||
var particles = ParticleSystemExtensions.GetParticleArray(count);
|
var particles = ParticleSystemExtensions.GetParticleArray(count);
|
||||||
m_ParticleSystem.GetParticles(particles, count);
|
particleSystem.GetParticles(particles, count);
|
||||||
|
|
||||||
var dstPos = GetDestinationPosition();
|
var uiParticle = _uiParticles[particleIndex];
|
||||||
|
var dstPos = this.GetDestinationPosition(uiParticle, particleSystem);
|
||||||
for (var i = 0; i < count; i++)
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
// Attracted
|
// Attracted
|
||||||
var p = particles[i];
|
var p = particles[i];
|
||||||
if (0f < p.remainingLifetime && Vector3.Distance(p.position, dstPos) < m_DestinationRadius)
|
if (0f < p.remainingLifetime && Vector3.Distance(p.position, dstPos) < this.m_DestinationRadius)
|
||||||
{
|
{
|
||||||
p.remainingLifetime = 0f;
|
p.remainingLifetime = 0f;
|
||||||
particles[i] = p;
|
particles[i] = p;
|
||||||
|
|
||||||
if (m_OnAttracted != null)
|
if (this.m_OnAttracted != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_OnAttracted.Invoke();
|
this.m_OnAttracted.Invoke();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -153,7 +189,7 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calc attracting time
|
// Calc attracting time
|
||||||
var delayTime = p.startLifetime * m_DelayRate;
|
var delayTime = p.startLifetime * this.m_DelayRate;
|
||||||
var duration = p.startLifetime - delayTime;
|
var duration = p.startLifetime - delayTime;
|
||||||
var time = Mathf.Max(0, p.startLifetime - p.remainingLifetime - delayTime);
|
var time = Mathf.Max(0, p.startLifetime - p.remainingLifetime - delayTime);
|
||||||
|
|
||||||
@@ -161,37 +197,38 @@ namespace Coffee.UIExtensions
|
|||||||
if (time <= 0) continue;
|
if (time <= 0) continue;
|
||||||
|
|
||||||
// Attract
|
// Attract
|
||||||
p.position = GetAttractedPosition(p.position, dstPos, duration, time);
|
p.position = this.GetAttractedPosition(p.position, dstPos, duration, time);
|
||||||
p.velocity *= 0.5f;
|
p.velocity *= 0.5f;
|
||||||
particles[i] = p;
|
particles[i] = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ParticleSystem.SetParticles(particles, count);
|
particleSystem.SetParticles(particles, count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector3 GetDestinationPosition()
|
private Vector3 GetDestinationPosition(UIParticle uiParticle, ParticleSystem particleSystem)
|
||||||
{
|
{
|
||||||
var isUI = _uiParticle && _uiParticle.enabled;
|
var isUI = uiParticle && uiParticle.enabled;
|
||||||
var psPos = m_ParticleSystem.transform.position;
|
var psPos = particleSystem.transform.position;
|
||||||
var attractorPos = transform.position;
|
var attractorPos = transform.position;
|
||||||
var dstPos = attractorPos;
|
var dstPos = attractorPos;
|
||||||
var isLocalSpace = m_ParticleSystem.IsLocalSpace();
|
var isLocalSpace = particleSystem.IsLocalSpace();
|
||||||
|
|
||||||
if (isLocalSpace)
|
if (isLocalSpace)
|
||||||
{
|
{
|
||||||
dstPos = m_ParticleSystem.transform.InverseTransformPoint(dstPos);
|
dstPos = 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;
|
||||||
@@ -237,25 +274,59 @@ namespace Coffee.UIExtensions
|
|||||||
return Vector3.MoveTowards(current, target, speed);
|
return Vector3.MoveTowards(current, target, speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyParticleSystem()
|
private void CollectUIParticlesIfNeeded()
|
||||||
{
|
{
|
||||||
_uiParticle = null;
|
if (m_ParticleSystems.Count == 0 || _uiParticles.Count != 0) return;
|
||||||
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
|
||||||
if (Application.isPlaying)
|
private void OnValidate()
|
||||||
|
{
|
||||||
|
_uiParticles.Clear();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
||||||
{
|
{
|
||||||
Debug.LogError("No particle system attached to particle attractor script", this);
|
UpgradeIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
void ISerializationCallbackReceiver.OnAfterDeserialize()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
_uiParticle = m_ParticleSystem.GetComponentInParent<UIParticle>(true);
|
private void UpgradeIfNeeded()
|
||||||
if (_uiParticle && !_uiParticle.particles.Contains(m_ParticleSystem))
|
|
||||||
{
|
{
|
||||||
_uiParticle = null;
|
// Multiple ParticleSystems support: from 'm_ParticleSystem' to 'm_ParticleSystems'
|
||||||
|
if (m_ParticleSystem != null)
|
||||||
|
{
|
||||||
|
if (!m_ParticleSystems.Contains(m_ParticleSystem))
|
||||||
|
{
|
||||||
|
m_ParticleSystems.Add(m_ParticleSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ParticleSystem = null;
|
||||||
|
Debug.Log($"Upgraded!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
28
Packages/src/Runtime/UIParticleProjectSettings.cs
Normal file
28
Packages/src/Runtime/UIParticleProjectSettings.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma warning disable CS0414
|
||||||
|
using Coffee.UIParticleInternal;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Coffee.UIExtensions
|
||||||
|
{
|
||||||
|
public class UIParticleProjectSettings : PreloadedProjectSettings<UIParticleProjectSettings>
|
||||||
|
{
|
||||||
|
[Header("Setting")]
|
||||||
|
[SerializeField]
|
||||||
|
internal bool m_EnableLinearToGamma = true;
|
||||||
|
|
||||||
|
public static bool enableLinearToGamma
|
||||||
|
{
|
||||||
|
get => instance.m_EnableLinearToGamma;
|
||||||
|
set => instance.m_EnableLinearToGamma = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
[SettingsProvider]
|
||||||
|
private static SettingsProvider CreateSettingsProvider()
|
||||||
|
{
|
||||||
|
return new PreloadedProjectSettingsProvider("Project/UI/UI Particle");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Packages/src/Runtime/UIParticleProjectSettings.cs.meta
Normal file
11
Packages/src/Runtime/UIParticleProjectSettings.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f22a23b9d98e440478697f4adf30e61c
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -4,9 +4,10 @@
|
|||||||
#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.UIParticleExtensions;
|
using Coffee.UIParticleInternal;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Profiling;
|
using UnityEngine.Profiling;
|
||||||
@@ -21,19 +22,16 @@ namespace Coffee.UIExtensions
|
|||||||
[AddComponentMenu("")]
|
[AddComponentMenu("")]
|
||||||
internal class UIParticleRenderer : MaskableGraphic
|
internal class UIParticleRenderer : MaskableGraphic
|
||||||
{
|
{
|
||||||
private static readonly List<Component> s_Components = new List<Component>();
|
|
||||||
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>();
|
|
||||||
private static readonly List<Color32> s_Colors = new List<Color32>();
|
|
||||||
private static readonly Vector3[] s_Corners = new Vector3[4];
|
private static readonly Vector3[] s_Corners = new Vector3[4];
|
||||||
private Material _currentMaterialForRendering;
|
|
||||||
private bool _delay;
|
private bool _delay;
|
||||||
private int _index;
|
private int _index;
|
||||||
private bool _isPrevStored;
|
private bool _isPrevStored;
|
||||||
private bool _isTrail;
|
private bool _isTrail;
|
||||||
private Bounds _lastBounds;
|
private Bounds _lastBounds;
|
||||||
|
private Material _materialForRendering;
|
||||||
private Material _modifiedMaterial;
|
private Material _modifiedMaterial;
|
||||||
private UIParticle _parent;
|
private UIParticle _parent;
|
||||||
private ParticleSystem _particleSystem;
|
private ParticleSystem _particleSystem;
|
||||||
@@ -92,6 +90,19 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Material materialForRendering
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!_materialForRendering)
|
||||||
|
{
|
||||||
|
_materialForRendering = base.materialForRendering;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _materialForRendering;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Reset(int index = -1)
|
public void Reset(int index = -1)
|
||||||
{
|
{
|
||||||
if (_renderer)
|
if (_renderer)
|
||||||
@@ -117,9 +128,8 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ModifiedMaterial.Remove(_modifiedMaterial);
|
MaterialRepository.Release(ref _modifiedMaterial);
|
||||||
_modifiedMaterial = null;
|
_materialForRendering = null;
|
||||||
_currentMaterialForRendering = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,17 +145,14 @@ namespace Coffee.UIExtensions
|
|||||||
hideFlags = HideFlags.HideAndDontSave
|
hideFlags = HideFlags.HideAndDontSave
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentMaterialForRendering = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDisable()
|
protected override void OnDisable()
|
||||||
{
|
{
|
||||||
base.OnDisable();
|
base.OnDisable();
|
||||||
|
|
||||||
ModifiedMaterial.Remove(_modifiedMaterial);
|
MaterialRepository.Release(ref _modifiedMaterial);
|
||||||
_modifiedMaterial = null;
|
_materialForRendering = null;
|
||||||
_currentMaterialForRendering = null;
|
|
||||||
_isPrevStored = false;
|
_isPrevStored = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,12 +185,9 @@ namespace Coffee.UIExtensions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public override Material GetModifiedMaterial(Material baseMaterial)
|
public override Material GetModifiedMaterial(Material baseMaterial)
|
||||||
{
|
{
|
||||||
_currentMaterialForRendering = null;
|
|
||||||
|
|
||||||
if (!IsActive() || !_parent)
|
if (!IsActive() || !_parent)
|
||||||
{
|
{
|
||||||
ModifiedMaterial.Remove(_modifiedMaterial);
|
MaterialRepository.Release(ref _modifiedMaterial);
|
||||||
_modifiedMaterial = null;
|
|
||||||
return baseMaterial;
|
return baseMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,23 +197,31 @@ namespace Coffee.UIExtensions
|
|||||||
var texture = mainTexture;
|
var texture = mainTexture;
|
||||||
if (texture == null && _parent.m_AnimatableProperties.Length == 0)
|
if (texture == null && _parent.m_AnimatableProperties.Length == 0)
|
||||||
{
|
{
|
||||||
ModifiedMaterial.Remove(_modifiedMaterial);
|
MaterialRepository.Release(ref _modifiedMaterial);
|
||||||
_modifiedMaterial = null;
|
|
||||||
return modifiedMaterial;
|
return modifiedMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
var id = _parent.m_AnimatableProperties.Length == 0 ? 0 : GetInstanceID();
|
var hash = new Hash128(
|
||||||
|
modifiedMaterial ? (uint)modifiedMaterial.GetInstanceID() : 0,
|
||||||
|
texture ? (uint)texture.GetInstanceID() : 0,
|
||||||
|
0 < _parent.m_AnimatableProperties.Length ? (uint)GetInstanceID() : 0,
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
var props = EditorJsonUtility.ToJson(modifiedMaterial).GetHashCode();
|
(uint)EditorJsonUtility.ToJson(modifiedMaterial).GetHashCode()
|
||||||
#else
|
#else
|
||||||
var props = 0;
|
0
|
||||||
#endif
|
#endif
|
||||||
modifiedMaterial = ModifiedMaterial.Add(modifiedMaterial, texture, id, props);
|
);
|
||||||
ModifiedMaterial.Remove(_modifiedMaterial);
|
if (!MaterialRepository.Valid(hash, _modifiedMaterial))
|
||||||
_modifiedMaterial = modifiedMaterial;
|
{
|
||||||
|
MaterialRepository.Get(hash, ref _modifiedMaterial, x => new Material(x.mat)
|
||||||
|
{
|
||||||
|
hideFlags = HideFlags.HideAndDontSave,
|
||||||
|
mainTexture = x.texture ? x.texture : x.mat.mainTexture
|
||||||
|
}, (mat: modifiedMaterial, texture));
|
||||||
|
}
|
||||||
|
|
||||||
return modifiedMaterial;
|
return _modifiedMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Set(UIParticle parent, ParticleSystem ps, bool isTrail)
|
public void Set(UIParticle parent, ParticleSystem ps, bool isTrail)
|
||||||
@@ -405,95 +417,68 @@ namespace Coffee.UIExtensions
|
|||||||
_lastBounds = bounds;
|
_lastBounds = bounds;
|
||||||
|
|
||||||
// Convert linear color to gamma color.
|
// Convert linear color to gamma color.
|
||||||
if (QualitySettings.activeColorSpace == ColorSpace.Linear)
|
if (UIParticleProjectSettings.enableLinearToGamma && canvas.ShouldGammaToLinearInMesh())
|
||||||
{
|
{
|
||||||
Profiler.BeginSample("[UIParticleRenderer] Convert Linear to Gamma");
|
workerMesh.LinearToGamma();
|
||||||
workerMesh.GetColors(s_Colors);
|
|
||||||
var count_c = s_Colors.Count;
|
|
||||||
for (var i = 0; i < count_c; i++)
|
|
||||||
{
|
|
||||||
var c = s_Colors[i];
|
|
||||||
c.r = c.r.LinearToGamma();
|
|
||||||
c.g = c.g.LinearToGamma();
|
|
||||||
c.b = c.b.LinearToGamma();
|
|
||||||
s_Colors[i] = c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
workerMesh.SetColors(s_Colors);
|
var components = ListPool<Component>.Rent();
|
||||||
Profiler.EndSample();
|
GetComponents(typeof(IMeshModifier), components);
|
||||||
}
|
|
||||||
|
|
||||||
GetComponents(typeof(IMeshModifier), s_Components);
|
|
||||||
for (var i = 0; i < s_Components.Count; i++)
|
|
||||||
{
|
|
||||||
#pragma warning disable CS0618 // Type or member is obsolete
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
((IMeshModifier)s_Components[i]).ModifyMesh(workerMesh);
|
for (var i = 0; i < components.Count; i++)
|
||||||
|
{
|
||||||
|
((IMeshModifier)components[i]).ModifyMesh(workerMesh);
|
||||||
|
}
|
||||||
#pragma warning restore CS0618 // Type or member is obsolete
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
|
|
||||||
|
ListPool<Component>.Return(ref components);
|
||||||
}
|
}
|
||||||
|
|
||||||
s_Components.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
Profiler.EndSample();
|
|
||||||
|
|
||||||
|
|
||||||
// Get grouped renderers.
|
|
||||||
s_Renderers.Clear();
|
|
||||||
if (_parent.useMeshSharing)
|
|
||||||
{
|
|
||||||
UIParticleUpdater.GetGroupedRenderers(_parent.groupId, _index, s_Renderers);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set mesh to the CanvasRenderer.
|
|
||||||
Profiler.BeginSample("[UIParticleRenderer] Set Mesh");
|
|
||||||
for (var i = 0; i < s_Renderers.Count; i++)
|
|
||||||
{
|
|
||||||
if (s_Renderers[i] == this) continue;
|
|
||||||
s_Renderers[i].canvasRenderer.SetMesh(workerMesh);
|
|
||||||
s_Renderers[i]._lastBounds = _lastBounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_parent.canRender)
|
|
||||||
{
|
|
||||||
workerMesh.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
canvasRenderer.SetMesh(workerMesh);
|
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
|
|
||||||
// Update animatable material properties.
|
// Update animatable material properties.
|
||||||
Profiler.BeginSample("[UIParticleRenderer] Update Animatable Material Properties");
|
Profiler.BeginSample("[UIParticleRenderer] Update Animatable Material Properties");
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
if (_modifiedMaterial != material)
|
|
||||||
{
|
|
||||||
_renderer.GetSharedMaterials(s_Materials);
|
|
||||||
material = s_Materials[_isTrail ? 1 : 0];
|
|
||||||
s_Materials.Clear();
|
|
||||||
SetMaterialDirty();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
UpdateMaterialProperties();
|
UpdateMaterialProperties();
|
||||||
|
Profiler.EndSample();
|
||||||
|
|
||||||
|
// Get grouped renderers.
|
||||||
|
Profiler.BeginSample("[UIParticleRenderer] Set Mesh");
|
||||||
|
var renderers = ListPool<UIParticleRenderer>.Rent();
|
||||||
if (_parent.useMeshSharing)
|
if (_parent.useMeshSharing)
|
||||||
{
|
{
|
||||||
if (!_currentMaterialForRendering)
|
UIParticleUpdater.GetGroupedRenderers(_parent.groupId, _index, renderers);
|
||||||
{
|
|
||||||
_currentMaterialForRendering = materialForRendering;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < s_Renderers.Count; i++)
|
for (var i = 0; i < renderers.Count; i++)
|
||||||
{
|
{
|
||||||
if (s_Renderers[i] == this) continue;
|
var r = renderers[i];
|
||||||
|
if (r == this) continue;
|
||||||
|
|
||||||
s_Renderers[i].canvasRenderer.materialCount = 1;
|
r.canvasRenderer.SetMesh(workerMesh);
|
||||||
s_Renderers[i].canvasRenderer.SetMaterial(_currentMaterialForRendering, 0);
|
r._lastBounds = _lastBounds;
|
||||||
|
r.canvasRenderer.materialCount = 1;
|
||||||
|
r.canvasRenderer.SetMaterial(materialForRendering, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ListPool<UIParticleRenderer>.Return(ref renderers);
|
||||||
|
|
||||||
|
if (_parent.canRender)
|
||||||
|
{
|
||||||
|
canvasRenderer.SetMesh(workerMesh);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
workerMesh.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
s_Renderers.Clear();
|
public override void SetMaterialDirty()
|
||||||
|
{
|
||||||
|
_materialForRendering = null;
|
||||||
|
base.SetMaterialDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -701,12 +686,12 @@ namespace Coffee.UIExtensions
|
|||||||
if (s_Mpb.isEmpty) return;
|
if (s_Mpb.isEmpty) return;
|
||||||
|
|
||||||
// #41: Copy the value from MaterialPropertyBlock to CanvasRenderer
|
// #41: Copy the value from MaterialPropertyBlock to CanvasRenderer
|
||||||
if (!_modifiedMaterial) return;
|
if (!materialForRendering) return;
|
||||||
|
|
||||||
for (var i = 0; i < _parent.m_AnimatableProperties.Length; i++)
|
for (var i = 0; i < _parent.m_AnimatableProperties.Length; i++)
|
||||||
{
|
{
|
||||||
var ap = _parent.m_AnimatableProperties[i];
|
var ap = _parent.m_AnimatableProperties[i];
|
||||||
ap.UpdateMaterialProperties(_modifiedMaterial, s_Mpb);
|
ap.UpdateMaterialProperties(materialForRendering, s_Mpb);
|
||||||
}
|
}
|
||||||
|
|
||||||
s_Mpb.Clear();
|
s_Mpb.Clear();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Coffee.UIParticleInternal;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
@@ -44,8 +45,7 @@ namespace Coffee.UIExtensions
|
|||||||
#endif
|
#endif
|
||||||
private static void InitializeOnLoad()
|
private static void InitializeOnLoad()
|
||||||
{
|
{
|
||||||
Canvas.willRenderCanvases -= Refresh;
|
UIExtraCallbacks.onAfterCanvasRebuild += Refresh;
|
||||||
Canvas.willRenderCanvases += Refresh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Refresh()
|
private static void Refresh()
|
||||||
|
|||||||
8
Packages/src/Runtime/Utilities.meta
Normal file
8
Packages/src/Runtime/Utilities.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 66c42f0f30de84ca4bd8305a1188af85
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,96 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Object = UnityEngine.Object;
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
namespace Coffee.UIParticleExtensions
|
namespace Coffee.UIParticleInternal
|
||||||
{
|
{
|
||||||
public static class Color32Extensions
|
internal static class ParticleSystemExtensions
|
||||||
{
|
|
||||||
private static byte[] s_LinearToGammaLut;
|
|
||||||
|
|
||||||
public static byte LinearToGamma(this byte self)
|
|
||||||
{
|
|
||||||
if (s_LinearToGammaLut == null)
|
|
||||||
{
|
|
||||||
s_LinearToGammaLut = new byte[256];
|
|
||||||
for (var i = 0; i < 256; i++)
|
|
||||||
{
|
|
||||||
s_LinearToGammaLut[i] = (byte)(Mathf.LinearToGammaSpace(i / 255f) * 255f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return s_LinearToGammaLut[self];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Vector3Extensions
|
|
||||||
{
|
|
||||||
public static Vector3 Inverse(this Vector3 self)
|
|
||||||
{
|
|
||||||
self.x = Mathf.Approximately(self.x, 0) ? 1 : 1 / self.x;
|
|
||||||
self.y = Mathf.Approximately(self.y, 0) ? 1 : 1 / self.y;
|
|
||||||
self.z = Mathf.Approximately(self.z, 0) ? 1 : 1 / self.z;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3 GetScaled(this Vector3 self, Vector3 other1)
|
|
||||||
{
|
|
||||||
self.Scale(other1);
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3 GetScaled(this Vector3 self, Vector3 other1, Vector3 other2)
|
|
||||||
{
|
|
||||||
self.Scale(other1);
|
|
||||||
self.Scale(other2);
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3 GetScaled(this Vector3 self, Vector3 other1, Vector3 other2, Vector3 other3)
|
|
||||||
{
|
|
||||||
self.Scale(other1);
|
|
||||||
self.Scale(other2);
|
|
||||||
self.Scale(other3);
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsVisible(this Vector3 self)
|
|
||||||
{
|
|
||||||
return 0 < Mathf.Abs(self.x * self.y * self.z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static class SpriteExtensions
|
|
||||||
{
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
private static readonly Type s_SpriteEditorExtensionType =
|
|
||||||
Type.GetType("UnityEditor.Experimental.U2D.SpriteEditorExtension, UnityEditor")
|
|
||||||
?? Type.GetType("UnityEditor.U2D.SpriteEditorExtension, UnityEditor");
|
|
||||||
|
|
||||||
private static readonly MethodInfo s_GetActiveAtlasTextureMethodInfo = s_SpriteEditorExtensionType
|
|
||||||
.GetMethod("GetActiveAtlasTexture", BindingFlags.Static | BindingFlags.NonPublic);
|
|
||||||
|
|
||||||
public static Texture2D GetActualTexture(this Sprite self)
|
|
||||||
{
|
|
||||||
if (!self) return null;
|
|
||||||
|
|
||||||
if (Application.isPlaying) return self.texture;
|
|
||||||
var ret = s_GetActiveAtlasTextureMethodInfo.Invoke(null, new object[] { self }) as Texture2D;
|
|
||||||
return ret
|
|
||||||
? ret
|
|
||||||
: self.texture;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
internal static Texture2D GetActualTexture(this Sprite self)
|
|
||||||
{
|
|
||||||
return self ? self.texture : null;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ParticleSystemExtensions
|
|
||||||
{
|
{
|
||||||
private static ParticleSystem.Particle[] s_TmpParticles = new ParticleSystem.Particle[2048];
|
private static ParticleSystem.Particle[] s_TmpParticles = new ParticleSystem.Particle[2048];
|
||||||
|
|
||||||
@@ -250,59 +165,11 @@ namespace Coffee.UIParticleExtensions
|
|||||||
|
|
||||||
public static void Exec(this List<ParticleSystem> self, Action<ParticleSystem> action)
|
public static void Exec(this List<ParticleSystem> self, Action<ParticleSystem> action)
|
||||||
{
|
{
|
||||||
self.RemoveAll(p => !p);
|
foreach (var p in self)
|
||||||
self.ForEach(action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static class Misc
|
|
||||||
{
|
{
|
||||||
public static void Destroy(Object obj)
|
if (!p) continue;
|
||||||
{
|
action.Invoke(p);
|
||||||
if (!obj) return;
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
if (!Application.isPlaying)
|
|
||||||
{
|
|
||||||
Object.DestroyImmediate(obj);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
Object.Destroy(obj);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DestroyImmediate(Object obj)
|
|
||||||
{
|
|
||||||
if (!obj) return;
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
if (Application.isEditor)
|
|
||||||
{
|
|
||||||
Object.DestroyImmediate(obj);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
Object.Destroy(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !UNITY_2021_2_OR_NEWER && !UNITY_2020_3_45 && !UNITY_2020_3_46 && !UNITY_2020_3_47 && !UNITY_2020_3_48
|
|
||||||
public static T GetComponentInParent<T>(this Component self, bool includeInactive) where T : Component
|
|
||||||
{
|
|
||||||
if (!self) return null;
|
|
||||||
if (!includeInactive) return self.GetComponentInParent<T>();
|
|
||||||
|
|
||||||
var current = self.transform;
|
|
||||||
while (current)
|
|
||||||
{
|
|
||||||
var component = current.GetComponent<T>();
|
|
||||||
if (component) return component;
|
|
||||||
current = current.parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e51604bfb810e44519e2710fd1b8af90
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -51,7 +51,11 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
|
|
||||||
public void EnableAnimations(bool flag)
|
public void EnableAnimations(bool flag)
|
||||||
{
|
{
|
||||||
|
#if UNITY_2023_1_OR_NEWER
|
||||||
|
foreach (var animator in FindObjectsByType<Animator>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
||||||
|
#else
|
||||||
foreach (var animator in FindObjectsOfType<Animator>())
|
foreach (var animator in FindObjectsOfType<Animator>())
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
animator.enabled = flag;
|
animator.enabled = flag;
|
||||||
}
|
}
|
||||||
@@ -79,7 +83,11 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
|
|
||||||
public void UIParticle_Scale(float scale)
|
public void UIParticle_Scale(float scale)
|
||||||
{
|
{
|
||||||
|
#if UNITY_2023_1_OR_NEWER
|
||||||
|
foreach (var uip in FindObjectsByType<UIParticle>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
||||||
|
#else
|
||||||
foreach (var uip in FindObjectsOfType<UIParticle>())
|
foreach (var uip in FindObjectsOfType<UIParticle>())
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
uip.scale = scale;
|
uip.scale = scale;
|
||||||
}
|
}
|
||||||
@@ -87,7 +95,11 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
|
|
||||||
public void ParticleSystem_WorldSpaseSimulation(bool flag)
|
public void ParticleSystem_WorldSpaseSimulation(bool flag)
|
||||||
{
|
{
|
||||||
|
#if UNITY_2023_1_OR_NEWER
|
||||||
|
foreach (var p in FindObjectsByType<ParticleSystem>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
||||||
|
#else
|
||||||
foreach (var p in FindObjectsOfType<ParticleSystem>())
|
foreach (var p in FindObjectsOfType<ParticleSystem>())
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
var main = p.main;
|
var main = p.main;
|
||||||
main.simulationSpace = flag
|
main.simulationSpace = flag
|
||||||
@@ -123,7 +135,11 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
|
|
||||||
public void ParticleSystem_SetScale(float scale)
|
public void ParticleSystem_SetScale(float scale)
|
||||||
{
|
{
|
||||||
|
#if UNITY_2023_1_OR_NEWER
|
||||||
|
foreach (var ps in FindObjectsByType<ParticleSystem>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
||||||
|
#else
|
||||||
foreach (var ps in FindObjectsOfType<ParticleSystem>())
|
foreach (var ps in FindObjectsOfType<ParticleSystem>())
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
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: 1
|
spriteMeshType: 0
|
||||||
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: 1
|
spriteGenerateFallbackPhysicsShape: 0
|
||||||
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: 1
|
textureFormat: 4
|
||||||
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: 1
|
spriteMeshType: 0
|
||||||
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: 1
|
spriteGenerateFallbackPhysicsShape: 0
|
||||||
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: 1
|
spriteMeshType: 0
|
||||||
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: 1
|
spriteGenerateFallbackPhysicsShape: 0
|
||||||
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: -1
|
textureFormat: 4
|
||||||
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: 1
|
spriteMeshType: 0
|
||||||
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: 1
|
spriteGenerateFallbackPhysicsShape: 0
|
||||||
alphaUsage: 1
|
alphaUsage: 1
|
||||||
alphaIsTransparency: 1
|
alphaIsTransparency: 1
|
||||||
spriteTessellationDetail: -1
|
spriteTessellationDetail: -1
|
||||||
|
|||||||
@@ -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.8.1",
|
"version": "4.9.0",
|
||||||
"unity": "2018.2",
|
"unity": "2018.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ PlayerSettings:
|
|||||||
bundleVersion: 1.0
|
bundleVersion: 1.0
|
||||||
preloadedAssets:
|
preloadedAssets:
|
||||||
- {fileID: 11400000, guid: 86087a0847f384b538391745dad4565c, type: 2}
|
- {fileID: 11400000, guid: 86087a0847f384b538391745dad4565c, type: 2}
|
||||||
- {fileID: 11400000, guid: be3e05903ef7041d39b3ef8ecdd47f08, type: 2}
|
- {fileID: 11400000, guid: e8e7744b163af4869b07b8f192c810ed, type: 2}
|
||||||
metroInputSource: 0
|
metroInputSource: 0
|
||||||
wsaTransparentSwapchain: 0
|
wsaTransparentSwapchain: 0
|
||||||
m_HolographicPauseOnTrackingLoss: 1
|
m_HolographicPauseOnTrackingLoss: 1
|
||||||
@@ -520,7 +520,7 @@ PlayerSettings:
|
|||||||
webGLTemplate: APPLICATION:Default
|
webGLTemplate: APPLICATION:Default
|
||||||
webGLAnalyzeBuildSize: 0
|
webGLAnalyzeBuildSize: 0
|
||||||
webGLUseEmbeddedResources: 0
|
webGLUseEmbeddedResources: 0
|
||||||
webGLCompressionFormat: 1
|
webGLCompressionFormat: 2
|
||||||
webGLLinkerTarget: 0
|
webGLLinkerTarget: 0
|
||||||
webGLThreadsSupport: 0
|
webGLThreadsSupport: 0
|
||||||
scriptingDefineSymbols:
|
scriptingDefineSymbols:
|
||||||
|
|||||||
Reference in New Issue
Block a user