Compare commits

..

21 Commits

Author SHA1 Message Date
mob-sakai
ed0da9785c feat: external time controller 2025-02-21 14:32:01 +09:00
semantic-release-bot
d1a1e23e50 chore(release): 4.10.7 [skip ci]
## [4.10.7](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.6...v4.10.7) (2025-01-14)

### Bug Fixes

* editor crashed on exit play mode (editor, windows) ([47ee45c](47ee45cbbe)), closes [#351](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/351)
2025-01-14 11:49:21 +00:00
mob-sakai
47ee45cbbe fix: editor crashed on exit play mode (editor, windows)
close #351
2025-01-07 10:25:23 +09:00
semantic-release-bot
1b0110320b chore(release): 4.10.6 [skip ci]
## [4.10.6](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.5...v4.10.6) (2025-01-03)

### Bug Fixes

* sub-emitter particles may not render correctly in certain scenarios ([8276684](8276684c3b)), closes [#348](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/348)
* sub-emitter's `inherit velocity` module doubles at runtime ([67de3d1](67de3d1bd3)), closes [#349](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/349)
2025-01-03 14:24:40 +00:00
mob-sakai
a1ca74f854 chore: update coffee.internal 2025-01-03 23:13:17 +09:00
mob-sakai
8276684c3b fix: sub-emitter particles may not render correctly in certain scenarios
close #348
2025-01-03 23:13:17 +09:00
mob-sakai
67de3d1bd3 fix: sub-emitter's inherit velocity module doubles at runtime
close #349
2025-01-03 23:13:17 +09:00
semantic-release-bot
90d966e659 chore(release): 4.10.5 [skip ci]
## [4.10.5](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.4...v4.10.5) (2024-12-23)

### Bug Fixes

* '3D' scale toggle in the inspector does not keep on reload ([934f4b8](934f4b8f1c)), closes [#346](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/346)
2024-12-23 03:54:11 +00:00
mob-sakai
0036b03d12 refactor: update coffee.internal 2024-12-23 12:53:15 +09:00
mob-sakai
934f4b8f1c fix: '3D' scale toggle in the inspector does not keep on reload
close #346
2024-12-22 13:10:21 +09:00
semantic-release-bot
fe4fcc5ddd chore(release): 4.10.4 [skip ci]
## [4.10.4](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.3...v4.10.4) (2024-12-19)

### Bug Fixes

* rendering issues when playing with opening a prefab stage ([95235a9](95235a929b)), closes [#345](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/345)
2024-12-19 08:50:19 +00:00
mob-sakai
072aac521b chore: update test workflow 2024-12-18 19:50:31 +09:00
mob-sakai
95235a929b fix: rendering issues when playing with opening a prefab stage
close #345
2024-12-18 19:46:32 +09:00
semantic-release-bot
1a748f19d0 chore(release): 4.10.3 [skip ci]
## [4.10.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.2...v4.10.3) (2024-11-20)

### Bug Fixes

* if not configured as a preloaded asset, the project settings asset will be regenerated ([abe0948](abe09485f6)), closes [#342](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/342)
2024-11-20 16:56:36 +00:00
mob-sakai
f9ce2c6c96 chore: update workflows 2024-11-21 01:46:37 +09:00
mob-sakai
abe09485f6 fix: if not configured as a preloaded asset, the project settings asset will be regenerated
close #342
2024-11-21 01:39:16 +09:00
mob-sakai
253fb52650 refactor: update coffee.internal 2024-11-21 01:36:51 +09:00
mob-sakai
3544c593e2 chore: add demo for cfxrf 2024-11-21 01:26:03 +09:00
semantic-release-bot
4faf151c87 chore(release): 4.10.2 [skip ci]
## [4.10.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.1...v4.10.2) (2024-11-01)

### Bug Fixes

* trail incorrect offset ([afe00a1](afe00a1dde)), closes [#335](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/335)
2024-11-01 02:15:40 +00:00
Jie
afe00a1dde fix: trail incorrect offset
close #335
2024-11-01 11:14:03 +09:00
mob-sakai
c1e3d68f60 refactor 2024-09-30 03:01:48 +09:00
29 changed files with 7508 additions and 231 deletions

View File

@@ -38,7 +38,7 @@ jobs:
@semantic-release/changelog @semantic-release/changelog
@semantic-release/git @semantic-release/git
env: env:
GITHUB_TOKEN: ${{ github.token }} GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
- id: summary - id: summary
run: | run: |

View File

@@ -3,29 +3,36 @@
# UNITY_EMAIL: Unity user email to login # UNITY_EMAIL: Unity user email to login
# UNITY_PASSWORD: Unity user password to login # UNITY_PASSWORD: Unity user password to login
name: 🧪 Test name: 🧪 Test
run-name: 🧪 Test (${{ github.ref_name }}) run-name: 🧪 Test (${{ github.event.pull_request.title || github.ref_name }})
env: env:
# MINIMUM_VERSION: The minimum version of Unity. # MINIMUM_VERSION: The minimum version of Unity.
MINIMUM_VERSION: 2019.4 MINIMUM_VERSION: 2019.4
# EXCLUDE_FILTER: The excluded versions of Unity. # EXCLUDE_FILTER: The excluded versions of Unity.
EXCLUDE_FILTER: '(2020.2.0|2021.1|2023.3)' EXCLUDE_FILTER: "(2020.2.0|2021.1|2023.3)"
on: on:
workflow_dispatch: workflow_dispatch:
inputs:
usePeriodVersions:
description: "Use the period versions (.0f1, .10f1, 20f1, ...)."
required: false
default: "true"
push: push:
branches: branches:
- develop - develop
- develop-preview - develop-preview
- develop-4.x
tags: tags:
- "!*" - "!*"
paths-ignore: paths-ignore:
- "*.md" - "**.md"
pull_request: pull_request_target:
types: types:
- opened - opened
- reopened
- synchronize - synchronize
paths-ignore:
- "**.md"
jobs: jobs:
setup: setup:
@@ -38,9 +45,12 @@ jobs:
id: setup id: setup
run: | run: |
echo "==== Target Unity Versions ====" echo "==== Target Unity Versions ===="
LATEST_VERSIONS=`npx unity-changeset list --versions --latest-patch --min ${MINIMUM_VERSION} --json --all` LATEST_VERSIONS=`npx unity-changeset@latest list --versions --latest-patch --min ${MINIMUM_VERSION} --json --all`
# ADDITIONAL_VERSIONS=`npx unity-changeset list --versions --grep '0f' --min ${MINIMUM_VERSION} --json` if [ "${{ inputs.usePeriodVersions }}" = "true" ]; then
ADDITIONAL_VERSIONS=[] ADDITIONAL_VERSIONS=`npx unity-changeset list --versions --grep '0f' --min ${MINIMUM_VERSION} --json`
else
ADDITIONAL_VERSIONS=[]
fi
VERSIONS=`echo "[${LATEST_VERSIONS}, ${ADDITIONAL_VERSIONS}]" \ VERSIONS=`echo "[${LATEST_VERSIONS}, ${ADDITIONAL_VERSIONS}]" \
| jq -c '[ flatten | sort | unique | .[] | select( test("${{ env.EXCLUDE_FILTER }}") | not ) ]'` | jq -c '[ flatten | sort | unique | .[] | select( test("${{ env.EXCLUDE_FILTER }}") | not ) ]'`
@@ -49,33 +59,44 @@ jobs:
test: test:
name: 🧪 Run tests name: 🧪 Run tests
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
permissions: permissions:
checks: write checks: write
contents: read contents: read
needs: setup needs: setup
strategy: strategy:
fail-fast: false fail-fast: false
max-parallel: 4 max-parallel: 6
matrix: matrix:
unityVersion: ${{ fromJson(needs.setup.outputs.unityVersions) }} unityVersion: ${{ fromJson(needs.setup.outputs.unityVersions) }}
steps: steps:
- name: 🚚 Checkout - name: 🚚 Checkout ($${{ github.ref }})
if: github.event_name == 'push'
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: 🚚 Checkout pull request (pull_request_target)
if: github.event_name == 'pull_request_target'
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: 🚚 Marge pull request (pull_request_target)
if: github.event_name == 'pull_request_target'
run: |
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git merge origin/${{ github.event.pull_request.base.ref }} --no-edit
- name: 📥 Cache library - name: 📥 Cache library
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
path: Library path: Library
key: Library-${{ matrix.unityVersion }}-${{ github.sha }} key: Library-${{ matrix.unityVersion }}-${{ github.event.pull_request.head.sha || github.sha }}
restore-keys: | restore-keys: |
Library-${{ matrix.unityVersion }}- Library-${{ matrix.unityVersion }}-
Library- Library-
- name: 🛠️ Build Unity Project - name: 🛠️ Build Unity Project (Test)
uses: game-ci/unity-builder@v4 uses: game-ci/unity-builder@v4
timeout-minutes: 45 timeout-minutes: 45
with: with:
@@ -83,6 +104,10 @@ jobs:
targetPlatform: StandaloneLinux64 targetPlatform: StandaloneLinux64
allowDirtyBuild: true allowDirtyBuild: true
customParameters: -nographics customParameters: -nographics
env:
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
- name: 🧪 Run tests - name: 🧪 Run tests
uses: game-ci/unity-test-runner@v4 uses: game-ci/unity-test-runner@v4
@@ -93,4 +118,7 @@ jobs:
customParameters: -nographics customParameters: -nographics
checkName: ${{ matrix.unityVersion }} Test Results checkName: ${{ matrix.unityVersion }} Test Results
githubToken: ${{ github.token }} githubToken: ${{ github.token }}
coverageOptions: "dontClear;generateHtmlReport;generateBadgeReport;pathFilters:+**/Packages/src/**;assemblyFilters:+<packages>,-*.Editor,-*.Test" env:
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
fileFormatVersion: 2
guid: e34a092899a9547189add96707de1b5a
DefaultImporter:
userData:

View File

@@ -1,3 +1,4 @@
using Coffee.UIParticleInternal;
using UnityEngine; using UnityEngine;
using UnityEngine.Serialization; using UnityEngine.Serialization;
@@ -46,11 +47,7 @@ namespace Coffee.UIExtensions.Demo
if (!flag) if (!flag)
{ {
#if UNITY_2023_1_OR_NEWER foreach (var ps in Misc.FindObjectsOfType<ParticleSystem>())
foreach (var ps in FindObjectsByType<ParticleSystem>(FindObjectsInactive.Include, FindObjectsSortMode.None))
#else
foreach (var ps in FindObjectsOfType<ParticleSystem>())
#endif
{ {
ps.Play(false); ps.Play(false);
} }
@@ -79,11 +76,7 @@ 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 Misc.FindObjectsOfType<ParticleSystem>())
foreach (var ps in FindObjectsByType<ParticleSystem>(FindObjectsInactive.Include, FindObjectsSortMode.None))
#else
foreach (var ps in FindObjectsOfType<ParticleSystem>())
#endif
{ {
ps.transform.localScale = new Vector3(scale, scale, scale); ps.transform.localScale = new Vector3(scale, scale, scale);
} }

View File

@@ -1,6 +1,7 @@
{ {
"dependencies": { "dependencies": {
"com.coffee.development": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/Development", "com.coffee.development": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/Development",
"com.coffee.minimal-resource": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/MinimalResource",
"com.coffee.nano-monitor": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/NanoMonitor", "com.coffee.nano-monitor": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/NanoMonitor",
"com.unity.ide.rider": "3.0.31", "com.unity.ide.rider": "3.0.31",
"com.unity.test-framework": "1.1.33", "com.unity.test-framework": "1.1.33",

View File

@@ -5,7 +5,14 @@
"depth": 0, "depth": 0,
"source": "git", "source": "git",
"dependencies": {}, "dependencies": {},
"hash": "4e5f735ccf956ee469b5014ae781068c49a2825d" "hash": "52987fb6e66e7fc48498d8d164c3c8808de4de6b"
},
"com.coffee.minimal-resource": {
"version": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/MinimalResource",
"depth": 0,
"source": "git",
"dependencies": {},
"hash": "52987fb6e66e7fc48498d8d164c3c8808de4de6b"
}, },
"com.coffee.nano-monitor": { "com.coffee.nano-monitor": {
"version": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/NanoMonitor", "version": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/NanoMonitor",
@@ -14,7 +21,7 @@
"dependencies": { "dependencies": {
"com.unity.ugui": "1.0.0" "com.unity.ugui": "1.0.0"
}, },
"hash": "4e5f735ccf956ee469b5014ae781068c49a2825d" "hash": "52987fb6e66e7fc48498d8d164c3c8808de4de6b"
}, },
"com.coffee.ui-particle": { "com.coffee.ui-particle": {
"version": "file:src", "version": "file:src",

View File

@@ -1,3 +1,46 @@
## [4.10.7](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.6...v4.10.7) (2025-01-14)
### Bug Fixes
* editor crashed on exit play mode (editor, windows) ([47ee45c](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/47ee45cbbe651a8f87ca2b8a3948f8b88db8211e)), closes [#351](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/351)
## [4.10.6](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.5...v4.10.6) (2025-01-03)
### Bug Fixes
* sub-emitter particles may not render correctly in certain scenarios ([8276684](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/8276684c3b1646f0490ed64557547ba15281664a)), closes [#348](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/348)
* sub-emitter's `inherit velocity` module doubles at runtime ([67de3d1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/67de3d1bd3e16dc9b564625cb990c53d75769506)), closes [#349](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/349)
## [4.10.5](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.4...v4.10.5) (2024-12-23)
### Bug Fixes
* '3D' scale toggle in the inspector does not keep on reload ([934f4b8](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/934f4b8f1c61f8ff20228d0ebcea9f636a3758ed)), closes [#346](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/346)
## [4.10.4](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.3...v4.10.4) (2024-12-19)
### Bug Fixes
* rendering issues when playing with opening a prefab stage ([95235a9](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/95235a929b82cf681365ed6eba837d857f83e3d2)), closes [#345](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/345)
## [4.10.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.2...v4.10.3) (2024-11-20)
### Bug Fixes
* if not configured as a preloaded asset, the project settings asset will be regenerated ([abe0948](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/abe09485f65dd4efd18e74675e752e0213bdf3be)), closes [#342](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/342)
## [4.10.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.1...v4.10.2) (2024-11-01)
### Bug Fixes
* trail incorrect offset ([afe00a1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/afe00a1dde80eb1c0a7bb668b75f4c3733d3fa43)), closes [#335](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/335)
## [4.10.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.0...v4.10.1) (2024-09-29) ## [4.10.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.0...v4.10.1) (2024-09-29)

View File

@@ -28,6 +28,11 @@ namespace Coffee.UIExtensions
[CanEditMultipleObjects] [CanEditMultipleObjects]
internal class UIParticleEditor : GraphicEditor internal class UIParticleEditor : GraphicEditor
{ {
internal class State : ScriptableSingleton<State>
{
public bool is3DScaleMode;
}
//################################ //################################
// Constant or Static Members. // Constant or Static Members.
//################################ //################################
@@ -46,7 +51,6 @@ namespace Coffee.UIExtensions
private static readonly GUIContent s_ContentPrimary = new GUIContent("Primary"); private static readonly GUIContent s_ContentPrimary = new GUIContent("Primary");
private static readonly Regex s_RegexBuiltInGuid = new Regex(@"^0{16}.0{15}$", RegexOptions.Compiled); private static readonly Regex s_RegexBuiltInGuid = new Regex(@"^0{16}.0{15}$", RegexOptions.Compiled);
private static readonly List<Material> s_TempMaterials = new List<Material>(); private static readonly List<Material> s_TempMaterials = new List<Material>();
private static bool s_XYZMode;
private SerializedProperty _maskable; private SerializedProperty _maskable;
private SerializedProperty _scale3D; private SerializedProperty _scale3D;
@@ -60,6 +64,7 @@ namespace Coffee.UIExtensions
private SerializedProperty _customViewSize; private SerializedProperty _customViewSize;
private ReorderableList _ro; private ReorderableList _ro;
private bool _showMax; private bool _showMax;
private bool _is3DScaleMode;
private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>(); private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>();
#if UNITY_2018 || UNITY_2019 #if UNITY_2018 || UNITY_2019
@@ -163,6 +168,19 @@ namespace Coffee.UIExtensions
uip.RefreshParticles(uip.particles); uip.RefreshParticles(uip.particles);
} }
} }
// Initialize 3D scale mode.
_is3DScaleMode = State.instance.is3DScaleMode;
if (!_is3DScaleMode)
{
var x = _scale3D.FindPropertyRelative("x");
var y = _scale3D.FindPropertyRelative("y");
var z = _scale3D.FindPropertyRelative("z");
_is3DScaleMode = !Mathf.Approximately(x.floatValue, y.floatValue) ||
!Mathf.Approximately(y.floatValue, z.floatValue) ||
y.hasMultipleDifferentValues ||
z.hasMultipleDifferentValues;
}
} }
/// <summary> /// <summary>
@@ -181,7 +199,11 @@ namespace Coffee.UIExtensions
// Scale // Scale
EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4); EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4);
s_XYZMode = DrawFloatOrVector3Field(_scale3D, s_XYZMode); if (DrawFloatOrVector3Field(_scale3D, _is3DScaleMode) != _is3DScaleMode)
{
State.instance.is3DScaleMode = _is3DScaleMode = !_is3DScaleMode;
}
EditorGUI.EndDisabledGroup(); EditorGUI.EndDisabledGroup();
// AnimatableProperties // AnimatableProperties

Binary file not shown.

View File

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

View File

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

View File

@@ -1,125 +0,0 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.UI;
namespace Coffee.UIParticleInternal
{
/// <summary>
/// Extension methods for Graphic class.
/// </summary>
internal static class GraphicExtensions
{
private static readonly Vector3[] s_WorldCorners = new Vector3[4];
private static readonly Bounds s_ScreenBounds = new Bounds(new Vector3(0.5f, 0.5f, 0.5f), new Vector3(1, 1, 1));
/// <summary>
/// Check if a Graphic component is currently in the screen view.
/// </summary>
public static void GetMaterialsForRendering(this Graphic self, List<Material> result)
{
result.Clear();
if (!self) return;
var cr = self.canvasRenderer;
var count = cr.materialCount;
var popCount = cr.popMaterialCount;
if (result.Capacity < count + popCount)
{
result.Capacity = count + popCount;
}
for (var i = 0; i < count; i++)
{
result.Add(cr.GetMaterial(i));
}
for (var i = 0; i < popCount; i++)
{
result.Add(cr.GetPopMaterial(i));
}
}
/// <summary>
/// Check if a Graphic component is currently in the screen view.
/// </summary>
public static bool IsInScreen(this Graphic self)
{
if (!self || !self.canvas) return false;
if (FrameCache.TryGet(self, nameof(IsInScreen), out bool result))
{
return result;
}
Profiler.BeginSample("(COF)[GraphicExt] IsInScreen");
var cam = self.canvas.renderMode != RenderMode.ScreenSpaceOverlay
? self.canvas.worldCamera
: null;
var min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
var max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
self.rectTransform.GetWorldCorners(s_WorldCorners);
var screenSize = GetScreenSize();
for (var i = 0; i < 4; i++)
{
if (cam)
{
s_WorldCorners[i] = cam.WorldToViewportPoint(s_WorldCorners[i]);
}
else
{
s_WorldCorners[i] = RectTransformUtility.WorldToScreenPoint(null, s_WorldCorners[i]);
s_WorldCorners[i].x /= screenSize.x;
s_WorldCorners[i].y /= screenSize.y;
}
s_WorldCorners[i].z = 0;
min = Vector3.Min(s_WorldCorners[i], min);
max = Vector3.Max(s_WorldCorners[i], max);
}
var bounds = new Bounds(min, Vector3.zero);
bounds.Encapsulate(max);
result = bounds.Intersects(s_ScreenBounds);
FrameCache.Set(self, nameof(IsInScreen), result);
Profiler.EndSample();
return result;
}
/// <summary>
/// Get the actual main texture of a Graphic component.
/// </summary>
public static Texture GetActualMainTexture(this Graphic self)
{
var image = self as Image;
if (image == null) return self.mainTexture;
var sprite = image.overrideSprite;
return sprite ? sprite.GetActualTexture() : self.mainTexture;
}
private static Vector2Int GetScreenSize()
{
#if UNITY_EDITOR
if (!Application.isPlaying && !Camera.current)
{
var res = UnityStats.screenRes.Split('x');
return new Vector2Int(int.Parse(res[0]), int.Parse(res[1]));
}
#endif
return new Vector2Int(Screen.width, Screen.height);
}
public static float GetParentGroupAlpha(this Graphic self)
{
var alpha = self.canvasRenderer.GetAlpha();
if (Mathf.Approximately(alpha, 0)) return 1;
var inheritedAlpha = self.canvasRenderer.GetInheritedAlpha();
return Mathf.Clamp01(inheritedAlpha / alpha);
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 3803b037cd2ed45459dd660072f223dd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,6 +9,8 @@ using UnityEngine.UI;
using Random = UnityEngine.Random; using Random = UnityEngine.Random;
[assembly: InternalsVisibleTo("Coffee.UIParticle.Editor")] [assembly: InternalsVisibleTo("Coffee.UIParticle.Editor")]
[assembly: InternalsVisibleTo("Coffee.UIParticle.PerformanceDemo")]
[assembly: InternalsVisibleTo("Coffee.UIParticle.Demo")]
namespace Coffee.UIExtensions namespace Coffee.UIExtensions
{ {
@@ -575,12 +577,14 @@ namespace Coffee.UIExtensions
{ {
var ps = particleSystems[i]; var ps = particleSystems[i];
if (!ps) continue; if (!ps) continue;
GetRenderer(j++).Set(this, ps, false);
var mainEmitter = ps.GetMainEmitter(particleSystems);
GetRenderer(j++).Set(this, ps, false, mainEmitter);
// If the trail is enabled, set it additionally. // If the trail is enabled, set it additionally.
if (ps.trails.enabled) if (ps.trails.enabled)
{ {
GetRenderer(j++).Set(this, ps, true); GetRenderer(j++).Set(this, ps, true, mainEmitter);
} }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,11 @@
{
"MonoBehaviour": {
"m_Enabled": true,
"m_EditorHideFlags": 0,
"m_Name": "",
"m_EditorClassIdentifier": "",
"m_OutputDllPaths": [
"Packages/com.coffee.ui-particle/Runtime/Coffee.UIParticle.R.dll"
]
}
}