You've already forked ParticleEffectForUGUI
mirror of
https://github.com/mob-sakai/ParticleEffectForUGUI.git
synced 2026-06-29 10:55:09 +00:00
Compare commits
11 Commits
e32120b18c
...
5.0.0-prev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
73d208e9b8 | ||
|
|
bfac4d4e2f | ||
|
|
88d956ece8 | ||
|
|
2842b3db7d | ||
|
|
c2958d5d7d | ||
|
|
7456b5d555 | ||
|
|
9955eefdc2 | ||
|
|
c09bfb81ab | ||
|
|
fab2ed1697 | ||
|
|
ef4dbc3cba | ||
|
|
27551a4d47 |
28
.github/workflows/deploy.yml
vendored
Normal file
28
.github/workflows/deploy.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: 🚀 Deploy with Zip
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
zip:
|
||||
description: "The url to the zip file"
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
name: 🚀 Deploy
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pages: write
|
||||
id-token: write
|
||||
steps:
|
||||
- name: 📦 Download zip file To '_site'
|
||||
run: |
|
||||
curl -L ${{ github.event.inputs.zip }} -o _site.zip
|
||||
unzip _site.zip -d _site
|
||||
find _site -name __MACOSX | xargs rm -rf
|
||||
|
||||
- name: 📦 Upload '_site'
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
|
||||
- name: 🚀 Deploy To GitHub Pages
|
||||
uses: actions/deploy-pages@v4
|
||||
71
.github/workflows/release.yml
vendored
71
.github/workflows/release.yml
vendored
@@ -5,8 +5,9 @@ on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- release
|
||||
- release-*
|
||||
- preview
|
||||
- main
|
||||
- v*.x
|
||||
tags-ignore:
|
||||
- "**"
|
||||
|
||||
@@ -22,15 +23,12 @@ jobs:
|
||||
channel: ${{ steps.release.outputs.new_release_channel }}
|
||||
released: ${{ steps.release.outputs.new_release_published }}
|
||||
tag: ${{ steps.release.outputs.new_release_git_tag }}
|
||||
version: ${{ steps.release.outputs.new_release_version }}
|
||||
merge_to: ${{ steps.summary.outputs.merge_to }}
|
||||
split_to: ${{ steps.summary.outputs.split_to }}
|
||||
steps:
|
||||
- name: 🚚 Checkout (${{ github.ref_name }})
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 🔖 Run semantic release
|
||||
uses: cycjimmy/semantic-release-action@v6
|
||||
uses: cycjimmy/semantic-release-action@v4
|
||||
id: release
|
||||
with:
|
||||
working_directory: Packages/src
|
||||
@@ -38,64 +36,9 @@ jobs:
|
||||
@semantic-release/changelog
|
||||
@semantic-release/git
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
- id: summary
|
||||
run: |
|
||||
- run: |
|
||||
echo "🔖 New release published: '${{ steps.release.outputs.new_release_published }}'" | tee -a $GITHUB_STEP_SUMMARY
|
||||
echo "🔖 New release version: '${{ steps.release.outputs.new_release_version }}'" | tee -a $GITHUB_STEP_SUMMARY
|
||||
echo "🔖 New release channel: '${{ steps.release.outputs.new_release_channel }}'" | tee -a $GITHUB_STEP_SUMMARY
|
||||
echo "🔖 New release git tag: '${{ steps.release.outputs.new_release_git_tag }}'" | tee -a $GITHUB_STEP_SUMMARY
|
||||
|
||||
if [ '${{ steps.release.outputs.new_release_published }}' = 'false' ]; then
|
||||
echo "No new release published." | tee -a $GITHUB_STEP_SUMMARY
|
||||
elif [ '${{ github.ref_name }}' = 'release' ]; then
|
||||
echo "merge_to=develop" | tee -a $GITHUB_OUTPUT $GITHUB_STEP_SUMMARY
|
||||
echo "split_to=main" | tee -a $GITHUB_OUTPUT $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
channel=$(echo ${{ github.ref_name }} | sed 's/^release-//')
|
||||
echo "merge_to=develop-${channel}" | tee -a $GITHUB_OUTPUT $GITHUB_STEP_SUMMARY
|
||||
echo "split_to=${channel}" | tee -a $GITHUB_OUTPUT $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
merge-to:
|
||||
if: needs.release.outputs.merge_to != ''
|
||||
needs: release
|
||||
name: 🔀 Merge to ${{ needs.release.outputs.merge_to }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: 🚚 Checkout (${{ needs.release.outputs.merge_to }})
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ needs.release.outputs.merge_to }}
|
||||
fetch-depth: 0
|
||||
- name: 🔀 Merge '${{ needs.release.outputs.tag }}' into '${{ needs.release.outputs.merge_to }}'
|
||||
run: |
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
|
||||
git merge ${{ needs.release.outputs.tag }}
|
||||
git push origin ${{ needs.release.outputs.merge_to }}
|
||||
|
||||
split-to:
|
||||
if: needs.release.outputs.split_to != ''
|
||||
needs: release
|
||||
name: 🔀 Split package to ${{ needs.release.outputs.split_to }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: 🚚 Checkout (${{ needs.release.outputs.tag }})
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ needs.release.outputs.tag }}
|
||||
fetch-depth: 0
|
||||
- name: 🔀 Split subtree 'Packages/src' to '${{ needs.release.outputs.split_to }}'
|
||||
run: |
|
||||
split_to=${{ needs.release.outputs.split_to }}
|
||||
git branch $split_to origin/$split_to
|
||||
git subtree split --prefix=Packages/src --branch $split_to
|
||||
git tag ${{ needs.release.outputs.version }} $split_to
|
||||
git push origin ${{ needs.release.outputs.version }} $split_to:$split_to
|
||||
|
||||
59
.github/workflows/test.yml
vendored
59
.github/workflows/test.yml
vendored
@@ -7,10 +7,9 @@ run-name: 🧪 Test (${{ github.event.pull_request.title || github.ref_name }})
|
||||
|
||||
env:
|
||||
# MINIMUM_VERSION: The minimum version of Unity.
|
||||
MINIMUM_VERSION: 2020.3
|
||||
MINIMUM_VERSION: 2019.4
|
||||
# EXCLUDE_FILTER: The excluded versions of Unity.
|
||||
EXCLUDE_FILTER: "(2017|2018|2023.3)"
|
||||
PROJECT_PATH: .
|
||||
EXCLUDE_FILTER: "(2020.2.0|2021.1|2023.3)"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -22,12 +21,12 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
- "develop-*"
|
||||
- develop-preview
|
||||
tags:
|
||||
- "!*"
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
@@ -39,29 +38,16 @@ jobs:
|
||||
setup:
|
||||
name: ⚙️ Setup
|
||||
runs-on: ubuntu-latest
|
||||
permissions: {} # No permissions needed for setup job
|
||||
outputs:
|
||||
unityVersions: ${{ steps.setup.outputs.unityVersions }}
|
||||
steps:
|
||||
- name: 🔑 Secrets check
|
||||
run: |
|
||||
if [ -z "$UNITY_EMAIL" ] || [ -z "$UNITY_PASSWORD" ] || [ -z "UNITY_LICENSE" ]; then
|
||||
echo "Error: UNITY_EMAIL, UNITY_PASSWORD, and UNITY_LICENSE secrets must be set." | tee -a $GITHUB_STEP_SUMMARY >&2
|
||||
echo "Error: See https://game.ci/docs/github/test-runner#basic-setup" | tee -a $GITHUB_STEP_SUMMARY >&2
|
||||
echo "Error: Set the secrets at ${{ github.server_url }}/${{ github.repository }}/settings/secrets/actions" | tee -a $GITHUB_STEP_SUMMARY >&2
|
||||
exit 1
|
||||
fi
|
||||
env:
|
||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
- name: ⚙️ Find target Unity versions
|
||||
id: setup
|
||||
run: |
|
||||
echo "==== Target Unity Versions ===="
|
||||
LATEST_VERSIONS=`npx -y unity-changeset@latest list --json --versions --all --latest-patch --ignore-alpha --min ${MINIMUM_VERSION}`
|
||||
LATEST_VERSIONS=`npx unity-changeset@latest list --versions --latest-patch --min ${MINIMUM_VERSION} --json --all`
|
||||
if [ "${{ inputs.usePeriodVersions }}" = "true" ]; then
|
||||
ADDITIONAL_VERSIONS=`npx -y unity-changeset@latest list --json --versions --ignore-alpha --min ${MINIMUM_VERSION} --grep '0f'`
|
||||
ADDITIONAL_VERSIONS=`npx unity-changeset list --versions --grep '0f' --min ${MINIMUM_VERSION} --json`
|
||||
else
|
||||
ADDITIONAL_VERSIONS=[]
|
||||
fi
|
||||
@@ -79,31 +65,45 @@ jobs:
|
||||
needs: setup
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 8
|
||||
max-parallel: 6
|
||||
matrix:
|
||||
unityVersion: ${{ fromJson(needs.setup.outputs.unityVersions) }}
|
||||
steps:
|
||||
- name: 🚚 Checkout ($${{ github.ref }})
|
||||
uses: actions/checkout@v6
|
||||
if: github.event_name == 'push'
|
||||
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
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.PROJECT_PATH }}/Library
|
||||
key: ${{ env.PROJECT_PATH }}-Library-${{ matrix.unityVersion }}-${{ github.event.pull_request.head.sha || github.sha }}
|
||||
path: Library
|
||||
key: Library-${{ matrix.unityVersion }}-${{ github.event.pull_request.head.sha || github.sha }}
|
||||
restore-keys: |
|
||||
${{ env.PROJECT_PATH }}-Library-${{ matrix.unityVersion }}-
|
||||
${{ env.PROJECT_PATH }}-Library-
|
||||
Library-${{ matrix.unityVersion }}-
|
||||
Library-
|
||||
|
||||
- name: 🛠️ Build Unity Project (Test)
|
||||
uses: game-ci/unity-builder@v5
|
||||
uses: game-ci/unity-builder@v4
|
||||
timeout-minutes: 45
|
||||
with:
|
||||
customImage: ghcr.io/mob-sakai/unity3d:${{ matrix.unityVersion }}
|
||||
targetPlatform: StandaloneLinux64
|
||||
allowDirtyBuild: true
|
||||
customParameters: -nographics
|
||||
projectPath: ${{ env.PROJECT_PATH }}
|
||||
env:
|
||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||
@@ -118,7 +118,6 @@ jobs:
|
||||
customParameters: -nographics
|
||||
checkName: ${{ matrix.unityVersion }} Test Results
|
||||
githubToken: ${{ github.token }}
|
||||
projectPath: ${{ env.PROJECT_PATH }}
|
||||
env:
|
||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||
|
||||
@@ -18,12 +18,11 @@ MonoBehaviour:
|
||||
m_EnabledInEditor: 1
|
||||
m_AlwaysIncludeAssembly: 1
|
||||
m_InstantiateOnLoad: 1
|
||||
m_Prefab: {fileID: 4567906826058368312, guid: 7cebff2d255b9433cbe23b243c193329,
|
||||
m_Prefab: {fileID: 7211429669315726685, guid: b73940fc30a2f4eb9a73783e9c1f8da6,
|
||||
type: 3}
|
||||
m_Interval: 0.5
|
||||
m_Anchor: 0
|
||||
m_Width: 750
|
||||
m_HelpUrl: https://github.com/mob-sakai/ParticleEffectForUGUI
|
||||
m_CustomMonitorItems:
|
||||
- m_Format: Screen:{0}x{1}
|
||||
m_Arg0:
|
||||
|
||||
2465
Assets/ProjectSettings/NanoMonitor.prefab
Normal file
2465
Assets/ProjectSettings/NanoMonitor.prefab
Normal file
File diff suppressed because it is too large
Load Diff
7
Assets/ProjectSettings/NanoMonitor.prefab.meta
Normal file
7
Assets/ProjectSettings/NanoMonitor.prefab.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b73940fc30a2f4eb9a73783e9c1f8da6
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -10,7 +10,7 @@ MonoBehaviour:
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f22a23b9d98e440478697f4adf30e61c, type: 3}
|
||||
m_Name: UIParticleProjectSettings
|
||||
m_Name: UIParticle
|
||||
m_EditorClassIdentifier:
|
||||
m_EnableLinearToGamma: 1
|
||||
m_HideGeneratedObjects: 1
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5b9278dfbd194d04b1c6ae7031928c1
|
||||
guid: 4b9df7b8a4193489299b8f477348ae0c
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
@@ -1,21 +1,16 @@
|
||||
using System.Collections;
|
||||
using Coffee.UIParticleInternal;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Coffee.UIParticle.Editor.Tests
|
||||
{
|
||||
public class NewTestScript
|
||||
{
|
||||
[TestCase(-1)]
|
||||
[TestCase(0)]
|
||||
[TestCase(2048)]
|
||||
[TestCase(3000)]
|
||||
public void GetParticleArray(int requiredSize)
|
||||
// A Test behaves as an ordinary method
|
||||
[Test]
|
||||
public void NewTestScriptSimplePasses()
|
||||
{
|
||||
var array = ParticleSystemExtensions.GetParticleArray(requiredSize);
|
||||
Debug.Log($"requiredSize: {requiredSize}, array.Length: {array.Length}");
|
||||
// Use the Assert class to test conditions
|
||||
}
|
||||
|
||||
// A UnityTest behaves like a coroutine in Play Mode. In Edit Mode you can use
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"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.unity.ide.rider": "3.0.36",
|
||||
"com.unity.ide.rider": "3.0.31",
|
||||
"com.unity.test-framework": "1.1.33",
|
||||
"com.unity.modules.animation": "1.0.0",
|
||||
"com.unity.modules.physics": "1.0.0"
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
"depth": 0,
|
||||
"source": "git",
|
||||
"dependencies": {},
|
||||
"hash": "3c280f1a8f4db5038b881ff07f270efd9638fa31"
|
||||
"hash": "52987fb6e66e7fc48498d8d164c3c8808de4de6b"
|
||||
},
|
||||
"com.coffee.minimal-resource": {
|
||||
"version": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/MinimalResource",
|
||||
"depth": 0,
|
||||
"source": "git",
|
||||
"dependencies": {},
|
||||
"hash": "3c280f1a8f4db5038b881ff07f270efd9638fa31"
|
||||
"hash": "52987fb6e66e7fc48498d8d164c3c8808de4de6b"
|
||||
},
|
||||
"com.coffee.nano-monitor": {
|
||||
"version": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/NanoMonitor",
|
||||
@@ -21,7 +21,7 @@
|
||||
"dependencies": {
|
||||
"com.unity.ugui": "1.0.0"
|
||||
},
|
||||
"hash": "3c280f1a8f4db5038b881ff07f270efd9638fa31"
|
||||
"hash": "52987fb6e66e7fc48498d8d164c3c8808de4de6b"
|
||||
},
|
||||
"com.coffee.ui-particle": {
|
||||
"version": "file:src",
|
||||
@@ -40,7 +40,7 @@
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.ide.rider": {
|
||||
"version": "3.0.36",
|
||||
"version": "3.0.31",
|
||||
"depth": 0,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
{
|
||||
"branches": [
|
||||
"release",
|
||||
"release-4.x",
|
||||
"main",
|
||||
"[0-9]+.x",
|
||||
{
|
||||
"name": "release-preview",
|
||||
"prerelease": "preview"
|
||||
"name": "preview",
|
||||
"prerelease": true
|
||||
}
|
||||
],
|
||||
"tagFormat": "${version}",
|
||||
"plugins": [
|
||||
"@semantic-release/commit-analyzer",
|
||||
"@semantic-release/release-notes-generator",
|
||||
|
||||
@@ -1,75 +1,17 @@
|
||||
## [4.12.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.12.1...v4.12.2) (2026-06-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add `meshCleared` flag to optimize mesh clearing ([859fa20](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/859fa20d297c3f44e3361f20dbb7ce966407e03e))
|
||||
* fix Unity6.5 compile errors and warnings ([a5ee687](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/a5ee6878212be2fc4d7b48879426f239e8753009)), closes [#400](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/400)
|
||||
* potential access to UIParticleRenderer that has already been destroyed ([b740dd6](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/b740dd662d423c6bef849662ce1b0bfbb4940ed4)), closes [#403](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/403)
|
||||
* updated support for some changed menu paths ([f8ac986](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/f8ac9869f141238169730e74f5d65c4fc6081f51)), closes [#397](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/397)
|
||||
|
||||
## [4.12.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.12.0...v4.12.1) (2026-03-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ignore "EditorOnly" tagged gameObjects on refresh ([031d46a](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/031d46a3216c942d2d1a6ccfadf5f0b9e3ce3006))
|
||||
|
||||
# [4.12.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.4...v4.12.0) (2026-03-24)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* explicit null checks ([5384f61](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/5384f61c569e9f78ff9d5b45acfc6f5c2f021a87))
|
||||
|
||||
## [4.11.4](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.3...v4.11.4) (2025-12-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add early return for case where subEmitter module is disabled ([d1386a1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/d1386a12216743a6e09f1b9b87bea1dfcf7702e4))
|
||||
* avoid endless loop ([eb2e862](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/eb2e862e80e549c8cf16ddfed776c101c2413bac)), closes [#392](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/392)
|
||||
|
||||
## [4.11.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.2...v4.11.3) (2025-10-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix icon ([a9461ec](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/a9461ecb4d40d7fe878e12465d6e38faae7ae65b))
|
||||
* fix URL link in README ([1c8c65d](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/1c8c65d25e7f6fe7b1d20da4461333df8fc7578e)), closes [#376](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/376)
|
||||
* fix: second and subsequent bursts not displayed when world simulation and non-looping ([df2f3ca](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/df2f3caafbe279f1457d74f8183cb561ac14aa17)), closes [#326](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/326)
|
||||
* UIParticle in canvas with 0f-0.01f alpha value does not start to play until alpha value is greater than 0.01f, causes play calls to be delayed unintentionally if canvas alpha value is set to mentioned value range ([38aec2e](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/38aec2ea1afd77677d629c86665a3342d92e49d9))
|
||||
|
||||
## [4.11.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.1...v4.11.2) (2025-03-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* IL2CPP build fails on older versions of Unity ([0da6525](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/0da652520cd165b43de7404c0b0ab1fbcf9349d1))
|
||||
* NRE on enable ([0cff50e](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/0cff50ef696aa53fb7c46a9a737b7cf3a05b7b9b)), closes [#359](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/359)
|
||||
|
||||
## [4.11.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.0...v4.11.1) (2025-02-21)
|
||||
# [5.0.0-preview.15](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/5.0.0-preview.14...5.0.0-preview.15) (2025-02-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* component icons will no longer be displayed in the scene view ([6dfbdae](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/6dfbdae38d3822ab9c2c6f0e4ca1ca32ee98a239))
|
||||
|
||||
# [4.11.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.7...v4.11.0) (2025-02-21)
|
||||
* 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)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add 'TimeScaleMultiplier' option ([925af0b](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/925af0b6046f65f23a778f67cefa8ff9cbedb513))
|
||||
|
||||
## [4.10.7](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.6...v4.10.7) (2025-01-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* editor crashed on exit play mode (editor, windows) ([47ee45c](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/47ee45cbbe651a8f87ca2b8a3948f8b88db8211e)), closes [#351](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/351)
|
||||
|
||||
## [4.10.6](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.5...v4.10.6) (2025-01-03)
|
||||
# [5.0.0-preview.14](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/5.0.0-preview.13...5.0.0-preview.14) (2025-01-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
@@ -77,6 +19,19 @@
|
||||
* 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)
|
||||
|
||||
# [5.0.0-preview.13](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/5.0.0-preview.12...5.0.0-preview.13) (2025-01-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* change the default value of `UIParticle.scale` from `10` to `1` ([9955eef](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/9955eefdc22cf565502f85c87cd2efd3a25fbe50))
|
||||
* UIParticle no longer inherits from MaskableGraphic ([c09bfb8](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c09bfb81abc9179bf5fc49d29eaf7fc4ed01a4dc))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* Some members inherited from MaskableGraphic will no longer be available.
|
||||
|
||||
## [4.10.5](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.4...v4.10.5) (2024-12-23)
|
||||
|
||||
|
||||
|
||||
@@ -76,21 +76,12 @@ namespace Coffee.UIExtensions
|
||||
for (var j = 0; j < mats.Count; j++)
|
||||
{
|
||||
var mat = mats[j];
|
||||
if (mat == null || mat.shader == null) continue;
|
||||
if (!mat || !mat.shader) continue;
|
||||
|
||||
#if UNITY_6000_5_OR_NEWER
|
||||
for (var i = 0; i < mat.shader.GetPropertyCount(); i++)
|
||||
#else
|
||||
for (var i = 0; i < ShaderUtil.GetPropertyCount(mat.shader); i++)
|
||||
#endif
|
||||
{
|
||||
#if UNITY_6000_5_OR_NEWER
|
||||
var name = mat.shader.GetPropertyName(i);
|
||||
var type = (AnimatableProperty.ShaderPropertyType)mat.shader.GetPropertyType(i);
|
||||
#else
|
||||
var name = ShaderUtil.GetPropertyName(mat.shader, i);
|
||||
var type = (AnimatableProperty.ShaderPropertyType)ShaderUtil.GetPropertyType(mat.shader, i);
|
||||
#endif
|
||||
if (!s_Names.Add(name)) continue;
|
||||
|
||||
AddMenu(gm, sp, new ShaderProperty(name, type), true);
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UI;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
using UnityEngine.UI;
|
||||
using Coffee.UIParticleInternal;
|
||||
using Object = UnityEngine.Object;
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
using UnityEditor.Overlays;
|
||||
#else
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Object = UnityEngine.Object;
|
||||
#endif
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
using UnityEditor.SceneManagement;
|
||||
@@ -26,7 +25,7 @@ namespace Coffee.UIExtensions
|
||||
{
|
||||
[CustomEditor(typeof(UIParticle))]
|
||||
[CanEditMultipleObjects]
|
||||
internal class UIParticleEditor : GraphicEditor
|
||||
internal class UIParticleEditor : Editor
|
||||
{
|
||||
internal class State : ScriptableSingleton<State>
|
||||
{
|
||||
@@ -66,7 +65,6 @@ namespace Coffee.UIExtensions
|
||||
private ReorderableList _ro;
|
||||
private bool _showMax;
|
||||
private bool _is3DScaleMode;
|
||||
private GameObject[] _gameObjects;
|
||||
|
||||
private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>();
|
||||
#if UNITY_2018 || UNITY_2019
|
||||
@@ -88,10 +86,8 @@ namespace Coffee.UIExtensions
|
||||
/// <summary>
|
||||
/// This function is called when the object becomes enabled and active.
|
||||
/// </summary>
|
||||
protected override void OnEnable()
|
||||
private void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
_maskable = serializedObject.FindProperty("m_Maskable");
|
||||
_scale3D = serializedObject.FindProperty("m_Scale3D");
|
||||
_animatableProperties = serializedObject.FindProperty("m_AnimatableProperties");
|
||||
@@ -111,7 +107,7 @@ namespace Coffee.UIExtensions
|
||||
{
|
||||
var ps = sp.GetArrayElementAtIndex(index).objectReferenceValue as ParticleSystem;
|
||||
var materialCount = 0;
|
||||
if (ps != null && ps.TryGetComponent<ParticleSystemRenderer>(out var psr))
|
||||
if (ps && ps.TryGetComponent<ParticleSystemRenderer>(out var psr))
|
||||
{
|
||||
materialCount = psr.sharedMaterials.Length;
|
||||
}
|
||||
@@ -125,7 +121,7 @@ namespace Coffee.UIExtensions
|
||||
var p = sp.GetArrayElementAtIndex(index);
|
||||
EditorGUI.ObjectField(rect, p, GUIContent.none);
|
||||
var ps = p.objectReferenceValue as ParticleSystem;
|
||||
if (ps == null || !ps.TryGetComponent<ParticleSystemRenderer>(out var psr)) return;
|
||||
if (!ps || !ps.TryGetComponent<ParticleSystemRenderer>(out var psr)) return;
|
||||
|
||||
rect.x += 15;
|
||||
rect.width -= 15;
|
||||
@@ -184,13 +180,6 @@ namespace Coffee.UIExtensions
|
||||
y.hasMultipleDifferentValues ||
|
||||
z.hasMultipleDifferentValues;
|
||||
}
|
||||
|
||||
// Add temporary ParticleSystem for preview if enabled.
|
||||
if (UIParticleProjectSettings.s_PreviewOnSelectOnSelect)
|
||||
{
|
||||
_gameObjects = targets.OfType<UIParticle>().Select(x => x.gameObject).ToArray();
|
||||
ParticleSystemPreviewSystem.Register(_gameObjects);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -199,16 +188,13 @@ namespace Coffee.UIExtensions
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
var current = target as UIParticle;
|
||||
if (current == null) return;
|
||||
if (!current) return;
|
||||
|
||||
Profiler.BeginSample("(UIP:E) OnInspectorGUI");
|
||||
serializedObject.Update();
|
||||
|
||||
// Maskable
|
||||
if (_maskable != null)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_maskable);
|
||||
}
|
||||
EditorGUILayout.PropertyField(_maskable);
|
||||
|
||||
// Scale
|
||||
EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4);
|
||||
@@ -278,7 +264,7 @@ namespace Coffee.UIExtensions
|
||||
Profiler.BeginSample("(UIP:E) Non-UI built-in shader is not supported.");
|
||||
foreach (var mat in s_TempMaterials)
|
||||
{
|
||||
if (mat == null || mat.shader == null) continue;
|
||||
if (!mat || !mat.shader) continue;
|
||||
var shader = mat.shader;
|
||||
if (IsBuiltInObject(shader) && !shader.name.StartsWith("UI/"))
|
||||
{
|
||||
@@ -297,7 +283,7 @@ namespace Coffee.UIExtensions
|
||||
{
|
||||
foreach (var mat in s_TempMaterials)
|
||||
{
|
||||
if (mat == null || mat.shader == null) continue;
|
||||
if (!mat || !mat.shader) continue;
|
||||
var shader = mat.shader;
|
||||
if (!s_Shaders.Add(shader)) continue;
|
||||
|
||||
@@ -355,10 +341,6 @@ namespace Coffee.UIExtensions
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Remove the temporary ParticleSystem.
|
||||
ParticleSystemPreviewSystem.DrawWarningForTemporary(_gameObjects);
|
||||
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
@@ -479,9 +461,11 @@ namespace Coffee.UIExtensions
|
||||
{
|
||||
if (!p || (ignoreCurrent && target == p)) return;
|
||||
|
||||
var cr = p.canvasRenderer;
|
||||
DestroyImmediate(p);
|
||||
DestroyImmediate(cr);
|
||||
Misc.DestroyImmediate(p);
|
||||
if (p.TryGetComponent<CanvasRenderer>(out var cr))
|
||||
{
|
||||
Misc.DestroyImmediate(cr);
|
||||
}
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
var stage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
@@ -497,7 +481,7 @@ namespace Coffee.UIExtensions
|
||||
#endif
|
||||
}
|
||||
|
||||
private static bool FixButton(bool show, string text, GUIContent buttonText = null)
|
||||
private static bool FixButton(bool show, string text)
|
||||
{
|
||||
if (!show) return false;
|
||||
using (new EditorGUILayout.HorizontalScope(GUILayout.ExpandWidth(true)))
|
||||
@@ -505,7 +489,7 @@ namespace Coffee.UIExtensions
|
||||
EditorGUILayout.HelpBox(text, MessageType.Warning, true);
|
||||
using (new EditorGUILayout.VerticalScope())
|
||||
{
|
||||
return GUILayout.Button(buttonText ?? s_ContentFix, GUILayout.ExpandWidth(false));
|
||||
return GUILayout.Button(s_ContentFix, GUILayout.Width(30));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,22 +6,11 @@ namespace Coffee.UIExtensions
|
||||
{
|
||||
internal class UIParticleMenu
|
||||
{
|
||||
#if UNITY_6000_5_OR_NEWER
|
||||
private const string k_MenuPathToCreateParticleSystem = "GameObject/Visual Effects/Particle System";
|
||||
#else
|
||||
private const string k_MenuPathToCreateParticleSystem = "GameObject/Effects/Particle System";
|
||||
#endif
|
||||
#if UNITY_6000_3_OR_NEWER
|
||||
private const string k_MenuPathForUgui = "GameObject/UI (Canvas)";
|
||||
#else
|
||||
private const string k_MenuPathForUgui = "GameObject/UI";
|
||||
#endif
|
||||
|
||||
[MenuItem(k_MenuPathForUgui + "/Particle System (Empty)", false, 2018)]
|
||||
[MenuItem("GameObject/UI/Particle System (Empty)", false, 2018)]
|
||||
private static void AddParticleEmpty(MenuCommand menuCommand)
|
||||
{
|
||||
// Create empty UI element.
|
||||
EditorApplication.ExecuteMenuItem(k_MenuPathForUgui + "/Image");
|
||||
EditorApplication.ExecuteMenuItem("GameObject/UI/Image");
|
||||
var ui = Selection.activeGameObject;
|
||||
Object.DestroyImmediate(ui.GetComponent<Image>());
|
||||
|
||||
@@ -32,7 +21,7 @@ namespace Coffee.UIExtensions
|
||||
uiParticle.rectTransform.sizeDelta = Vector2.zero;
|
||||
}
|
||||
|
||||
[MenuItem(k_MenuPathForUgui + "/Particle System", false, 2019)]
|
||||
[MenuItem("GameObject/UI/Particle System", false, 2019)]
|
||||
private static void AddParticle(MenuCommand menuCommand)
|
||||
{
|
||||
// Create empty UIEffect.
|
||||
@@ -40,7 +29,7 @@ namespace Coffee.UIExtensions
|
||||
var uiParticle = Selection.activeGameObject.GetComponent<UIParticle>();
|
||||
|
||||
// Create ParticleSystem.
|
||||
EditorApplication.ExecuteMenuItem(k_MenuPathToCreateParticleSystem);
|
||||
EditorApplication.ExecuteMenuItem("GameObject/Effects/Particle System");
|
||||
var ps = Selection.activeGameObject;
|
||||
ps.transform.SetParent(uiParticle.transform, false);
|
||||
ps.transform.localPosition = Vector3.zero;
|
||||
|
||||
8
Packages/src/Icons.meta
Normal file
8
Packages/src/Icons.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a55e246f37df405bac88eac692e3a86
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
Before Width: | Height: | Size: 418 B After Width: | Height: | Size: 418 B |
@@ -1,9 +1,9 @@
|
||||
# <img alt="UIParticleIcon" src="https://github.com/mob-sakai/ParticleEffectForUGUI/assets/12690315/d76e105e-a840-4f61-a1f6-8cf311c0812d" width="26"/> Particle Effect For UGUI (UI Particle) <!-- omit in toc -->
|
||||
# <img alt="UIParticleIcon" src="https://github.com/mob-sakai/ParticleEffectForUGUI/assets/12690315/d76e105e-a840-4f61-a1f6-8cf311c0812d" width="26"/> UI Particle v5 <!-- omit in toc -->
|
||||
|
||||
[](https://openupm.com/packages/com.coffee.ui-particle/)
|
||||
[](https://github.com/mob-sakai/ParticleEffectForUGUI/releases)
|
||||
[](https://github.com/mob-sakai/ParticleEffectForUGUI/blob/main/LICENSE.md)
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
@@ -11,7 +11,7 @@
|
||||
[](https://github.com/mob-sakai/ParticleEffectForUGUI/subscription)
|
||||
[](https://twitter.com/intent/follow?screen_name=mob_sakai)
|
||||
|
||||
<< [📝 Description](#-description-) | [📌 Key Features](#-key-features) | [🎮 Demo](#-demo) | [⚙ Installation](#-installation) | [🚀 Usage](#-usage) | [🛠 Development Note](#-development-note) | [🤝 Contributing](#-contributing) >>
|
||||
<< [📝 Description](#-description-) | [📌 Key Features](#-key-features) | [🎮 Demo](#-demo) | [⚙ Installation](#-installation) | [🔄 Upgrading to 5.x](#-upgrading-from-3x4x-to-5x) | [🚀 Usage](#-usage) | [🛠 Development Note](#-development-note) | [🤝 Contributing](#-contributing) >>
|
||||
|
||||
## 📝 Description <!-- omit in toc -->
|
||||
|
||||
@@ -26,7 +26,9 @@ You can render, mask, and sort your `ParticleSystems` for UI without the need fo
|
||||
- [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)
|
||||
- [Install as Embedded Package](#install-as-embedded-package)
|
||||
- [🔄 Upgrading from v3/v4 to v5](#-upgrading-from-v3v4-to-v5)
|
||||
- [Breaking Changes](#breaking-changes)
|
||||
- [🚀 Usage](#-usage)
|
||||
- [Component: UIParticle](#component-uiparticle)
|
||||
- [Basic Usage](#basic-usage)
|
||||
@@ -104,7 +106,7 @@ You can render, mask, and sort your `ParticleSystems` for UI without the need fo
|
||||
|
||||
## ⚙ Installation
|
||||
|
||||
_This package requires **Unity 2018.3 or later**._
|
||||
_This package requires **Unity 2019.3 or later**._
|
||||
|
||||
#### Install via OpenUPM
|
||||
|
||||
@@ -116,16 +118,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}`:
|
||||
```
|
||||
openupm add com.coffee.ui-particle@4.9.0
|
||||
openupm add com.coffee.ui-particle@5.0.0
|
||||
```
|
||||
|
||||
#### Install via UPM (with 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?path=Packages/src`
|
||||

|
||||
- To update the package, change suffix `#{version}` to the target version.
|
||||
- e.g. `https://github.com/mob-sakai/ParticleEffectForUGUI.git#4.9.0`
|
||||
- e.g. `https://github.com/mob-sakai/ParticleEffectForUGUI.git?path=Packages/src#5.0.0`
|
||||
|
||||
#### Install via UPM (Manually)
|
||||
|
||||
@@ -133,22 +135,41 @@ _This package requires **Unity 2018.3 or later**._
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git",
|
||||
"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git?path=Packages/src",
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- To update the package, change suffix `#{version}` to the target version.
|
||||
- e.g. `"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git#4.9.0",`
|
||||
- e.g. `"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git?path=Packages/src#5.0.0",`
|
||||
|
||||
#### Install as Embedded Package
|
||||
### Install as Embedded Package
|
||||
|
||||
1. Download a source code zip file from [Releases](https://github.com/mob-sakai/ParticleEffectForUGUI/releases) and extract it.
|
||||
2. Place it in your project's `Packages` directory.
|
||||

|
||||
- If you want to fix bugs or add features, install it as an embedded package.
|
||||
- To update the package, you need to re-download it and replace the contents.
|
||||
1. Download the `Source code (zip)` file from [Releases](https://github.com/mob-sakai/SoftMaskForUGUI/releases) and
|
||||
extract it.
|
||||
2. Move the `<extracted_dir>/Packages/src` directory into your project's `Packages` directory.
|
||||

|
||||
- You can rename the `src` directory if needed.
|
||||
- If you intend to fix bugs or add features, installing it as an embedded package is recommended.
|
||||
- To update the package, re-download it and replace the existing contents.
|
||||
|
||||
<br><br>
|
||||
|
||||
## 🔄 Upgrading from v3/v4 to v5
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- The default value of `UIParticle.scale` has been changed from `10` to `1`.
|
||||
- `UIParticle` no longer inherits from `MaskableGraphic`.
|
||||
- If you are installing via git URL, add `?path=Packages/src`.
|
||||
```json
|
||||
// v3/v4
|
||||
"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git",
|
||||
|
||||
// v5
|
||||
"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git?path=Packages/src",
|
||||
```
|
||||
|
||||
<br><br>
|
||||
|
||||
@@ -183,14 +204,9 @@ _This package requires **Unity 2018.3 or later**._
|
||||
- **Time Scale Multiplier:** Time scale multiplier.
|
||||
- **Rendering Order**: The ParticleSystem list to be rendered. You can change the order and the materials.
|
||||
|
||||
> [!TIPS]
|
||||
> Press the `Refresh` button to reconstruct the rendering order based on children ParticleSystem's sorting order
|
||||
**NOTE:** Press the `Refresh` button to reconstruct the rendering order based on children ParticleSystem's sorting order
|
||||
and z-position.
|
||||
|
||||
> [!TIPS]
|
||||
> When a `GameObject` with this component is selected in the editor, a temporary `ParticleSystem` is added if needed so you can preview the effect in the Scene view.
|
||||
> The generated `ParticleSystem` is marked with `HideFlags.DontSave`, so it is neither saved nor included in builds.
|
||||
|
||||
<br><br>
|
||||
|
||||
### Basic Usage
|
||||
@@ -200,10 +216,6 @@ and z-position.
|
||||
2. Adjust the ParticleSystem as you like.
|
||||

|
||||
|
||||
> [!Tips]
|
||||
> Adding a `UIParticle` to the parent is the recommended setup rather than attaching it directly to the `ParticleSystem`.
|
||||
> When using `ParticleSystem.emission.rateOverDistance`, it is recommended to move the transform of `UIParticle` rather than the `ParticleSystem`.
|
||||
|
||||
<br>
|
||||
|
||||
### Usage with Your Existing ParticleSystem Prefab
|
||||
@@ -265,34 +277,13 @@ uiParticle.Stop();
|
||||
- **Unscaled Time:** Update with unscaled delta time.
|
||||
- **OnAttracted**: An event called when attracting is complete (per particle).
|
||||
|
||||
|
||||
<br><br>
|
||||
|
||||
### Component: ParticleSystemPreviewer
|
||||
|
||||
`ParticleSystemPreviewer` is used to preview a ParticleSystem in the editor.
|
||||
|
||||
- When a `GameObject` with this component is selected in the editor, a temporary `ParticleSystem` is added if needed so you can preview the effect in the Scene view.
|
||||
- The generated `ParticleSystem` is marked with `HideFlags.DontSave`, so it is neither saved nor included in builds.
|
||||
|
||||
|
||||
<br><br>
|
||||
|
||||
### Project Settings
|
||||
|
||||
You can adjust the project-wide settings for `UI Particle`. (`Edit > Project Settings > UI > UI Particle`)
|
||||

|
||||
|
||||

|
||||
|
||||
#### Settings
|
||||
|
||||
- **Enable Linear To Gamma**: Automatically correct the color space of the mesh.
|
||||
|
||||
#### Editor
|
||||
|
||||
- **Hide Generated Component**: Automatically hide the generated `UIParticleRenderer` component and `UIParticle BakingCamera`.
|
||||
|
||||
- **Preview On Select**: When selecting UIParticle, a temporary ParticleSystem is generated for preview.
|
||||
- Click `Edit > Project Settings` to open the Project Settings window and then select `UI > UI Particle` category.
|
||||
|
||||
<br><br>
|
||||
|
||||
|
||||
@@ -37,17 +37,37 @@ namespace Coffee.UIExtensions
|
||||
switch (type)
|
||||
{
|
||||
case ShaderPropertyType.Color:
|
||||
material.SetColor(id, mpb.GetColor(id));
|
||||
var color = mpb.GetColor(id);
|
||||
if (color != default)
|
||||
{
|
||||
material.SetColor(id, color);
|
||||
}
|
||||
|
||||
break;
|
||||
case ShaderPropertyType.Vector:
|
||||
material.SetVector(id, mpb.GetVector(id));
|
||||
var vector = mpb.GetVector(id);
|
||||
if (vector != default)
|
||||
{
|
||||
material.SetVector(id, vector);
|
||||
}
|
||||
|
||||
break;
|
||||
case ShaderPropertyType.Float:
|
||||
case ShaderPropertyType.Range:
|
||||
material.SetFloat(id, mpb.GetFloat(id));
|
||||
var value = mpb.GetFloat(id);
|
||||
if (!Mathf.Approximately(value, 0))
|
||||
{
|
||||
material.SetFloat(id, value);
|
||||
}
|
||||
|
||||
break;
|
||||
case ShaderPropertyType.Texture:
|
||||
material.SetTexture(id, mpb.GetTexture(id));
|
||||
var tex = mpb.GetTexture(id);
|
||||
if (tex != default(Texture))
|
||||
{
|
||||
material.SetTexture(id, tex);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -98,7 +98,7 @@ namespace Coffee.UIParticleInternal
|
||||
Profiler.BeginSample("(COF)[CanvasExt] GetViewProjectionMatrix");
|
||||
var rootCanvas = canvas.rootCanvas;
|
||||
var cam = rootCanvas.worldCamera;
|
||||
if (rootCanvas != null && rootCanvas.renderMode != RenderMode.ScreenSpaceOverlay && cam != null)
|
||||
if (rootCanvas && rootCanvas.renderMode != RenderMode.ScreenSpaceOverlay && cam)
|
||||
{
|
||||
if (eye == Camera.MonoOrStereoscopicEye.Mono)
|
||||
{
|
||||
|
||||
@@ -12,33 +12,6 @@ namespace Coffee.UIParticleInternal
|
||||
/// </summary>
|
||||
internal static class ComponentExtensions
|
||||
{
|
||||
#if !UNITY_2019_2_OR_NEWER
|
||||
public static bool TryGetComponent<T>(this GameObject self, out T component)
|
||||
where T : Component
|
||||
{
|
||||
if (self == null)
|
||||
{
|
||||
component = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
component = self.GetComponent<T>();
|
||||
return component != null;
|
||||
}
|
||||
|
||||
public static bool TryGetComponent<T>(this Component self, out T component)
|
||||
where T : Component
|
||||
{
|
||||
if (self == null)
|
||||
{
|
||||
component = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return self.gameObject.TryGetComponent(out component);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Get components in children of a specific type in the hierarchy of a GameObject.
|
||||
/// </summary>
|
||||
@@ -65,7 +38,7 @@ namespace Coffee.UIParticleInternal
|
||||
private static void GetComponentsInChildren_Internal<T>(this Component self, List<T> results, int depth)
|
||||
where T : Component
|
||||
{
|
||||
if (self == null || results == null || depth < 0) return;
|
||||
if (!self || results == null || depth < 0) return;
|
||||
|
||||
var tr = self.transform;
|
||||
if (tr.TryGetComponent<T>(out var t))
|
||||
@@ -86,7 +59,7 @@ namespace Coffee.UIParticleInternal
|
||||
/// </summary>
|
||||
public static T GetOrAddComponent<T>(this Component self) where T : Component
|
||||
{
|
||||
if (self == null) return null;
|
||||
if (!self) return null;
|
||||
return self.TryGetComponent<T>(out var component)
|
||||
? component
|
||||
: self.gameObject.AddComponent<T>();
|
||||
@@ -99,7 +72,7 @@ namespace Coffee.UIParticleInternal
|
||||
{
|
||||
T component = null;
|
||||
var transform = self.transform;
|
||||
while (transform != null)
|
||||
while (transform)
|
||||
{
|
||||
if (transform.TryGetComponent<T>(out var c))
|
||||
{
|
||||
@@ -120,7 +93,7 @@ namespace Coffee.UIParticleInternal
|
||||
where T : Component
|
||||
{
|
||||
var tr = includeSelf ? self.transform : self.transform.parent;
|
||||
while (tr != null)
|
||||
while (tr)
|
||||
{
|
||||
if (tr.TryGetComponent<T>(out var c) && valid(c)) return c;
|
||||
if (tr == stopAfter) return null;
|
||||
@@ -193,11 +166,11 @@ namespace Coffee.UIParticleInternal
|
||||
#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 == null) return null;
|
||||
if (!self) return null;
|
||||
if (!includeInactive) return self.GetComponentInParent<T>();
|
||||
|
||||
var current = self.transform;
|
||||
while (current != null)
|
||||
while (current)
|
||||
{
|
||||
if (current.TryGetComponent<T>(out var c)) return c;
|
||||
current = current.parent;
|
||||
@@ -213,7 +186,7 @@ namespace Coffee.UIParticleInternal
|
||||
/// </summary>
|
||||
internal static bool CanConvertTo<T>(this Object context) where T : MonoBehaviour
|
||||
{
|
||||
return context != null && context.GetType() != typeof(T);
|
||||
return context && context.GetType() != typeof(T);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -32,10 +32,10 @@ namespace Coffee.UIParticleInternal
|
||||
/// </summary>
|
||||
public static Texture2D GetActualTexture(this Sprite self)
|
||||
{
|
||||
if (self == null) return null;
|
||||
if (!self) return null;
|
||||
|
||||
var ret = s_GetActiveAtlasTextureMethod(self);
|
||||
return ret != null ? ret : self.texture;
|
||||
return ret ? ret : self.texture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -43,7 +43,7 @@ namespace Coffee.UIParticleInternal
|
||||
/// </summary>
|
||||
public static SpriteAtlas GetActiveAtlas(this Sprite self)
|
||||
{
|
||||
if (self == null) return null;
|
||||
if (!self) return null;
|
||||
|
||||
return s_GetActiveAtlasMethod(self);
|
||||
}
|
||||
@@ -53,7 +53,7 @@ namespace Coffee.UIParticleInternal
|
||||
/// </summary>
|
||||
internal static Texture2D GetActualTexture(this Sprite self)
|
||||
{
|
||||
return self != null ? self.texture : null;
|
||||
return self ? self.texture : null;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -14,66 +14,22 @@ namespace Coffee.UIParticleInternal
|
||||
public abstract class PreloadedProjectSettings : ScriptableObject
|
||||
#if UNITY_EDITOR
|
||||
{
|
||||
[Tooltip("When enabled, this settings asset will be added to PlayerSettings.preloadedAssets in build.\n\n" +
|
||||
"When disable, you should load this settings via Resources, AssetBundles or Addressables to use.")]
|
||||
[SerializeField]
|
||||
[Header("Advanced")]
|
||||
[HideInInspector]
|
||||
private bool m_PreLoadSettingsInBuild = true;
|
||||
|
||||
protected static bool s_BuildingPlayer;
|
||||
|
||||
private class EditorEvents : AssetPostprocessor, IPreprocessBuildWithReport, IPostprocessBuildWithReport
|
||||
private class Postprocessor : AssetPostprocessor
|
||||
{
|
||||
int IOrderedCallback.callbackOrder => 0;
|
||||
|
||||
private static void OnPostprocessAllAssets(string[] _, string[] __, string[] ___, string[] ____)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
private class PreprocessBuildWithReport : IPreprocessBuildWithReport
|
||||
{
|
||||
int IOrderedCallback.callbackOrder => 0;
|
||||
|
||||
void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report)
|
||||
{
|
||||
AssetDatabase.Refresh();
|
||||
Initialize();
|
||||
s_BuildingPlayer = true;
|
||||
|
||||
foreach (var t in TypeCache.GetTypesDerivedFrom(typeof(PreloadedProjectSettings<>)))
|
||||
{
|
||||
var settings = GetDefaultSettings(t);
|
||||
if (settings == null || settings.m_PreLoadSettingsInBuild) continue;
|
||||
|
||||
PlayerSettings.SetPreloadedAssets(
|
||||
PlayerSettings.GetPreloadedAssets()
|
||||
.Where(x => x != null && x.GetType() != t)
|
||||
.ToArray());
|
||||
|
||||
Debug.Log($"[PreloadedProjectSettings] Build started: removed '{settings.name}' " +
|
||||
$"({t.Name}) from PreloadedAssets. " +
|
||||
$"It will be restored after build completes.");
|
||||
}
|
||||
}
|
||||
|
||||
void IPostprocessBuildWithReport.OnPostprocessBuild(BuildReport report)
|
||||
{
|
||||
s_BuildingPlayer = false;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void OnDomainReload()
|
||||
{
|
||||
foreach (var t in TypeCache.GetTypesDerivedFrom(typeof(PreloadedProjectSettings<>)))
|
||||
{
|
||||
var defaultSettings = GetDefaultSettings(t);
|
||||
if (defaultSettings != null)
|
||||
{
|
||||
defaultSettings.OnDomainReload();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void Initialize()
|
||||
@@ -81,21 +37,18 @@ namespace Coffee.UIParticleInternal
|
||||
foreach (var t in TypeCache.GetTypesDerivedFrom(typeof(PreloadedProjectSettings<>)))
|
||||
{
|
||||
var defaultSettings = GetDefaultSettings(t);
|
||||
if (defaultSettings == null)
|
||||
if (!defaultSettings)
|
||||
{
|
||||
if (!s_BuildingPlayer)
|
||||
{
|
||||
// When create a new instance, automatically set it as default settings.
|
||||
defaultSettings = CreateInstance(t) as PreloadedProjectSettings;
|
||||
SetDefaultSettings(defaultSettings);
|
||||
}
|
||||
// When create a new instance, automatically set it as default settings.
|
||||
defaultSettings = CreateInstance(t) as PreloadedProjectSettings;
|
||||
SetDefaultSettings(defaultSettings);
|
||||
}
|
||||
else if (GetPreloadedSettings(t).Length != 1)
|
||||
{
|
||||
if (!s_BuildingPlayer) SetDefaultSettings(defaultSettings);
|
||||
SetDefaultSettings(defaultSettings);
|
||||
}
|
||||
|
||||
if (defaultSettings != null)
|
||||
if (defaultSettings)
|
||||
{
|
||||
defaultSettings.OnInitialize();
|
||||
}
|
||||
@@ -113,22 +66,22 @@ namespace Coffee.UIParticleInternal
|
||||
private static Object[] GetPreloadedSettings(Type type)
|
||||
{
|
||||
return PlayerSettings.GetPreloadedAssets()
|
||||
.Where(x => x != null && x.GetType() == type)
|
||||
.Where(x => x && x.GetType() == type)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
protected static PreloadedProjectSettings GetDefaultSettings(Type type)
|
||||
{
|
||||
return GetPreloadedSettings(type).FirstOrDefault() as PreloadedProjectSettings
|
||||
?? AssetDatabase.FindAssets($"t:{type.Name}")
|
||||
?? AssetDatabase.FindAssets($"t:{nameof(PreloadedProjectSettings)}")
|
||||
.Select(AssetDatabase.GUIDToAssetPath)
|
||||
.Select(AssetDatabase.LoadAssetAtPath<PreloadedProjectSettings>)
|
||||
.FirstOrDefault(x => x != null && x.GetType() == type);
|
||||
.FirstOrDefault(x => x && x.GetType() == type);
|
||||
}
|
||||
|
||||
protected static void SetDefaultSettings(PreloadedProjectSettings asset)
|
||||
{
|
||||
if (asset == null) return;
|
||||
if (!asset) return;
|
||||
|
||||
var type = asset.GetType();
|
||||
if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(asset)))
|
||||
@@ -150,7 +103,7 @@ namespace Coffee.UIParticleInternal
|
||||
var preloadedAssets = PlayerSettings.GetPreloadedAssets();
|
||||
var projectSettings = GetPreloadedSettings(type);
|
||||
PlayerSettings.SetPreloadedAssets(preloadedAssets
|
||||
.Where(x => x != null)
|
||||
.Where(x => x)
|
||||
.Except(projectSettings.Except(new[] { asset }))
|
||||
.Append(asset)
|
||||
.Distinct()
|
||||
@@ -166,39 +119,6 @@ namespace Coffee.UIParticleInternal
|
||||
protected virtual void OnInitialize()
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void OnDomainReload()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class PreloadedProjectSettingsEditor : Editor
|
||||
{
|
||||
private SerializedProperty _preLoadSettingsInBuild;
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
_preLoadSettingsInBuild = serializedObject.FindProperty("m_PreLoadSettingsInBuild");
|
||||
}
|
||||
|
||||
protected void DrawPreLoadSettingsInBuild(string packageName)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_preLoadSettingsInBuild);
|
||||
if (!_preLoadSettingsInBuild.boolValue)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.HelpBox(
|
||||
$"{target.GetType().Name} asset will not be built in.\n" +
|
||||
$"please load manually from Resources, AssetBundle, or Addressables before using {packageName}.",
|
||||
MessageType.Warning);
|
||||
if (GUILayout.Button("Ping"))
|
||||
{
|
||||
EditorGUIUtility.PingObject(target);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
@@ -213,33 +133,31 @@ namespace Coffee.UIParticleInternal
|
||||
#if UNITY_EDITOR
|
||||
private string _jsonText;
|
||||
|
||||
public static bool hasInstance => s_Instance != null;
|
||||
public static bool hasInstance => s_Instance;
|
||||
|
||||
public static T instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_Instance != null) return s_Instance;
|
||||
if (s_Instance) return s_Instance;
|
||||
|
||||
s_Instance = GetDefaultSettings(typeof(T)) as T;
|
||||
if (s_Instance != null) return s_Instance;
|
||||
if (s_Instance) return s_Instance;
|
||||
|
||||
s_Instance = CreateInstance<T>();
|
||||
if (s_Instance == null)
|
||||
if (!s_Instance)
|
||||
{
|
||||
s_Instance = null;
|
||||
return s_Instance;
|
||||
}
|
||||
|
||||
if (!s_BuildingPlayer) SetDefaultSettings(s_Instance);
|
||||
SetDefaultSettings(s_Instance);
|
||||
return s_Instance;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPlayModeStateChanged(PlayModeStateChange state)
|
||||
{
|
||||
if (this == null) return;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case PlayModeStateChange.ExitingEditMode:
|
||||
@@ -255,13 +173,8 @@ namespace Coffee.UIParticleInternal
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDomainReload()
|
||||
{
|
||||
s_Instance = null;
|
||||
}
|
||||
#else
|
||||
public static T instance => s_Instance != null ? s_Instance : s_Instance = CreateInstance<T>();
|
||||
public static T instance => s_Instance ? s_Instance : s_Instance = CreateInstance<T>();
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
@@ -270,21 +183,17 @@ namespace Coffee.UIParticleInternal
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var isDefaultSettings = s_Instance == null || s_Instance == this || GetDefaultSettings(typeof(T)) == this;
|
||||
var isDefaultSettings = !s_Instance || s_Instance == this || GetDefaultSettings(typeof(T)) == this;
|
||||
if (!isDefaultSettings)
|
||||
{
|
||||
DestroyImmediate(this, true);
|
||||
return;
|
||||
}
|
||||
|
||||
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
|
||||
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
||||
#else
|
||||
if (s_Instance != null && s_Instance != this)
|
||||
{
|
||||
Destroy(s_Instance);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (s_Instance) return;
|
||||
s_Instance = this as T;
|
||||
}
|
||||
|
||||
@@ -313,9 +222,9 @@ namespace Coffee.UIParticleInternal
|
||||
|
||||
public override void OnGUI(string searchContext)
|
||||
{
|
||||
if (_target == null)
|
||||
if (!_target)
|
||||
{
|
||||
if (_editor != null)
|
||||
if (_editor)
|
||||
{
|
||||
DestroyImmediate(_editor);
|
||||
_editor = null;
|
||||
|
||||
@@ -66,6 +66,11 @@ namespace Coffee.UIParticleInternal
|
||||
node = node.Next;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_delegates.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -8,19 +8,19 @@ namespace Coffee.UIParticleInternal
|
||||
{
|
||||
private static readonly Dictionary<Type, IFrameCache> s_Caches = new Dictionary<Type, IFrameCache>();
|
||||
|
||||
#if UNITY_EDITOR && UNITY_2019_3_OR_NEWER
|
||||
static FrameCache()
|
||||
{
|
||||
s_Caches.Clear();
|
||||
UIExtraCallbacks.onLateAfterCanvasRebuild += ClearAllCache;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
#elif UNITY_EDITOR
|
||||
[InitializeOnLoadMethod]
|
||||
#else
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
#endif
|
||||
private static void Clear()
|
||||
{
|
||||
s_Caches.Clear();
|
||||
UIExtraCallbacks.onLateAfterCanvasRebuild -= ClearAllCache;
|
||||
UIExtraCallbacks.onLateAfterCanvasRebuild += ClearAllCache;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Tries to retrieve a value from the frame cache with a specified key.
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4f9f22bb079324476b1473030ad9fec3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -11,7 +11,7 @@ using Conditional = System.Diagnostics.ConditionalAttribute;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal static class Logger
|
||||
internal static class Logging
|
||||
{
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
private const string k_DisableSymbol = "DISABLE_COFFEE_LOGGER";
|
||||
@@ -48,7 +48,7 @@ namespace Coffee.UIParticleInternal
|
||||
public static void LogIf(bool enable, object tag, object message, Object context = null)
|
||||
{
|
||||
if (!enable) return;
|
||||
Log_Internal(LogType.Log, tag, message, context != null ? context : tag as Object);
|
||||
Log_Internal(LogType.Log, tag, message, context ? context : tag as Object);
|
||||
}
|
||||
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
@@ -56,7 +56,7 @@ namespace Coffee.UIParticleInternal
|
||||
#endif
|
||||
public static void Log(object tag, object message, Object context = null)
|
||||
{
|
||||
Log_Internal(LogType.Log, tag, message, context != null ? context : tag as Object);
|
||||
Log_Internal(LogType.Log, tag, message, context ? context : tag as Object);
|
||||
}
|
||||
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
@@ -64,13 +64,13 @@ namespace Coffee.UIParticleInternal
|
||||
#endif
|
||||
public static void LogWarning(object tag, object message, Object context = null)
|
||||
{
|
||||
Log_Internal(LogType.Warning, tag, message, context != null ? context : tag as Object);
|
||||
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 != null ? context : tag as Object);
|
||||
Log_Internal(LogType.Error, tag, message, context ? context : tag as Object);
|
||||
#else
|
||||
Debug.LogError($"{tag}: {message}", context);
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc1207b657ed74ec19e459664d06925f
|
||||
guid: 8255313895da84e7cbdc876be3795334
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -13,9 +13,7 @@ namespace Coffee.UIParticleInternal
|
||||
|
||||
public static int count => s_Repository.count;
|
||||
|
||||
public static Func<string, Shader> onShaderFind = Shader.Find;
|
||||
|
||||
#if UNITY_EDITOR && UNITY_2019_3_OR_NEWER
|
||||
#if UNITY_EDITOR
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
public static void Clear()
|
||||
{
|
||||
@@ -50,7 +48,7 @@ namespace Coffee.UIParticleInternal
|
||||
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(onShaderFind(x))
|
||||
s_Repository.Get(hash, ref material, x => new Material(Shader.Find(x))
|
||||
{
|
||||
hideFlags = HideFlags.DontSave | HideFlags.NotEditable
|
||||
}, shaderName);
|
||||
@@ -63,7 +61,7 @@ namespace Coffee.UIParticleInternal
|
||||
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(onShaderFind(x.shaderName))
|
||||
s_Repository.Get(hash, ref material, x => new Material(Shader.Find(x.shaderName))
|
||||
{
|
||||
hideFlags = HideFlags.DontSave | HideFlags.NotEditable,
|
||||
shaderKeywords = x.keywords
|
||||
|
||||
@@ -20,9 +20,7 @@ namespace Coffee.UIParticleInternal
|
||||
{
|
||||
public static T[] FindObjectsOfType<T>() where T : Object
|
||||
{
|
||||
#if UNITY_6000_4_OR_NEWER
|
||||
return Object.FindObjectsByType<T>(FindObjectsInactive.Include);
|
||||
#elif UNITY_2023_1_OR_NEWER
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
return Object.FindObjectsByType<T>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
||||
#else
|
||||
return Object.FindObjectsOfType<T>();
|
||||
@@ -31,7 +29,7 @@ namespace Coffee.UIParticleInternal
|
||||
|
||||
public static void Destroy(Object obj)
|
||||
{
|
||||
if (obj == null) return;
|
||||
if (!obj) return;
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
@@ -46,19 +44,24 @@ namespace Coffee.UIParticleInternal
|
||||
|
||||
public static void DestroyImmediate(Object obj)
|
||||
{
|
||||
if (obj == null) return;
|
||||
if (!obj) return;
|
||||
#if UNITY_EDITOR
|
||||
Object.DestroyImmediate(obj, true);
|
||||
#else
|
||||
Object.Destroy(obj);
|
||||
if (Application.isEditor)
|
||||
{
|
||||
Object.DestroyImmediate(obj);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Object.Destroy(obj);
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional("UNITY_EDITOR")]
|
||||
public static void SetDirty(Object obj)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (obj == null) return;
|
||||
if (!obj) return;
|
||||
EditorUtility.SetDirty(obj);
|
||||
#endif
|
||||
}
|
||||
@@ -109,16 +112,16 @@ namespace Coffee.UIParticleInternal
|
||||
{
|
||||
if (Misc.isBatchOrBuilding) return;
|
||||
|
||||
var types = TypeCache.GetTypesWithAttribute(typeof(IconAttribute));
|
||||
var types = TypeCache.GetTypesWithAttribute<IconAttribute>();
|
||||
var scripts = MonoImporter.GetAllRuntimeMonoScripts();
|
||||
foreach (var type in types)
|
||||
{
|
||||
var script = scripts.FirstOrDefault(x => x.GetClass() == type);
|
||||
if (script == null) continue;
|
||||
if (!script) continue;
|
||||
|
||||
var path = type.GetCustomAttribute<IconAttribute>()?._path;
|
||||
var icon = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
|
||||
if (icon == null) continue;
|
||||
if (!icon) continue;
|
||||
|
||||
s_SetIconForObject(script, icon);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Coffee.UIParticleInternal
|
||||
}
|
||||
|
||||
// If there are no instances in the pool, create a new one.
|
||||
Logger.Log(this, $"A new instance is created (pooled: {_pool.CountInactive}, created: {_pool.CountAll}).");
|
||||
Logging.Log(this, $"A new instance is created (pooled: {_pool.CountInactive}, created: {_pool.CountAll}).");
|
||||
return _pool.Get();
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Coffee.UIParticleInternal
|
||||
if (instance == null) return; // Ignore if already pooled or null.
|
||||
|
||||
_pool.Release(instance);
|
||||
Logger.Log(this, $"An instance is released (pooled: {_pool.CountInactive}, created: {_pool.CountAll}).");
|
||||
Logging.Log(this, $"An instance is released (pooled: {_pool.CountInactive}, created: {_pool.CountAll}).");
|
||||
instance = default; // Set the reference to null.
|
||||
}
|
||||
#else
|
||||
@@ -80,7 +80,7 @@ namespace Coffee.UIParticleInternal
|
||||
}
|
||||
|
||||
// If there are no instances in the pool, create a new one.
|
||||
Logger.Log(this, $"A new instance is created (pooled: {_pool.Count}, created: {++_count}).");
|
||||
Logging.Log(this, $"A new instance is created (pooled: {_pool.Count}, created: {++_count}).");
|
||||
return _onCreate();
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace Coffee.UIParticleInternal
|
||||
|
||||
_onReturn(instance); // Return the instance to the pool.
|
||||
_pool.Push(instance);
|
||||
Logger.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.
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace Coffee.UIParticleInternal
|
||||
Profiler.BeginSample("(COF)[ObjectRepository] GetFromCache");
|
||||
if (_cache.TryGetValue(hash, out var entry))
|
||||
{
|
||||
if (entry.storedObject == null)
|
||||
if (!entry.storedObject)
|
||||
{
|
||||
Release(ref entry.storedObject);
|
||||
Profiler.EndSample();
|
||||
@@ -103,7 +103,7 @@ namespace Coffee.UIParticleInternal
|
||||
Release(ref obj);
|
||||
++entry.reference;
|
||||
obj = entry.storedObject;
|
||||
Logger.Log(_name, $"Get(total#{count}): {entry}");
|
||||
Logging.Log(_name, $"Get(total#{count}): {entry}");
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
@@ -116,7 +116,7 @@ namespace Coffee.UIParticleInternal
|
||||
|
||||
private void Add(Hash128 hash, ref T obj, T newObject)
|
||||
{
|
||||
if (newObject == null)
|
||||
if (!newObject)
|
||||
{
|
||||
Release(ref obj);
|
||||
obj = newObject;
|
||||
@@ -130,8 +130,8 @@ namespace Coffee.UIParticleInternal
|
||||
newEntry.hash = hash;
|
||||
newEntry.reference = 1;
|
||||
_cache[hash] = newEntry;
|
||||
_objectKey[newObject.GetHashCode()] = hash;
|
||||
Logger.Log(_name, $"<color=#03c700>Add</color>(total#{count}): {newEntry}");
|
||||
_objectKey[newObject.GetInstanceID()] = hash;
|
||||
Logging.Log(_name, $"<color=#03c700>Add</color>(total#{count}): {newEntry}");
|
||||
Release(ref obj);
|
||||
obj = newObject;
|
||||
Profiler.EndSample();
|
||||
@@ -146,23 +146,23 @@ namespace Coffee.UIParticleInternal
|
||||
|
||||
// Find and release the entry.
|
||||
Profiler.BeginSample("(COF)[ObjectRepository] Release");
|
||||
var id = obj.GetHashCode();
|
||||
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 == null)
|
||||
if (entry.reference <= 0 || !entry.storedObject)
|
||||
{
|
||||
Remove(entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log(_name, $"Release(total#{_cache.Count}): {entry}");
|
||||
Logging.Log(_name, $"Release(total#{_cache.Count}): {entry}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log(_name, $"Release(total#{_cache.Count}): <color=red>Already released: {obj}</color>");
|
||||
Logging.Log(_name, $"Release(total#{_cache.Count}): <color=red>Already released: {obj}</color>");
|
||||
}
|
||||
|
||||
obj = null;
|
||||
@@ -175,10 +175,10 @@ namespace Coffee.UIParticleInternal
|
||||
|
||||
Profiler.BeginSample("(COF)[ObjectRepository] Remove");
|
||||
_cache.Remove(entry.hash);
|
||||
_objectKey.Remove(entry.storedObject.GetHashCode());
|
||||
_objectKey.Remove(entry.storedObject.GetInstanceID());
|
||||
_pool.Push(entry);
|
||||
entry.reference = 0;
|
||||
Logger.Log(_name, $"<color=#f29e03>Remove</color>(total#{_cache.Count}): {entry}");
|
||||
Logging.Log(_name, $"<color=#f29e03>Remove</color>(total#{_cache.Count}): {entry}");
|
||||
entry.Release(_onRelease);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
@@ -192,7 +192,7 @@ namespace Coffee.UIParticleInternal
|
||||
public void Release(Action<T> onRelease)
|
||||
{
|
||||
reference = 0;
|
||||
if (storedObject != null)
|
||||
if (storedObject)
|
||||
{
|
||||
onRelease?.Invoke(storedObject);
|
||||
}
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
#if !UNITY_2019_2_OR_NEWER
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
public static class TypeCache
|
||||
{
|
||||
private static readonly object s_Lock = new object();
|
||||
private static readonly Dictionary<Type, Type[]> s_DerivedTypesCache = new Dictionary<Type, Type[]>();
|
||||
private static readonly Dictionary<Type, Type[]> s_AttributeTypesCache = new Dictionary<Type, Type[]>();
|
||||
|
||||
public static IEnumerable<Type> GetTypesDerivedFrom(Type baseType)
|
||||
{
|
||||
lock (s_Lock)
|
||||
{
|
||||
if (s_DerivedTypesCache.TryGetValue(baseType, out var cached))
|
||||
{
|
||||
return cached;
|
||||
}
|
||||
|
||||
var types = new List<Type>();
|
||||
foreach (var t in GetAllLoadableTypes())
|
||||
{
|
||||
if (t != baseType && baseType.IsAssignableFrom(t))
|
||||
{
|
||||
types.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
return s_DerivedTypesCache[baseType] = types.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> GetTypesWithAttribute(Type attr)
|
||||
{
|
||||
lock (s_Lock)
|
||||
{
|
||||
if (s_AttributeTypesCache.TryGetValue(attr, out var cached))
|
||||
{
|
||||
return cached;
|
||||
}
|
||||
|
||||
var types = new List<Type>();
|
||||
foreach (var t in GetAllLoadableTypes())
|
||||
{
|
||||
if (t.GetCustomAttributes(attr, inherit: true).Length > 0)
|
||||
{
|
||||
types.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
return s_AttributeTypesCache[attr] = types.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<Type> GetAllLoadableTypes()
|
||||
{
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
Type[] types;
|
||||
try
|
||||
{
|
||||
types = assembly.GetTypes();
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
{
|
||||
types = ex.Types;
|
||||
}
|
||||
|
||||
if (types == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var t in types)
|
||||
{
|
||||
if (t != null)
|
||||
{
|
||||
yield return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
@@ -21,7 +20,7 @@ namespace Coffee.UIParticleInternal
|
||||
static UIExtraCallbacks()
|
||||
{
|
||||
Canvas.willRenderCanvases += OnBeforeCanvasRebuild;
|
||||
Logger.LogMulticast(typeof(Canvas), "willRenderCanvases", message: "ctor");
|
||||
Logging.LogMulticast(typeof(Canvas), "willRenderCanvases", message: "ctor");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -68,32 +67,20 @@ namespace Coffee.UIParticleInternal
|
||||
if (s_IsInitializedAfterCanvasRebuild) return;
|
||||
s_IsInitializedAfterCanvasRebuild = true;
|
||||
|
||||
// Explicitly set `Canvas.willRenderCanvases += CanvasUpdateRegistry.PerformUpdate`.
|
||||
CanvasUpdateRegistry.IsRebuildingLayout();
|
||||
#if TMP_ENABLE
|
||||
// Explicitly set `Canvas.willRenderCanvases += TMP_UpdateManager.DoRebuilds`.
|
||||
typeof(TMPro.TMP_UpdateManager)
|
||||
.GetProperty("instance", BindingFlags.NonPublic | BindingFlags.Static)
|
||||
.GetValue(null);
|
||||
#endif
|
||||
Canvas.willRenderCanvases -= OnAfterCanvasRebuild;
|
||||
Canvas.willRenderCanvases += OnAfterCanvasRebuild;
|
||||
Logger.LogMulticast(typeof(Canvas), "willRenderCanvases",
|
||||
Logging.LogMulticast(typeof(Canvas), "willRenderCanvases",
|
||||
message: "InitializeAfterCanvasRebuild");
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR && UNITY_2019_3_OR_NEWER
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
#elif UNITY_EDITOR
|
||||
#if UNITY_EDITOR
|
||||
[InitializeOnLoadMethod]
|
||||
#else
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
#endif
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
private static void InitializeOnLoad()
|
||||
{
|
||||
Canvas.willRenderCanvases -= OnAfterCanvasRebuild;
|
||||
s_IsInitializedAfterCanvasRebuild = false;
|
||||
s_LastScreenSize = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,237 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Coffee.UIParticleInternal;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIExtensions
|
||||
{
|
||||
[Icon("Packages/com.coffee.ui-particle/Editor/UIParticleIcon.png")]
|
||||
[ExecuteAlways]
|
||||
internal class ParticleSystemPreviewer : MonoBehaviour
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[CustomEditor(typeof(ParticleSystemPreviewer))]
|
||||
[CanEditMultipleObjects]
|
||||
internal class ParticleSystemPreviewerEditor : Editor
|
||||
{
|
||||
private GameObject[] _gameObjects;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_gameObjects = targets.OfType<ParticleSystemPreviewer>().Select(x => x.gameObject).ToArray();
|
||||
ParticleSystemPreviewSystem.Register(_gameObjects);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
ParticleSystemPreviewSystem.DrawWarningForTemporary(_gameObjects);
|
||||
ParticleSystemPreviewSystem.DrawWarningForPermanent(_gameObjects);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class manages temporary ParticleSystems for preview purposes.
|
||||
/// When previewing in the editor, it is common to place an empty ParticleSystem as the root, but it consumes memory at runtime if included in the build.
|
||||
/// The temporary ParticleSystems created by this class only exist when the specified GameObject is selected, and are automatically deleted when the selection is cleared.
|
||||
/// </summary>
|
||||
internal class ParticleSystemPreviewSystem : ScriptableSingleton<ParticleSystemPreviewSystem>
|
||||
{
|
||||
private const HideFlags k_TemporaryHideFlags = HideFlags.DontSave | HideFlags.NotEditable;
|
||||
|
||||
[SerializeField]
|
||||
private List<GameObject> m_PreviewObjects = new List<GameObject>();
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
#endif
|
||||
[InitializeOnLoadMethod]
|
||||
public static void Initialize()
|
||||
{
|
||||
instance.OnSelectionChanged();
|
||||
|
||||
Selection.selectionChanged -= instance.OnSelectionChanged;
|
||||
Selection.selectionChanged += instance.OnSelectionChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a temporary ParticleSystem to the specified GameObject for preview purposes.
|
||||
/// </summary>
|
||||
public static void Register(GameObject[] targets)
|
||||
{
|
||||
foreach (var target in targets)
|
||||
{
|
||||
Register(target);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a temporary ParticleSystem to the specified GameObject for preview purposes.
|
||||
/// </summary>
|
||||
public static void Register(GameObject target)
|
||||
{
|
||||
if (!target) return;
|
||||
if (EditorApplication.isPlaying) return;
|
||||
if (instance.m_PreviewObjects.Contains(target)) return;
|
||||
if (target.TryGetComponent<ParticleSystem>(out var ps))
|
||||
{
|
||||
if (ps.hideFlags == k_TemporaryHideFlags)
|
||||
{
|
||||
RegisterParticleSystem(ps);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Create temporary ParticleSystem for preview.
|
||||
RegisterParticleSystem(target.AddComponent<ParticleSystem>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the temporary ParticleSystem associated with the specified GameObject.
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
public static void Unregister(GameObject target)
|
||||
{
|
||||
if (!target) return;
|
||||
|
||||
var index = instance.m_PreviewObjects.IndexOf(target);
|
||||
if (index < 0) return;
|
||||
|
||||
instance.m_PreviewObjects.RemoveAt(index);
|
||||
if (HasTemporaryParticleSystem(target))
|
||||
{
|
||||
RemoveParticleSystem(target);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterParticleSystem(ParticleSystem ps)
|
||||
{
|
||||
if (!ps) return;
|
||||
if (EditorApplication.isPlaying) return;
|
||||
|
||||
ps.hideFlags = k_TemporaryHideFlags;
|
||||
|
||||
var emission = ps.emission;
|
||||
emission.enabled = false;
|
||||
var shape = ps.shape;
|
||||
shape.enabled = false;
|
||||
|
||||
if (ps.TryGetComponent<ParticleSystemRenderer>(out var psr))
|
||||
{
|
||||
psr.enabled = false;
|
||||
psr.hideFlags = k_TemporaryHideFlags;
|
||||
}
|
||||
|
||||
instance.m_PreviewObjects.Add(ps.gameObject);
|
||||
EditorUtility.SetDirty(ps.gameObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the temporary ParticleSystem associated with the specified GameObject.
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
private static void RemoveParticleSystem(GameObject target)
|
||||
{
|
||||
if (target.TryGetComponent<ParticleSystem>(out var ps))
|
||||
{
|
||||
Misc.DestroyImmediate(ps);
|
||||
EditorUtility.SetDirty(target);
|
||||
}
|
||||
|
||||
if (target.TryGetComponent<ParticleSystem>(out var psr))
|
||||
{
|
||||
Misc.DestroyImmediate(psr);
|
||||
EditorUtility.SetDirty(target);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the specified GameObject has a temporary ParticleSystem.
|
||||
/// </summary>
|
||||
private static bool HasTemporaryParticleSystem(GameObject target)
|
||||
{
|
||||
return target
|
||||
&& instance.m_PreviewObjects.Contains(target)
|
||||
&& target.TryGetComponent<ParticleSystem>(out var ps)
|
||||
&& ps.hideFlags == k_TemporaryHideFlags;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the specified GameObject has a permanent ParticleSystem.
|
||||
/// </summary>
|
||||
private static bool HasPermanentParticleSystem(GameObject target)
|
||||
{
|
||||
return target
|
||||
&& target.TryGetComponent<ParticleSystem>(out var ps)
|
||||
&& ps.hideFlags != k_TemporaryHideFlags;
|
||||
}
|
||||
|
||||
private void OnSelectionChanged()
|
||||
{
|
||||
var selectedGameObjects = Selection.gameObjects;
|
||||
for (var i = m_PreviewObjects.Count - 1; 0 <= i; i--)
|
||||
{
|
||||
var go = m_PreviewObjects[i];
|
||||
if (!go)
|
||||
{
|
||||
m_PreviewObjects.RemoveAt(i);
|
||||
}
|
||||
else if (EditorApplication.isPlaying && !selectedGameObjects.Contains(go))
|
||||
{
|
||||
Unregister(go);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawWarningForTemporary(GameObject[] gameObjects)
|
||||
{
|
||||
if (gameObjects == null || gameObjects.Length == 0 || !gameObjects.Any(HasTemporaryParticleSystem)) return;
|
||||
|
||||
if (WarningButton("The temporary ParticleSystem for preview is attached.\n" +
|
||||
"It will be removed when exiting edit mode.", "Remove"))
|
||||
{
|
||||
foreach (var go in gameObjects)
|
||||
{
|
||||
if (HasTemporaryParticleSystem(go))
|
||||
{
|
||||
RemoveParticleSystem(go);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawWarningForPermanent(GameObject[] gameObjects)
|
||||
{
|
||||
if (gameObjects == null || gameObjects.Length == 0 || !gameObjects.Any(HasPermanentParticleSystem)) return;
|
||||
|
||||
if (WarningButton("The permanent ParticleSystem is attached.\n" +
|
||||
"It will be included in build.", "Remove"))
|
||||
{
|
||||
foreach (var go in gameObjects)
|
||||
{
|
||||
if (HasPermanentParticleSystem(go))
|
||||
{
|
||||
RemoveParticleSystem(go);
|
||||
Unregister(go);
|
||||
Register(go);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool WarningButton(string message, string buttonText)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.HelpBox(message, MessageType.Warning, true);
|
||||
var clicked = GUILayout.Button(EditorGUIUtility.TrTempContent(buttonText));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
return clicked;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b171deb49fb7b471291108ad7e1c9baa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -3,13 +3,12 @@ using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Coffee.UIParticleInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Serialization;
|
||||
using UnityEngine.UI;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
[assembly: InternalsVisibleTo("Coffee.UIParticle.Editor")]
|
||||
[assembly: InternalsVisibleTo("Coffee.UIParticle.Editor.Tests")]
|
||||
[assembly: InternalsVisibleTo("Coffee.UIParticle.PerformanceDemo")]
|
||||
[assembly: InternalsVisibleTo("Coffee.UIParticle.Demo")]
|
||||
|
||||
@@ -18,11 +17,11 @@ namespace Coffee.UIExtensions
|
||||
/// <summary>
|
||||
/// Render maskable and sortable particle effect ,without Camera, RenderTexture or Canvas.
|
||||
/// </summary>
|
||||
[Icon("Packages/com.coffee.ui-particle/Editor/UIParticleIcon.png")]
|
||||
[Icon("Packages/com.coffee.ui-particle/Icons/UIParticleIcon.png")]
|
||||
[ExecuteAlways]
|
||||
[RequireComponent(typeof(RectTransform))]
|
||||
[RequireComponent(typeof(CanvasRenderer))]
|
||||
public class UIParticle : MaskableGraphic, ISerializationCallbackReceiver
|
||||
public class UIParticle : UIBehaviour, ISerializationCallbackReceiver
|
||||
{
|
||||
public enum AutoScalingMode
|
||||
{
|
||||
@@ -64,7 +63,7 @@ namespace Coffee.UIExtensions
|
||||
|
||||
[Tooltip("Scale the rendering particles. When the `3D` toggle is enabled, 3D scale (x, y, z) is supported.")]
|
||||
[SerializeField]
|
||||
private Vector3 m_Scale3D = new Vector3(10, 10, 10);
|
||||
private Vector3 m_Scale3D = new Vector3(1, 1, 1);
|
||||
|
||||
[Tooltip("If you want to update material properties (e.g. _MainTex_ST, _Color) in AnimationClip, " +
|
||||
"use this to mark as animatable.")]
|
||||
@@ -125,20 +124,48 @@ namespace Coffee.UIExtensions
|
||||
[Tooltip("Time scale multiplier.")]
|
||||
private float m_TimeScaleMultiplier = 1;
|
||||
|
||||
[SerializeField]
|
||||
private bool m_Maskable = true;
|
||||
|
||||
private readonly List<UIParticleRenderer> _renderers = new List<UIParticleRenderer>();
|
||||
private Camera _bakeCamera;
|
||||
private Canvas _canvas;
|
||||
private int _groupId;
|
||||
private bool _isScaleStored;
|
||||
private Vector3 _storedScale;
|
||||
private DrivenRectTransformTracker _tracker;
|
||||
|
||||
/// <summary>
|
||||
/// Should this graphic be considered a target for ray-casting?
|
||||
/// </summary>
|
||||
public override bool raycastTarget
|
||||
public RectTransform rectTransform => transform as RectTransform;
|
||||
|
||||
public Canvas canvas
|
||||
{
|
||||
get => false;
|
||||
set { }
|
||||
get
|
||||
{
|
||||
if (_canvas) return _canvas;
|
||||
|
||||
var tr = transform;
|
||||
while (tr && !_canvas)
|
||||
{
|
||||
if (tr.TryGetComponent(out _canvas)) return _canvas;
|
||||
tr = tr.parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does this graphic allow masking.
|
||||
/// </summary>
|
||||
public bool maskable
|
||||
{
|
||||
get => m_Maskable;
|
||||
set
|
||||
{
|
||||
if (value == m_Maskable) return;
|
||||
m_Maskable = value;
|
||||
UpdateRendererMaterial();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -324,15 +351,15 @@ namespace Coffee.UIExtensions
|
||||
|
||||
public Vector3 parentScale { get; private set; }
|
||||
|
||||
public Vector3 canvasScale { get; private set; }
|
||||
private Vector3 canvasScale { get; set; }
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
_isScaleStored = false;
|
||||
ResetGroupId();
|
||||
UIParticleUpdater.Register(this);
|
||||
RegisterDirtyMaterialCallback(UpdateRendererMaterial);
|
||||
|
||||
//
|
||||
if (0 < particles.Count)
|
||||
{
|
||||
RefreshParticles(particles);
|
||||
@@ -342,7 +369,7 @@ namespace Coffee.UIExtensions
|
||||
RefreshParticles();
|
||||
}
|
||||
|
||||
base.OnEnable();
|
||||
UpdateRendererMaterial();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -358,11 +385,16 @@ namespace Coffee.UIExtensions
|
||||
|
||||
_isScaleStored = false;
|
||||
UIParticleUpdater.Unregister(this);
|
||||
_renderers.RemoveAll(r => r == null);
|
||||
_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>
|
||||
@@ -372,6 +404,14 @@ namespace Coffee.UIExtensions
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function is called when a direct or indirect parent of the transform of the GameObject has changed.
|
||||
/// </summary>
|
||||
protected override void OnTransformParentChanged()
|
||||
{
|
||||
_canvas = null;
|
||||
}
|
||||
|
||||
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
||||
{
|
||||
}
|
||||
@@ -472,7 +512,7 @@ namespace Coffee.UIExtensions
|
||||
for (var i = 0; i < _renderers.Count; i++)
|
||||
{
|
||||
var r = _renderers[i];
|
||||
if (r == null || r.material == null) continue;
|
||||
if (!r || !r.material) continue;
|
||||
result.Add(r.material);
|
||||
}
|
||||
}
|
||||
@@ -490,7 +530,7 @@ namespace Coffee.UIExtensions
|
||||
/// </summary>
|
||||
public void SetParticleSystemInstance(GameObject instance, bool destroyOldParticles)
|
||||
{
|
||||
if (instance == null) return;
|
||||
if (!instance) return;
|
||||
|
||||
var childCount = transform.childCount;
|
||||
for (var i = 0; i < childCount; i++)
|
||||
@@ -519,7 +559,7 @@ namespace Coffee.UIExtensions
|
||||
/// </summary>
|
||||
public void SetParticleSystemPrefab(GameObject prefab)
|
||||
{
|
||||
if (prefab == null) return;
|
||||
if (!prefab) return;
|
||||
|
||||
SetParticleSystemInstance(Instantiate(prefab.gameObject), true);
|
||||
}
|
||||
@@ -539,17 +579,12 @@ namespace Coffee.UIExtensions
|
||||
/// </summary>
|
||||
private void RefreshParticles(GameObject root)
|
||||
{
|
||||
if (root == null) return;
|
||||
if (!root) return;
|
||||
root.GetComponentsInChildren(true, particles);
|
||||
for (var i = particles.Count - 1; 0 <= i; i--)
|
||||
{
|
||||
var ps = particles[i];
|
||||
if (!ps
|
||||
#if UNITY_EDITOR
|
||||
|| (ps.hideFlags & HideFlags.DontSave) != 0 // Dummy ParticleSystems for preview.
|
||||
|| ps.gameObject.CompareTag("EditorOnly") // Ignore "EditorOnly" tagged ParticleSystems.
|
||||
#endif
|
||||
|| ps.GetComponentInParent<UIParticle>(true) != this) // Ignore ParticleSystems that are not under this UIParticle.
|
||||
if (!ps || ps.GetComponentInParent<UIParticle>(true) != this)
|
||||
{
|
||||
particles.RemoveAt(i);
|
||||
}
|
||||
@@ -597,7 +632,7 @@ namespace Coffee.UIExtensions
|
||||
for (var i = 0; i < particleSystems.Count; i++)
|
||||
{
|
||||
var ps = particleSystems[i];
|
||||
if (ps == null) continue;
|
||||
if (!ps) continue;
|
||||
|
||||
var mainEmitter = ps.GetMainEmitter(particleSystems);
|
||||
GetRenderer(j++).Set(this, ps, false, mainEmitter);
|
||||
@@ -648,7 +683,7 @@ namespace Coffee.UIExtensions
|
||||
for (var i = 0; i < _renderers.Count; i++)
|
||||
{
|
||||
var r = _renderers[i];
|
||||
if (r != null) continue;
|
||||
if (r) continue;
|
||||
|
||||
RefreshParticles(particles);
|
||||
break;
|
||||
@@ -658,7 +693,7 @@ namespace Coffee.UIExtensions
|
||||
for (var i = 0; i < _renderers.Count; i++)
|
||||
{
|
||||
var r = _renderers[i];
|
||||
if (r == null) continue;
|
||||
if (!r) continue;
|
||||
|
||||
r.UpdateMesh(bakeCamera);
|
||||
}
|
||||
@@ -671,23 +706,12 @@ namespace Coffee.UIExtensions
|
||||
: Random.Range(m_GroupId, m_GroupMaxId + 1);
|
||||
}
|
||||
|
||||
protected override void UpdateMaterial()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call to update the geometry of the Graphic onto the CanvasRenderer.
|
||||
/// </summary>
|
||||
protected override void UpdateGeometry()
|
||||
{
|
||||
}
|
||||
|
||||
private void UpdateRendererMaterial()
|
||||
{
|
||||
for (var i = 0; i < _renderers.Count; i++)
|
||||
{
|
||||
var r = _renderers[i];
|
||||
if (r == null) continue;
|
||||
if (!r) continue;
|
||||
r.maskable = maskable;
|
||||
r.SetMaterialDirty();
|
||||
}
|
||||
@@ -700,7 +724,7 @@ namespace Coffee.UIExtensions
|
||||
_renderers.Add(UIParticleRenderer.AddRenderer(this, index));
|
||||
}
|
||||
|
||||
if (_renderers[index] == null)
|
||||
if (!_renderers[index])
|
||||
{
|
||||
_renderers[index] = UIParticleRenderer.AddRenderer(this, index);
|
||||
}
|
||||
@@ -710,13 +734,13 @@ namespace Coffee.UIExtensions
|
||||
|
||||
private Camera GetBakeCamera()
|
||||
{
|
||||
if (canvas == null) return Camera.main;
|
||||
if (!canvas) return Camera.main;
|
||||
if (!useCustomView && canvas.renderMode != RenderMode.ScreenSpaceOverlay && canvas.rootCanvas.worldCamera)
|
||||
{
|
||||
return canvas.rootCanvas.worldCamera;
|
||||
}
|
||||
|
||||
if (_bakeCamera != null)
|
||||
if (_bakeCamera)
|
||||
{
|
||||
_bakeCamera.orthographicSize = useCustomView ? customViewSize : 10;
|
||||
return _bakeCamera;
|
||||
@@ -735,7 +759,7 @@ namespace Coffee.UIExtensions
|
||||
}
|
||||
|
||||
// Create baking camera.
|
||||
if (_bakeCamera == null)
|
||||
if (!_bakeCamera)
|
||||
{
|
||||
var go = new GameObject("[generated] UIParticle BakingCamera");
|
||||
go.SetActive(false);
|
||||
|
||||
@@ -208,7 +208,7 @@ namespace Coffee.UIExtensions
|
||||
|
||||
private Vector3 GetDestinationPosition(UIParticle uiParticle, ParticleSystem particleSystem)
|
||||
{
|
||||
var isUI = uiParticle != null && uiParticle.enabled;
|
||||
var isUI = uiParticle && uiParticle.enabled;
|
||||
var psPos = particleSystem.transform.position;
|
||||
var attractorPos = transform.position;
|
||||
var dstPos = attractorPos;
|
||||
|
||||
@@ -2,22 +2,20 @@
|
||||
using Coffee.UIParticleInternal;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Coffee.UIExtensions
|
||||
{
|
||||
[Icon("Packages/com.coffee.ui-particle/Icons/UIParticleIcon.png")]
|
||||
public class UIParticleProjectSettings : PreloadedProjectSettings<UIParticleProjectSettings>
|
||||
{
|
||||
[Header("Setting")]
|
||||
[SerializeField]
|
||||
[Tooltip("Automatically correct the color space of the mesh.")]
|
||||
[FormerlySerializedAs("m_EnableLinearToGamma")]
|
||||
internal bool m_AutoColorCorrection = true;
|
||||
internal bool m_EnableLinearToGamma = true;
|
||||
|
||||
public static bool autoColorCorrection
|
||||
public static bool enableLinearToGamma
|
||||
{
|
||||
get => instance.m_AutoColorCorrection;
|
||||
set => instance.m_AutoColorCorrection = value;
|
||||
get => instance.m_EnableLinearToGamma;
|
||||
set => instance.m_EnableLinearToGamma = value;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,16 +26,10 @@ namespace Coffee.UIExtensions
|
||||
[SerializeField]
|
||||
private bool m_HideGeneratedObjects = true;
|
||||
|
||||
[Tooltip("When selecting UIParticle, a temporary ParticleSystem is generated for preview.")]
|
||||
[SerializeField]
|
||||
private bool m_PreviewOnSelect = true;
|
||||
|
||||
internal static HideFlags globalHideFlags => instance.m_HideGeneratedObjects
|
||||
public static HideFlags globalHideFlags => instance.m_HideGeneratedObjects
|
||||
? HideFlags.DontSave | HideFlags.NotEditable | HideFlags.HideInHierarchy | HideFlags.HideInInspector
|
||||
: HideFlags.DontSave | HideFlags.NotEditable;
|
||||
|
||||
internal static bool s_PreviewOnSelectOnSelect => instance.m_PreviewOnSelect;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[SettingsProvider]
|
||||
private static SettingsProvider CreateSettingsProvider()
|
||||
|
||||
@@ -5,7 +5,7 @@ MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 5f0675613942149309588d556e33d990, type: 3}
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
@@ -15,7 +15,7 @@ using UnityEngine.UI;
|
||||
|
||||
namespace Coffee.UIExtensions
|
||||
{
|
||||
[Icon("Packages/com.coffee.ui-particle/Editor/UIParticleIcon.png")]
|
||||
[Icon("Packages/com.coffee.ui-particle/Icons/UIParticleIcon.png")]
|
||||
[ExecuteAlways]
|
||||
[RequireComponent(typeof(RectTransform))]
|
||||
[RequireComponent(typeof(CanvasRenderer))]
|
||||
@@ -30,7 +30,6 @@ namespace Coffee.UIExtensions
|
||||
private int _index;
|
||||
private bool _isPrevStored;
|
||||
private bool _isTrail;
|
||||
private bool _meshCleared;
|
||||
private Bounds _lastBounds;
|
||||
private Material _materialForRendering;
|
||||
private Material _modifiedMaterial;
|
||||
@@ -56,7 +55,7 @@ namespace Coffee.UIExtensions
|
||||
s_Corners[1] = transform.TransformPoint(_lastBounds.min.x, _lastBounds.max.y, 0);
|
||||
s_Corners[2] = transform.TransformPoint(_lastBounds.max.x, _lastBounds.max.y, 0);
|
||||
s_Corners[3] = transform.TransformPoint(_lastBounds.max.x, _lastBounds.min.y, 0);
|
||||
if (canvas != null)
|
||||
if (canvas)
|
||||
{
|
||||
var worldToLocalMatrix = canvas.rootCanvas.transform.worldToLocalMatrix;
|
||||
for (var i = 0; i < 4; ++i)
|
||||
@@ -96,7 +95,7 @@ namespace Coffee.UIExtensions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_materialForRendering == null)
|
||||
if (!_materialForRendering)
|
||||
{
|
||||
_materialForRendering = base.materialForRendering;
|
||||
}
|
||||
@@ -107,7 +106,7 @@ namespace Coffee.UIExtensions
|
||||
|
||||
public void Reset(int index = -1)
|
||||
{
|
||||
if (_renderer != null)
|
||||
if (_renderer)
|
||||
{
|
||||
_renderer.enabled = true;
|
||||
}
|
||||
@@ -122,7 +121,7 @@ namespace Coffee.UIExtensions
|
||||
}
|
||||
|
||||
//_emitter = null;
|
||||
if (isActiveAndEnabled)
|
||||
if (this && isActiveAndEnabled)
|
||||
{
|
||||
material = null;
|
||||
canvasRenderer.Clear();
|
||||
@@ -141,7 +140,7 @@ namespace Coffee.UIExtensions
|
||||
base.OnEnable();
|
||||
|
||||
hideFlags = UIParticleProjectSettings.globalHideFlags;
|
||||
if (s_CombineInstances[0].mesh == null)
|
||||
if (!s_CombineInstances[0].mesh)
|
||||
{
|
||||
s_CombineInstances[0].mesh = new Mesh
|
||||
{
|
||||
@@ -206,9 +205,9 @@ namespace Coffee.UIExtensions
|
||||
}
|
||||
|
||||
var hash = new Hash128(
|
||||
modifiedMaterial ? (uint)modifiedMaterial.GetHashCode() : 0,
|
||||
texture ? (uint)texture.GetHashCode() : 0,
|
||||
0 < _parent.m_AnimatableProperties.Length ? (uint)GetHashCode() : 0,
|
||||
modifiedMaterial ? (uint)modifiedMaterial.GetInstanceID() : 0,
|
||||
texture ? (uint)texture.GetInstanceID() : 0,
|
||||
0 < _parent.m_AnimatableProperties.Length ? (uint)GetInstanceID() : 0,
|
||||
#if UNITY_EDITOR
|
||||
(uint)EditorJsonUtility.ToJson(modifiedMaterial).GetHashCode()
|
||||
#else
|
||||
@@ -284,40 +283,21 @@ namespace Coffee.UIExtensions
|
||||
|| !transform.lossyScale.GetScaled(_parent.scale3DForCalc).IsVisible() // Scale is not visible.
|
||||
|| (!_particleSystem.IsAlive() && !_particleSystem.isPlaying) // No particle.
|
||||
|| (_isTrail && !_particleSystem.trails.enabled) // Trail, but it is not enabled.
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
|| canvasRenderer.GetInheritedAlpha() <
|
||||
0.01f // #102: Do not bake particle system to mesh when the alpha is zero.
|
||||
#endif
|
||||
)
|
||||
{
|
||||
// Skip clearing the mesh if it's already cleared.
|
||||
if (_meshCleared) return;
|
||||
|
||||
Profiler.BeginSample("[UIParticleRenderer] Clear Mesh");
|
||||
workerMesh.Clear();
|
||||
canvasRenderer.SetMesh(workerMesh);
|
||||
_lastBounds = new Bounds();
|
||||
_meshCleared = true;
|
||||
Profiler.EndSample();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset custom data.
|
||||
// var customData = _particleSystem.customData;
|
||||
// if (!customData.enabled || customData.GetMode(ParticleSystemCustomData.Custom1) == ParticleSystemCustomDataMode.Disabled)
|
||||
// {
|
||||
// customData.SetVector(ParticleSystemCustomData.Custom1, 0, 0);
|
||||
// customData.SetVector(ParticleSystemCustomData.Custom1, 1, 0);
|
||||
// customData.SetVector(ParticleSystemCustomData.Custom1, 2, 0);
|
||||
// customData.SetVector(ParticleSystemCustomData.Custom1, 3, 0);
|
||||
// }
|
||||
//
|
||||
// if (!customData.enabled || customData.GetMode(ParticleSystemCustomData.Custom2) == ParticleSystemCustomDataMode.Disabled)
|
||||
// {
|
||||
// customData.SetVector(ParticleSystemCustomData.Custom2, 0, 0);
|
||||
// customData.SetVector(ParticleSystemCustomData.Custom2, 1, 0);
|
||||
// customData.SetVector(ParticleSystemCustomData.Custom2, 2, 0);
|
||||
// customData.SetVector(ParticleSystemCustomData.Custom2, 3, 0);
|
||||
// }
|
||||
|
||||
_meshCleared = false;
|
||||
var main = _particleSystem.main;
|
||||
var scale = GetWorldScale();
|
||||
var psPos = _particleSystem.transform.position;
|
||||
@@ -335,13 +315,6 @@ namespace Coffee.UIExtensions
|
||||
#endif
|
||||
{
|
||||
ResolveResolutionChange(psPos, scale);
|
||||
|
||||
// fix: second and subsequent bursts not displayed when world simulation and non-looping. (#326)
|
||||
if (!_particleSystem.IsLocalSpace() && !main.loop && _particleSystem.time == 0)
|
||||
{
|
||||
_delay = true;
|
||||
}
|
||||
|
||||
Simulate(scale, _parent.isPaused || _delay);
|
||||
|
||||
if (_delay && !_parent.isPaused)
|
||||
@@ -444,7 +417,7 @@ namespace Coffee.UIExtensions
|
||||
_lastBounds = bounds;
|
||||
|
||||
// Convert linear color to gamma color.
|
||||
if (UIParticleProjectSettings.autoColorCorrection && canvas.ShouldGammaToLinearInMesh())
|
||||
if (UIParticleProjectSettings.enableLinearToGamma && canvas.ShouldGammaToLinearInMesh())
|
||||
{
|
||||
workerMesh.LinearToGamma();
|
||||
}
|
||||
@@ -737,7 +710,7 @@ namespace Coffee.UIExtensions
|
||||
if (s_Mpb.isEmpty) return;
|
||||
|
||||
// #41: Copy the value from MaterialPropertyBlock to CanvasRenderer
|
||||
if (materialForRendering == null) return;
|
||||
if (!materialForRendering) return;
|
||||
|
||||
for (var i = 0; i < _parent.m_AnimatableProperties.Length; i++)
|
||||
{
|
||||
|
||||
@@ -16,40 +16,29 @@ namespace Coffee.UIExtensions
|
||||
|
||||
public static void Register(UIParticle particle)
|
||||
{
|
||||
if (particle == null) return;
|
||||
if (!particle) return;
|
||||
s_ActiveParticles.Add(particle);
|
||||
}
|
||||
|
||||
public static void Unregister(UIParticle particle)
|
||||
{
|
||||
if (particle == null) return;
|
||||
if (!particle) return;
|
||||
s_ActiveParticles.Remove(particle);
|
||||
}
|
||||
|
||||
public static void Register(UIParticleAttractor attractor)
|
||||
{
|
||||
if (attractor == null) return;
|
||||
if (!attractor) return;
|
||||
s_ActiveAttractors.Add(attractor);
|
||||
}
|
||||
|
||||
public static void Unregister(UIParticleAttractor attractor)
|
||||
{
|
||||
if (attractor == null) return;
|
||||
if (!attractor) return;
|
||||
s_ActiveAttractors.Remove(attractor);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void OnDomainReload()
|
||||
{
|
||||
s_ActiveParticles.Clear();
|
||||
s_ActiveAttractors.Clear();
|
||||
s_UpdatedGroupIds.Clear();
|
||||
s_FrameCount = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
private static void InitializeOnLoad()
|
||||
{
|
||||
@@ -82,7 +71,7 @@ namespace Coffee.UIExtensions
|
||||
for (var i = 0; i < s_ActiveParticles.Count; i++)
|
||||
{
|
||||
var uip = s_ActiveParticles[i];
|
||||
if (uip == null || uip.canvas == null || !uip.isPrimary || !s_UpdatedGroupIds.Add(uip.groupId)) continue;
|
||||
if (!uip || !uip.canvas || !uip.isPrimary || !s_UpdatedGroupIds.Add(uip.groupId)) continue;
|
||||
|
||||
uip.UpdateTransformScale();
|
||||
uip.UpdateRenderers();
|
||||
@@ -92,7 +81,7 @@ namespace Coffee.UIExtensions
|
||||
for (var i = 0; i < s_ActiveParticles.Count; i++)
|
||||
{
|
||||
var uip = s_ActiveParticles[i];
|
||||
if (uip == null || uip.canvas == null) continue;
|
||||
if (!uip || !uip.canvas) continue;
|
||||
|
||||
uip.UpdateTransformScale();
|
||||
|
||||
@@ -136,7 +125,7 @@ namespace Coffee.UIExtensions
|
||||
var uip = s_ActiveParticles[i];
|
||||
if (!uip.useMeshSharing || uip.groupId != groupId) continue;
|
||||
if (uip.isPrimary) return uip;
|
||||
if (primary == null && uip.canSimulate) primary = uip;
|
||||
if (!primary && uip.canSimulate) primary = uip;
|
||||
}
|
||||
|
||||
return primary;
|
||||
|
||||
@@ -13,7 +13,11 @@ namespace Coffee.UIParticleInternal
|
||||
{
|
||||
if (s_TmpParticles.Length < size)
|
||||
{
|
||||
size = Mathf.NextPowerOfTwo(size);
|
||||
while (s_TmpParticles.Length < size)
|
||||
{
|
||||
size = Mathf.NextPowerOfTwo(size);
|
||||
}
|
||||
|
||||
s_TmpParticles = new ParticleSystem.Particle[size];
|
||||
}
|
||||
|
||||
@@ -84,15 +88,15 @@ namespace Coffee.UIParticleInternal
|
||||
var bRenderer = b.GetComponent<ParticleSystemRenderer>();
|
||||
|
||||
// Render queue: ascending
|
||||
var aMat = aRenderer.sharedMaterial != null ? aRenderer.sharedMaterial : aRenderer.trailMaterial;
|
||||
var bMat = bRenderer.sharedMaterial != null ? bRenderer.sharedMaterial : bRenderer.trailMaterial;
|
||||
if (aMat == null && bMat == null) return 0;
|
||||
if (aMat == null) return -1;
|
||||
if (bMat == null) return 1;
|
||||
var aMat = aRenderer.sharedMaterial ? aRenderer.sharedMaterial : aRenderer.trailMaterial;
|
||||
var bMat = bRenderer.sharedMaterial ? bRenderer.sharedMaterial : bRenderer.trailMaterial;
|
||||
if (!aMat && !bMat) return 0;
|
||||
if (!aMat) return -1;
|
||||
if (!bMat) return 1;
|
||||
|
||||
if (sortByMaterial)
|
||||
{
|
||||
return aMat.GetHashCode() - bMat.GetHashCode();
|
||||
return aMat.GetInstanceID() - bMat.GetInstanceID();
|
||||
}
|
||||
|
||||
if (aMat.renderQueue != bMat.renderQueue)
|
||||
@@ -131,7 +135,7 @@ namespace Coffee.UIParticleInternal
|
||||
{
|
||||
for (var i = 0; i < list.Count; i++)
|
||||
{
|
||||
if (list[i].GetHashCode() == ps.GetHashCode())
|
||||
if (list[i].GetInstanceID() == ps.GetInstanceID())
|
||||
{
|
||||
return i;
|
||||
}
|
||||
@@ -142,7 +146,7 @@ namespace Coffee.UIParticleInternal
|
||||
|
||||
public static Texture2D GetTextureForSprite(this ParticleSystem self)
|
||||
{
|
||||
if (self == null) return null;
|
||||
if (!self) return null;
|
||||
|
||||
// Get sprite's texture.
|
||||
var tsaModule = self.textureSheetAnimation;
|
||||
@@ -151,7 +155,7 @@ namespace Coffee.UIParticleInternal
|
||||
for (var i = 0; i < tsaModule.spriteCount; i++)
|
||||
{
|
||||
var sprite = tsaModule.GetSprite(i);
|
||||
if (sprite == null) continue;
|
||||
if (!sprite) continue;
|
||||
|
||||
return sprite.GetActualTexture();
|
||||
}
|
||||
@@ -163,14 +167,14 @@ namespace Coffee.UIParticleInternal
|
||||
{
|
||||
foreach (var p in self)
|
||||
{
|
||||
if (p == null) continue;
|
||||
if (!p) continue;
|
||||
action.Invoke(p);
|
||||
}
|
||||
}
|
||||
|
||||
public static ParticleSystem GetMainEmitter(this ParticleSystem self, List<ParticleSystem> list)
|
||||
{
|
||||
if (self == null || list == null || list.Count == 0) return null;
|
||||
if (!self || list == null || list.Count == 0) return null;
|
||||
|
||||
for (var i = 0; i < list.Count; i++)
|
||||
{
|
||||
@@ -183,11 +187,7 @@ namespace Coffee.UIParticleInternal
|
||||
|
||||
public static bool IsSubEmitterOf(this ParticleSystem self, ParticleSystem parent)
|
||||
{
|
||||
if (self == null || parent == null) return false;
|
||||
|
||||
var subEmitters = parent.subEmitters;
|
||||
if (!subEmitters.enabled) return false; // No sub emitters.
|
||||
|
||||
var count = subEmitters.subEmittersCount;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Coffee.UIExtensions.Demo
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (m_Origin == null) return;
|
||||
if (!m_Origin) return;
|
||||
m_Origin.SetActive(false);
|
||||
|
||||
var parent = m_Origin.transform.parent;
|
||||
|
||||
@@ -42,7 +42,7 @@ public class UIElementDragger : MonoBehaviour, IBeginDragHandler, IDragHandler,
|
||||
break;
|
||||
case Target.Custom:
|
||||
_rectTransform.localPosition += delta;
|
||||
if (m_CustomTarget != null)
|
||||
if (m_CustomTarget)
|
||||
{
|
||||
if (m_UseCanvasScale)
|
||||
{
|
||||
|
||||
@@ -40,8 +40,12 @@
|
||||
Lighting Off
|
||||
ZWrite Off
|
||||
ZTest [unity_GUIZTestMode]
|
||||
Fog { Mode Off }
|
||||
Fog
|
||||
{
|
||||
Mode Off
|
||||
}
|
||||
Blend One One
|
||||
|
||||
ColorMask [_ColorMask]
|
||||
|
||||
Pass
|
||||
@@ -72,7 +76,6 @@
|
||||
fixed4 color : COLOR;
|
||||
float2 texcoord : TEXCOORD0;
|
||||
float4 worldPosition : TEXCOORD1;
|
||||
float4 mask : TEXCOORD2;
|
||||
UNITY_VERTEX_OUTPUT_STEREO
|
||||
};
|
||||
|
||||
@@ -81,43 +84,16 @@
|
||||
float4 _MainTex_ST;
|
||||
fixed4 _TextureSampleAdd;
|
||||
float4 _ClipRect;
|
||||
float _UIMaskSoftnessX;
|
||||
float _UIMaskSoftnessY;
|
||||
int _UIVertexColorAlwaysGammaSpace;
|
||||
|
||||
half3 _UIGammaToLinear(half3 value)
|
||||
{
|
||||
half3 low = 0.0849710 * value - 0.000163029;
|
||||
half3 high = value * (value * (value * 0.265885 + 0.736584) - 0.00980184) + 0.00319697;
|
||||
|
||||
// We should be 0.5 away from any actual gamma value stored in an 8 bit channel
|
||||
const half3 split = (half3)0.0725490; // Equals 18.5 / 255
|
||||
return (value < split) ? low : high;
|
||||
}
|
||||
|
||||
v2f vert(appdata_t v)
|
||||
{
|
||||
v2f OUT;
|
||||
UNITY_SETUP_INSTANCE_ID(v);
|
||||
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
|
||||
float4 vPosition = UnityObjectToClipPos(v.vertex);
|
||||
OUT.worldPosition = v.vertex;
|
||||
OUT.vertex = vPosition;
|
||||
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
|
||||
|
||||
float2 pixelSize = vPosition.w;
|
||||
pixelSize /= float2(1, 1) * abs(mul((float2x2)UNITY_MATRIX_P, _ScreenParams.xy));
|
||||
|
||||
float4 clampedRect = clamp(_ClipRect, -2e10, 2e10);
|
||||
float2 maskUV = (v.vertex.xy - clampedRect.xy) / (clampedRect.zw - clampedRect.xy);
|
||||
OUT.texcoord = TRANSFORM_TEX(v.texcoord.xy, _MainTex);
|
||||
OUT.mask = float4(v.vertex.xy * 2 - clampedRect.xy - clampedRect.zw, 0.25 / (0.25 * half2(_UIMaskSoftnessX, _UIMaskSoftnessY) + abs(pixelSize.xy)));
|
||||
|
||||
if (_UIVertexColorAlwaysGammaSpace)
|
||||
{
|
||||
#ifndef UNITY_COLORSPACE_GAMMA
|
||||
v.color.rgb = _UIGammaToLinear(v.color.rgb);
|
||||
#endif
|
||||
}
|
||||
OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
|
||||
|
||||
OUT.color = v.color * _Color;
|
||||
return OUT;
|
||||
@@ -125,26 +101,17 @@
|
||||
|
||||
fixed4 frag(v2f IN) : SV_Target
|
||||
{
|
||||
//Round up the alpha color coming from the interpolator (to 1.0/256.0 steps)
|
||||
//The incoming alpha could have numerical instability, which makes it very sensible to
|
||||
//HDR color transparency blend, when it blends with the world's texture.
|
||||
const half alphaPrecision = half(0xff);
|
||||
const half invAlphaPrecision = half(1.0 / alphaPrecision);
|
||||
IN.color.a = round(IN.color.a * alphaPrecision) * invAlphaPrecision;
|
||||
|
||||
half4 color = IN.color * (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd);
|
||||
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
|
||||
|
||||
#ifdef UNITY_UI_CLIP_RECT
|
||||
half2 m = saturate((_ClipRect.zw - _ClipRect.xy - abs(IN.mask.xy)) * IN.mask.zw);
|
||||
color.a *= m.x * m.y;
|
||||
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
|
||||
#endif
|
||||
|
||||
#ifdef UNITY_UI_ALPHACLIP
|
||||
clip(color.a - 0.001);
|
||||
clip (color.a - 0.001);
|
||||
#endif
|
||||
|
||||
color.rgb *= color.a;
|
||||
|
||||
return color;
|
||||
}
|
||||
ENDCG
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"name": "com.coffee.ui-particle",
|
||||
"displayName": "UI Particle",
|
||||
"description": "This package provides a component to render particle effects for uGUI.\nThe particle rendering is maskable and sortable, without the need for an extra Camera, RenderTexture, or Canvas.",
|
||||
"version": "4.12.2",
|
||||
"unity": "2018.2",
|
||||
"version": "5.0.0-preview.15",
|
||||
"unity": "2019.3",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
Reference in New Issue
Block a user