You've already forked ParticleEffectForUGUI
mirror of
https://github.com/mob-sakai/ParticleEffectForUGUI.git
synced 2026-05-15 12:40:08 +00:00
Compare commits
112 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22795fca9a | ||
|
|
1aca69bbb7 | ||
|
|
3619b4ff94 | ||
|
|
cc3e95d8c7 | ||
|
|
5c28e9a2f3 | ||
|
|
b82f79c2de | ||
|
|
f029b7508e | ||
|
|
5c41c39847 | ||
|
|
49f46d5c9e | ||
|
|
628b9582b2 | ||
|
|
e8c9873201 | ||
|
|
fa6881a028 | ||
|
|
e0c8f6ade8 | ||
|
|
612015f7cf | ||
|
|
09c2c95f3b | ||
|
|
3454273095 | ||
|
|
e82b35466b | ||
|
|
50ba446cff | ||
|
|
d4ffadf599 | ||
|
|
4a940d8e31 | ||
|
|
6d8dee0b06 | ||
|
|
67b384a1fe | ||
|
|
990baacdf9 | ||
|
|
f73a6777c4 | ||
|
|
65da5d35f5 | ||
|
|
25a9cdb400 | ||
|
|
c6b2950a75 | ||
|
|
841e449f78 | ||
|
|
9d04e41cde | ||
|
|
f1e672470c | ||
|
|
9d1b6a81ee | ||
|
|
e32077fb0d | ||
|
|
293dc43db7 | ||
|
|
2b5166dcd9 | ||
|
|
ee780c4996 | ||
|
|
e840631fb3 | ||
|
|
a5fdfce554 | ||
|
|
8028b2a770 | ||
|
|
b45dc77312 | ||
|
|
5dab4f21c7 | ||
|
|
f17ecafae7 | ||
|
|
5892df1ce1 | ||
|
|
f0fb205212 | ||
|
|
70e917107d | ||
|
|
eaae94ce00 | ||
|
|
7430c39f52 | ||
|
|
5fc44b82bc | ||
|
|
128990acc6 | ||
|
|
4790db6b93 | ||
|
|
32b93d3eeb | ||
|
|
86de8b6e03 | ||
|
|
b80c3e6c9f | ||
|
|
6a1fef4150 | ||
|
|
3184ba94ae | ||
|
|
6126af9f37 | ||
|
|
c6b816c312 | ||
|
|
5d5eb34590 | ||
|
|
5c3232faf3 | ||
|
|
ac58475539 | ||
|
|
5607dc4eed | ||
|
|
4e4b9eb2a7 | ||
|
|
3fac6e4773 | ||
|
|
45c56bbd85 | ||
|
|
2b8d3b1385 | ||
|
|
c710787b5b | ||
|
|
107f901fe3 | ||
|
|
447996ce0f | ||
|
|
73f6dad0f3 | ||
|
|
3c11209f17 | ||
|
|
3f2f12d2cf | ||
|
|
b9643b98ff | ||
|
|
b36a1571b3 | ||
|
|
c42f8c8ab0 | ||
|
|
9b2e5c1d10 | ||
|
|
821f08ff5c | ||
|
|
28d8698597 | ||
|
|
db28f171f7 | ||
|
|
410304125f | ||
|
|
67eff61073 | ||
|
|
4851a1880e | ||
|
|
2fe0bde422 | ||
|
|
c2119c171a | ||
|
|
3df190382a | ||
|
|
35325c8899 | ||
|
|
903f702d7b | ||
|
|
e93051603e | ||
|
|
e4998365c9 | ||
|
|
68d9925a16 | ||
|
|
392ab6dd76 | ||
|
|
f75fcce0da | ||
|
|
fb31db47f2 | ||
|
|
425aad0cba | ||
|
|
8b4ca1add5 | ||
|
|
b308b26833 | ||
|
|
e67e9482e2 | ||
|
|
723a04d0cf | ||
|
|
52f2ef1f24 | ||
|
|
e92b514624 | ||
|
|
a4bcf93022 | ||
|
|
a499f0c046 | ||
|
|
447c83dbbc | ||
|
|
bdeeabbbe1 | ||
|
|
5e6da2e158 | ||
|
|
f60d6dfe60 | ||
|
|
c795d24003 | ||
|
|
9e2dbe7758 | ||
|
|
4edcef1bbf | ||
|
|
a11d2d01ce | ||
|
|
550d0c43be | ||
|
|
c1538a8399 | ||
|
|
f97e6195e6 | ||
|
|
7eb41124db |
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -26,9 +26,9 @@ A clear and concise description of what you expected to happen.
|
|||||||
If applicable, add screenshots to help explain your problem.
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
**Environment (please complete the following information):**
|
**Environment (please complete the following information):**
|
||||||
- Version [e.g. 1.0.0]
|
- Version [e.g. 4.0.0]
|
||||||
- Platform: [e.g. Editor(Windows/Mac), Standalone(Windows/Mac), iOS, Android, WebGL]
|
- Platform: [e.g. Editor(Windows/Mac), Standalone(Windows/Mac), iOS, Android, WebGL]
|
||||||
- Unity version: [e.g. 2018.2.8f1]
|
- Unity version: [e.g. 2022.3.0f1]
|
||||||
- Build options: [e.g. IL2CPP, .Net 4.x, LWRP]
|
- Build options: [e.g. IL2CPP, .Net 4.x, LWRP]
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
|
|||||||
9
.github/pull_request_template.md
vendored
Normal file
9
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
name: Pull Request
|
||||||
|
about: Create a pull request
|
||||||
|
title: ''
|
||||||
|
assignees: mob-sakai
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**NOTE: Create a pull request to merge into `develop` branch**
|
||||||
24
.github/workflows/release.yml
vendored
24
.github/workflows/release.yml
vendored
@@ -1,24 +0,0 @@
|
|||||||
name: release
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- preview
|
|
||||||
- main
|
|
||||||
- v*.x
|
|
||||||
tags-ignore:
|
|
||||||
- "**"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- uses: cycjimmy/semantic-release-action@v2
|
|
||||||
with:
|
|
||||||
extra_plugins: |
|
|
||||||
@semantic-release/changelog
|
|
||||||
@semantic-release/git
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
|
||||||
69
.github/workflows/test.yml
vendored
69
.github/workflows/test.yml
vendored
@@ -1,69 +0,0 @@
|
|||||||
# Secrets
|
|
||||||
# UNITY_LICENSE:
|
|
||||||
name: test
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- develop
|
|
||||||
tags:
|
|
||||||
- "!*"
|
|
||||||
pull_request:
|
|
||||||
types:
|
|
||||||
- opened
|
|
||||||
- synchronize
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
setup:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
versions: ${{ steps.setup.outputs.versions }}
|
|
||||||
steps:
|
|
||||||
- id: setup
|
|
||||||
run: |
|
|
||||||
VERSIONS=`npx unity-changeset list --versions --all --latest-patch --min 2018.3 --json`
|
|
||||||
echo "==== Target Unity Versions ===="
|
|
||||||
echo "${VERSIONS}"
|
|
||||||
echo "::set-output name=versions::${VERSIONS}"
|
|
||||||
|
|
||||||
test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: setup
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
version: ${{ fromJson(needs.setup.outputs.versions) }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
# Checkout sandbox project
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
ref: sandbox
|
|
||||||
submodules: true
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
# Update package submodule
|
|
||||||
- name: "Update package submodule"
|
|
||||||
working-directory: Packages/dev
|
|
||||||
run: git checkout ${{ github.sha }}
|
|
||||||
|
|
||||||
# Cache
|
|
||||||
- uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: Library
|
|
||||||
key: Library-${{ matrix.version }}-${{ github.sha }}
|
|
||||||
restore-keys: |
|
|
||||||
Library-${{ matrix.version }}-
|
|
||||||
Library-
|
|
||||||
|
|
||||||
# Run tests
|
|
||||||
- name: "Run tests"
|
|
||||||
uses: game-ci/unity-test-runner@v2
|
|
||||||
with:
|
|
||||||
customImage: mobsakai/unity3d:${{ matrix.version }}
|
|
||||||
customParameters: -nographics
|
|
||||||
# unityVersion: ${{ matrix.version }}
|
|
||||||
checkName: ${{ matrix.version }} Test Results
|
|
||||||
githubToken: ${{ github.token }}
|
|
||||||
env:
|
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
{
|
{
|
||||||
"branches": [
|
"branches": [
|
||||||
"+([0-9])?(.{+([0-9]),x}).x",
|
"release",
|
||||||
"master",
|
"release-4.x",
|
||||||
"main",
|
|
||||||
{
|
{
|
||||||
"name": "preview",
|
"name": "release-preview",
|
||||||
"prerelease": true
|
"prerelease": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"tagFormat": "${version}",
|
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"@semantic-release/commit-analyzer",
|
"@semantic-release/commit-analyzer",
|
||||||
"@semantic-release/release-notes-generator",
|
"@semantic-release/release-notes-generator",
|
||||||
|
|||||||
234
CHANGELOG.md
234
CHANGELOG.md
@@ -1,3 +1,237 @@
|
|||||||
|
# [4.7.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.8...v4.7.0) (2024-06-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* `UIParticle.transform.localScale` does not scale particles ([1d40e24](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/1d40e24c742741e97f03c55468ccb1e505341133)), closes [#313](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/313)
|
||||||
|
* UIParticle is scaled by canvas size even when `AutoScalingMode.None` and `ScalingMode.Local` ([54a4b1c](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/54a4b1cdfd06400c7be89c1ee704bb42a659c7c2)), closes [#313](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/313)
|
||||||
|
* UIParticle is scaled incorrectly with nested canvases ([f26920f](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/f26920f9825547222a4afbb31cc5dc5a002c3e9b)), closes [#313](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/313)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* reset previous position on start play for world space simulation ([3880484](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/3880484ce5190c42fc79c81d0b69e3fbeda09dd0)), closes [#303](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/303)
|
||||||
|
* restore `Transform.localScale` when setting `autoScalingMode` to something other than `Transform` ([5505247](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/5505247a94a929ff89635fde512a9b95691e0043))
|
||||||
|
|
||||||
|
## [4.6.8](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.7...v4.6.8) (2024-06-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 'Resource ID out of range in GetResource' error in overlay rendering mode ([05286ce](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/05286cedfd17b1a0cb90a5e918513644f47cd831)), closes [#308](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/308)
|
||||||
|
|
||||||
|
## [4.6.7](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.6...v4.6.7) (2024-05-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* the ParticleSystem's localPosition drifts at certain scales due to floating-point precision issues ([e924eb4](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/e924eb45968a112347471cabaeabc274e4c37ce4)), closes [#299](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/299) [#312](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/312)
|
||||||
|
|
||||||
|
## [4.6.6](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.5...v4.6.6) (2024-05-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix release workflow ([30b0076](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/30b00762f6da166c043587798b1552f27b4cc604))
|
||||||
|
|
||||||
|
## [4.6.5](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.4...v4.6.5) (2024-05-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* update workflows (for preview and v4) ([3eab097](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/3eab0979b9b85919b804442ab05735b7120eade5))
|
||||||
|
|
||||||
|
## [4.6.4](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.3...v4.6.4) (2024-05-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* assertion failed on expression: 'ps->array_size()' ([1b5c359](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/1b5c359058289895caf5f245fe09abb643bc38eb)), closes [#278](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/278)
|
||||||
|
* lost Material.mainTexture when using AnimatableProperties ([ea04352](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/ea043524c0b00f67cba26a1f9ea537ee4a56d6ff)), closes [#311](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/311)
|
||||||
|
* remove unnecessary code ([c37c014](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c37c01486499773e3d7e8296c95bb4c3fae94abb))
|
||||||
|
|
||||||
|
## [4.6.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.2...v4.6.3) (2024-04-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* if only Trail Material is used, it will not be displayed ([2eff411](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/2eff411bd97eb4e6947d29a02b85b414bfdaee3a)), closes [#294](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/294)
|
||||||
|
* if the UIParticle parents do not have Canvas, an exception is thrown in OnEnable ([e82c833](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/e82c833d04b819f103984931ba29a3616ef50908)), closes [#300](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/300)
|
||||||
|
* particle size too small due to auto scaling ([2ec3748](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/2ec374833614d64406e7c3207ca5fe234a749dcb)), closes [#295](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/295)
|
||||||
|
|
||||||
|
## [4.6.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.1...v4.6.2) (2024-02-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix compile error in Unity 2021.1 or older ([fcae60b](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/fcae60bf29079bac07463bd3a86f8644151d72ba))
|
||||||
|
* fix demos ([ad20d12](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/ad20d128a2ad033d9f30b98f0a0dab6091f5aa19))
|
||||||
|
* fix warning ([7fd4a8e](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/7fd4a8e343ce587dffa9db5ff186061b3ebb38a6))
|
||||||
|
|
||||||
|
## [4.6.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.0...v4.6.1) (2024-01-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* unintended scaling occurs when `AutoScalingMode=UIParticle` and `ScalingMode=Local` ([1627de1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/1627de10eb1e742a015603ae9939071665a5bd89)), closes [#292](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/292)
|
||||||
|
|
||||||
|
# [4.6.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.5.2...v4.6.0) (2024-01-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix abnormal mesh bounds error ([772bf50](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/772bf50d168982bd401c30e58172e0a60fbafe46)), closes [#213](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/213)
|
||||||
|
* fix warning ([93d3919](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/93d3919b6fb6ac186b3e99f8baaef9a044f583f2))
|
||||||
|
* fix warning ([8a78ec1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/8a78ec13ad2aad9138a22b67c332871e064a38cc))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* "[generated]" GameObjects on the hierarchy is disturbing ([7c42421](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/7c4242150b591daf64390588afa27efa27368af3)), closes [#288](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/288)
|
||||||
|
* add explicit dependencies ([9a0187a](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/9a0187a72a35d378ff7be965bfcb7475f423fe0f))
|
||||||
|
* add icon ([0c1022c](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/0c1022c6224394713f62b41e5e4ef0c289610ae1))
|
||||||
|
* remove samples ([f53a7fa](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/f53a7faed3ee73ac22d745a778284e818624b510))
|
||||||
|
|
||||||
|
# [4.6.0-preview.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.5.2...v4.6.0-preview.1) (2024-01-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix abnormal mesh bounds error ([772bf50](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/772bf50d168982bd401c30e58172e0a60fbafe46)), closes [#213](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/213)
|
||||||
|
* fix warning ([93d3919](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/93d3919b6fb6ac186b3e99f8baaef9a044f583f2))
|
||||||
|
* fix warning ([8a78ec1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/8a78ec13ad2aad9138a22b67c332871e064a38cc))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* "[generated]" GameObjects on the hierarchy is disturbing ([7c42421](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/7c4242150b591daf64390588afa27efa27368af3)), closes [#288](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/288)
|
||||||
|
* add explicit dependencies ([9a0187a](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/9a0187a72a35d378ff7be965bfcb7475f423fe0f))
|
||||||
|
* add icon ([0c1022c](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/0c1022c6224394713f62b41e5e4ef0c289610ae1))
|
||||||
|
* remove samples ([f53a7fa](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/f53a7faed3ee73ac22d745a778284e818624b510))
|
||||||
|
|
||||||
|
## [4.5.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.5.1...4.5.2) (2024-01-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* (editor) sometimes crashes when entering play mode ([b80c3e6](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/b80c3e6c9fdd2a8fb72ff233edb85df2e3dbba3d))
|
||||||
|
|
||||||
|
## [4.5.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.5.0...4.5.1) (2023-12-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix material for mesh sharing group ([6126af9](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/6126af9f376dd4c100a1b9d19d9499bdef7d5566))
|
||||||
|
* the changes made to the material used by the ParticleSystem are not immediately reflected ([3184ba9](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/3184ba94ae08264223c0c71443ad70acc1a1ccb2)), closes [#280](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/280)
|
||||||
|
|
||||||
|
# [4.5.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.4.0...4.5.0) (2023-12-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* incorrect rendering of world-space simulated particles while animating scale ([ac58475](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/ac584755393d87bda2e80d9653370b7e4c68912f)), closes [#285](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/285)
|
||||||
|
* remove obsolete warning ([5d5eb34](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/5d5eb34590b7cefb0e4ac26c0441e104176ce522))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Automatically generated objects are no longer editable (NotEditable). ([5607dc4](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/5607dc4eed0c086b4651941953df6c7d535712e0))
|
||||||
|
* support IMeshModifier ([5c3232f](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/5c3232faf3d2cfad1e3e1a9349b8346c7982a608)), closes [#282](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/282)
|
||||||
|
|
||||||
|
# [4.4.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.3.0...4.4.0) (2023-11-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* support 'Active Apply Color Space' for linear color space ([45c56bb](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/45c56bbd850202365751ea019baf5131b2eb9fbe))
|
||||||
|
|
||||||
|
# [4.3.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.2.2...4.3.0) (2023-11-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* added 'autoScalingMode (None, Transform.localScale, UIParticle.scale)' instead of 'autoScaling' ([107f901](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/107f901fe3232223322681edc4bf908642474298))
|
||||||
|
* reset transform.localScale on upgrading v3.x to v4.x ([c710787](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c710787b5ba496cf73e7eb43458bb3958139baa9)), closes [#277](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/277)
|
||||||
|
|
||||||
|
## [4.2.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.2.1...4.2.2) (2023-10-25)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* il2cpp code stripping bug ([73f6dad](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/73f6dad0f33641a76ddd05ffc6812ced3f8a276d)), closes [#269](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/269)
|
||||||
|
|
||||||
|
## [4.2.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.2.0...4.2.1) (2023-08-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* autoScaling and PositionMode may be locked ([3f2f12d](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/3f2f12d2cf7541118c02830ec9fdea8183357487))
|
||||||
|
|
||||||
|
# [4.2.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.1.7...4.2.0) (2023-08-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* assertion 'ps->array_size()' in UpdateMesh() when using trails of type ribbon ([f75fcce](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/f75fcce0dae0bc166bd01d36a150aded1fd721f3)), closes [#241](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/241)
|
||||||
|
* built-in shaders are no longer supported ([c2119c1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c2119c171a1262431eac7fea6bf3125db2bcaaca)), closes [#233](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/233) [#257](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/257)
|
||||||
|
* crash occurs when too many vertices are rendered ([723a04d](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/723a04d0cfd156715a3c92b6d6bd75fdc1862c28))
|
||||||
|
* error: SerializedObject target has been destroyed ([e930516](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/e93051603e121732c92bcd89ded48087c2b0d7fb)), closes [#267](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/267)
|
||||||
|
* excessive particle emitted on move ParticleSystem for local space simulation and emission over distance ([2fe0bde](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/2fe0bde422f9769dfedaf6b053ea07f773646679)), closes [#265](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/265)
|
||||||
|
* fix typos ([52f2ef1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/52f2ef1f2471a2e1c29fca96255c04b222d9c848))
|
||||||
|
* generated GameObject will be named '[generated] *' ([9b2e5c1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/9b2e5c1d1024e091de6d18a4578cd18b43563e48))
|
||||||
|
* inactive ParticleSystems are removed from the list on refresh ([4851a18](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/4851a1880eef9f385dd9db644ea7e544f95da4fc))
|
||||||
|
* mesh sharing not working ([8b4ca1a](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/8b4ca1add5c409601e840253e1c0dbcdbf536da8)), closes [#236](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/236)
|
||||||
|
* nullptr exceptions when using nested UIParticle components in hierarchy ([e67e948](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/e67e9482e2cb840b16e2cfe76e04f7423fcbd3a3)), closes [#246](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/246)
|
||||||
|
* nullReferenceException after copy-n-paste ([425aad0](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/425aad0cbab475635c72bee84ecbf3f2acedccc2)), closes [#258](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/258)
|
||||||
|
* remove unnecessary per-frame allocation. ([e92b514](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/e92b514624cc362e53ddeae5ade20fa732f94c7c))
|
||||||
|
* scaling ParticleSystem puts prewarmed particles in wrong location ([fb31db4](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/fb31db47f2debb3aadbdc4d1b88d0efd9c4ad7bd)), closes [#235](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/235)
|
||||||
|
* sub-emitters option is not work in editor playing ([b308b26](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/b308b2683372662bb834b6f6d23ea3435a68d1b3)), closes [#231](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/231)
|
||||||
|
* the camera under UIParticle will be assigned as _orthoCamera ([c42f8c8](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c42f8c8ab0ff033689349a81e02a4808e071a8a2))
|
||||||
|
* UIParticleAttractor attracts the particles at wrong position when in RelativeMode ([68d9925](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/68d9925a16237df3c7b07b4781172cbd03425421)), closes [#262](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/262)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 'AbsoluteMode' option is renamed to 'PositionMode' ([67eff61](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/67eff610736344ba0122163ff5ee63b25c43f555))
|
||||||
|
* 'AutoScaling' option will be imported from 'IgnoreCanvasScale' (for v3.x) ([4103041](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/410304125f3f25f3f543c7bc01dcc661eab00609))
|
||||||
|
* add 'AutoScaling' option for UIParticle ([35325c8](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/35325c88996fa6aea19a6dd1395c05884e1f84ae))
|
||||||
|
* add 'UpdateMode' option for UIParticleAttractor ([903f702](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/903f702d7be38228841a5a693e3afdceb4a59d9f)), closes [#250](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/250)
|
||||||
|
* add particle system getter and setter for attractor ([a4bcf93](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/a4bcf93022d2729f3d2a74a2cac4f52e68641b18)), closes [#253](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/253)
|
||||||
|
* add public properties for UIParticleAttractor ([392ab6d](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/392ab6dd76c36e815320d3a50744d19faa631260)), closes [#253](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/253)
|
||||||
|
* add Start/StopEmission API for UIParticle ([e499836](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/e4998365c9825fa385e0a317768ce073a1f15b48)), closes [#240](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/240)
|
||||||
|
|
||||||
|
## [4.1.7](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.1.6...4.1.7) (2022-08-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* the annoying empty black scene overlay box shown even when nothing is selected ([bdeeabb](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/bdeeabbbe140b0ba80fac7ac477874c2467d3a16))
|
||||||
|
|
||||||
|
## [4.1.6](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.1.5...4.1.6) (2022-08-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix abnormal mesh bounds error ([f60d6df](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/f60d6dfe6030ac89527a4265e414e9a0a20d56db)), closes [#213](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/213) [#218](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/218)
|
||||||
|
|
||||||
|
## [4.1.5](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.1.4...4.1.5) (2022-08-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix culling for RectMask2D ([9e2dbe7](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/9e2dbe7758eb28a4f6a7c11113d9169847880f96)), closes [#220](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/220)
|
||||||
|
|
||||||
|
## [4.1.4](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.1.3...4.1.4) (2022-07-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add `Enabled` toggle in overlay window ([f97e619](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/f97e6195e62b5acfa8f3e97bfe3bc4a7dcadf38a))
|
||||||
|
* if `m_Particles` contains null, an error will occur ([550d0c4](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/550d0c43be35cd07e390ffd5749557c89fee0332)), closes [#214](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/214)
|
||||||
|
* ParticleSystem reordering and refreshing in inspector does not work for prefab asset ([7eb4112](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/7eb41124db06ea794db76788b35ce82a0af2c402))
|
||||||
|
* refresh button does not works in prefab edit mode ([c1538a8](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c1538a83998608a30dc90944b05f8b75e165cf05)), closes [#214](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/214)
|
||||||
|
* when `UIParticlrRenderer` destroy manually, an error will occur ([a11d2d0](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/a11d2d01ce5f67e3f430bcb0bfdee1ad9abf7cfe))
|
||||||
|
|
||||||
## [4.1.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.1.2...4.1.3) (2022-06-28)
|
## [4.1.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.1.2...4.1.3) (2022-06-28)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -81,4 +81,4 @@ Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcem
|
|||||||
[homepage]: https://www.contributor-covenant.org
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
|
||||||
For answers to common questions about this code of conduct, see the FAQ at
|
For answers to common questions about this code of conduct, see the FAQ at
|
||||||
https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
|
https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
|
||||||
|
|||||||
@@ -19,11 +19,24 @@ When fixing a bug it is fine to submit a pull request right away.
|
|||||||
|
|
||||||
Steps to be performed to submit a pull request:
|
Steps to be performed to submit a pull request:
|
||||||
|
|
||||||
1. Fork the repository and create your branch from `develop`.
|
1. Fork the repository.
|
||||||
2. If you have fixed a bug or added code that should be tested, add tests.
|
2. Clone the repository.
|
||||||
3. Click `Window > Generals > Test Runner` to test
|
3. Checkout `develop` branch.
|
||||||
4. Commit with a massage based on [Angular Commit Message Conventions](https://gist.github.com/stephenparish/9941e89d80e2bc58a153).
|
4. Develop the package.
|
||||||
5. Fill out the description, link any related issues and submit your pull request.
|
5. Test the package with the test runner (`Window > Generals > Test Runner`).
|
||||||
|
6. Commit with a message based
|
||||||
|
on [Angular Commit Message Conventions](https://gist.github.com/stephenparish/9941e89d80e2bc58a153) as follows:
|
||||||
|
|
||||||
|
- `fix:` fix a bug
|
||||||
|
- `feat:` new feature
|
||||||
|
- `docs:` changes only in documentation
|
||||||
|
- `style:` changes only in formatting, white-space, etc
|
||||||
|
- `refactor:` changes only in code structure (extract method, rename variable, move method, etc)
|
||||||
|
- `perf:` changes only in code performance
|
||||||
|
- `test:` add or update tests
|
||||||
|
- `chore:` changes to the build process or auxiliary tools and libraries such as documentation generation
|
||||||
|
|
||||||
|
7. Create a pull request on GitHub. Fill out the description, link any related issues and submit your pull request.
|
||||||
|
|
||||||
#### License
|
#### License
|
||||||
|
|
||||||
|
|||||||
143
Editor/AnimatablePropertyEditor.cs
Normal file
143
Editor/AnimatablePropertyEditor.cs
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Coffee.UIExtensions
|
||||||
|
{
|
||||||
|
internal static class AnimatablePropertyEditor
|
||||||
|
{
|
||||||
|
private static readonly GUIContent s_ContentNothing = new GUIContent("Nothing");
|
||||||
|
private static readonly List<string> s_ActiveNames = new List<string>();
|
||||||
|
private static readonly StringBuilder s_Sb = new StringBuilder();
|
||||||
|
private static readonly HashSet<string> s_Names = new HashSet<string>();
|
||||||
|
|
||||||
|
private static string CollectActiveNames(SerializedProperty sp, List<string> result)
|
||||||
|
{
|
||||||
|
result.Clear();
|
||||||
|
for (var i = 0; i < sp.arraySize; i++)
|
||||||
|
{
|
||||||
|
var spName = sp.GetArrayElementAtIndex(i).FindPropertyRelative("m_Name");
|
||||||
|
if (spName == null) continue;
|
||||||
|
|
||||||
|
result.Add(spName.stringValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
s_Sb.Length = 0;
|
||||||
|
if (result.Count == 0)
|
||||||
|
{
|
||||||
|
s_Sb.Append("Nothing");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Aggregate(s_Sb, (a, b) => s_Sb.AppendFormat("{0}, ", b));
|
||||||
|
s_Sb.Length -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_Sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Draw(SerializedProperty sp, Material[] mats)
|
||||||
|
{
|
||||||
|
bool isClicked;
|
||||||
|
using (new EditorGUILayout.HorizontalScope(GUILayout.ExpandWidth(false)))
|
||||||
|
{
|
||||||
|
var pos = EditorGUILayout.GetControlRect(true);
|
||||||
|
var label = new GUIContent(sp.displayName, sp.tooltip);
|
||||||
|
var rect = EditorGUI.PrefixLabel(pos, label);
|
||||||
|
var text = sp.hasMultipleDifferentValues
|
||||||
|
? "-"
|
||||||
|
: CollectActiveNames(sp, s_ActiveNames);
|
||||||
|
isClicked = GUI.Button(rect, text, EditorStyles.popup);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isClicked) return;
|
||||||
|
|
||||||
|
var gm = new GenericMenu();
|
||||||
|
gm.AddItem(s_ContentNothing, s_ActiveNames.Count == 0, () =>
|
||||||
|
{
|
||||||
|
sp.ClearArray();
|
||||||
|
sp.serializedObject.ApplyModifiedProperties();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!sp.hasMultipleDifferentValues)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < sp.arraySize; i++)
|
||||||
|
{
|
||||||
|
var p = sp.GetArrayElementAtIndex(i);
|
||||||
|
var name = p.FindPropertyRelative("m_Name").stringValue;
|
||||||
|
var type = (AnimatableProperty.ShaderPropertyType)p.FindPropertyRelative("m_Type").intValue;
|
||||||
|
AddMenu(gm, sp, new ShaderProperty(name, type), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_Names.Clear();
|
||||||
|
for (var j = 0; j < mats.Length; j++)
|
||||||
|
{
|
||||||
|
var mat = mats[j];
|
||||||
|
if (!mat || !mat.shader) continue;
|
||||||
|
|
||||||
|
for (var i = 0; i < ShaderUtil.GetPropertyCount(mat.shader); i++)
|
||||||
|
{
|
||||||
|
var name = ShaderUtil.GetPropertyName(mat.shader, i);
|
||||||
|
var type = (AnimatableProperty.ShaderPropertyType)ShaderUtil.GetPropertyType(mat.shader, i);
|
||||||
|
if (s_Names.Contains(name)) continue;
|
||||||
|
s_Names.Add(name);
|
||||||
|
|
||||||
|
AddMenu(gm, sp, new ShaderProperty(name, type), true);
|
||||||
|
|
||||||
|
if (type != AnimatableProperty.ShaderPropertyType.Texture) continue;
|
||||||
|
|
||||||
|
AddMenu(gm, sp, new ShaderProperty($"{name}_ST"), true);
|
||||||
|
AddMenu(gm, sp, new ShaderProperty($"{name}_HDR"), true);
|
||||||
|
AddMenu(gm, sp, new ShaderProperty($"{name}_TexelSize"), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gm.ShowAsContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddMenu(GenericMenu menu, SerializedProperty sp, ShaderProperty prop, bool add)
|
||||||
|
{
|
||||||
|
if (add && s_ActiveNames.Contains(prop.name)) return;
|
||||||
|
|
||||||
|
var label = new GUIContent($"{prop.name} ({prop.type})");
|
||||||
|
menu.AddItem(label, s_ActiveNames.Contains(prop.name), () =>
|
||||||
|
{
|
||||||
|
var index = s_ActiveNames.IndexOf(prop.name);
|
||||||
|
if (0 <= index)
|
||||||
|
{
|
||||||
|
sp.DeleteArrayElementAtIndex(index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sp.InsertArrayElementAtIndex(sp.arraySize);
|
||||||
|
var p = sp.GetArrayElementAtIndex(sp.arraySize - 1);
|
||||||
|
p.FindPropertyRelative("m_Name").stringValue = prop.name;
|
||||||
|
p.FindPropertyRelative("m_Type").intValue = (int)prop.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp.serializedObject.ApplyModifiedProperties();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct ShaderProperty
|
||||||
|
{
|
||||||
|
public readonly string name;
|
||||||
|
public readonly AnimatableProperty.ShaderPropertyType type;
|
||||||
|
|
||||||
|
public ShaderProperty(string name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
type = AnimatableProperty.ShaderPropertyType.Vector;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderProperty(string name, AnimatableProperty.ShaderPropertyType type)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,23 @@
|
|||||||
#if UNITY_2019_3_11 || UNITY_2019_3_12 || UNITY_2019_3_13 || UNITY_2019_3_14 || UNITY_2019_3_15 || UNITY_2019_4_OR_NEWER
|
|
||||||
#define SERIALIZE_FIELD_MASKABLE
|
|
||||||
#endif
|
|
||||||
using UnityEditor;
|
|
||||||
using UnityEditor.UI;
|
|
||||||
using UnityEngine;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.UI;
|
||||||
using UnityEditorInternal;
|
using UnityEditorInternal;
|
||||||
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using System;
|
using Coffee.UIParticleExtensions;
|
||||||
#if UNITY_2021_2_OR_NEWER
|
#if UNITY_2021_2_OR_NEWER
|
||||||
using UnityEditor.Overlays;
|
using UnityEditor.Overlays;
|
||||||
#else
|
#else
|
||||||
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
#endif
|
||||||
|
#if UNITY_2021_2_OR_NEWER
|
||||||
|
using UnityEditor.SceneManagement;
|
||||||
|
#elif UNITY_2018_3_OR_NEWER
|
||||||
|
using UnityEditor.Experimental.SceneManagement;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Coffee.UIExtensions
|
namespace Coffee.UIExtensions
|
||||||
@@ -23,7 +28,10 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
#if UNITY_2021_2_OR_NEWER
|
#if UNITY_2021_2_OR_NEWER
|
||||||
#if UNITY_2022_1_OR_NEWER
|
#if UNITY_2022_1_OR_NEWER
|
||||||
[Overlay(typeof(SceneView), "Scene View/UI Particles", "UI Particles", true, defaultDockPosition = DockPosition.Bottom, defaultDockZone = DockZone.Floating, defaultLayout = Layout.Panel)]
|
[Overlay(typeof(SceneView), "Scene View/UI Particles", "UI Particles", true,
|
||||||
|
defaultDockPosition = DockPosition.Bottom,
|
||||||
|
defaultDockZone = DockZone.Floating,
|
||||||
|
defaultLayout = Layout.Panel)]
|
||||||
#else
|
#else
|
||||||
[Overlay(typeof(SceneView), "Scene View/UI Particles", "UI Particles", true)]
|
[Overlay(typeof(SceneView), "Scene View/UI Particles", "UI Particles", true)]
|
||||||
#endif
|
#endif
|
||||||
@@ -35,7 +43,7 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
if (visible)
|
if (visible)
|
||||||
{
|
{
|
||||||
WindowFunction(null, null);
|
WindowFunction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,24 +61,23 @@ namespace Coffee.UIExtensions
|
|||||||
private static readonly GUIContent s_ContentRandom = new GUIContent("Random");
|
private static readonly GUIContent s_ContentRandom = new GUIContent("Random");
|
||||||
private static readonly GUIContent s_ContentScale = new GUIContent("Scale");
|
private static readonly GUIContent s_ContentScale = new GUIContent("Scale");
|
||||||
private static SerializedObject s_SerializedObject;
|
private static SerializedObject s_SerializedObject;
|
||||||
|
private static bool s_XYZMode;
|
||||||
|
|
||||||
#if !SERIALIZE_FIELD_MASKABLE
|
private SerializedProperty _maskable;
|
||||||
private SerializedProperty m_Maskable;
|
private SerializedProperty _scale3D;
|
||||||
#endif
|
private SerializedProperty _animatableProperties;
|
||||||
private SerializedProperty m_Scale3D;
|
private SerializedProperty _meshSharing;
|
||||||
private SerializedProperty m_AnimatableProperties;
|
private SerializedProperty _groupId;
|
||||||
private SerializedProperty m_MeshSharing;
|
private SerializedProperty _groupMaxId;
|
||||||
private SerializedProperty m_GroupId;
|
private SerializedProperty _positionMode;
|
||||||
private SerializedProperty m_GroupMaxId;
|
private SerializedProperty _autoScalingMode;
|
||||||
private SerializedProperty m_AbsoluteMode;
|
|
||||||
|
|
||||||
|
|
||||||
private ReorderableList _ro;
|
private ReorderableList _ro;
|
||||||
static private bool _xyzMode;
|
|
||||||
private bool _showMax;
|
private bool _showMax;
|
||||||
|
|
||||||
private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>();
|
private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>();
|
||||||
|
#if UNITY_2018 || UNITY_2019
|
||||||
private static readonly List<ParticleSystemVertexStream> s_Streams = new List<ParticleSystemVertexStream>();
|
private static readonly List<ParticleSystemVertexStream> s_Streams = new List<ParticleSystemVertexStream>();
|
||||||
|
#endif
|
||||||
private static readonly List<string> s_MaskablePropertyNames = new List<string>
|
private static readonly List<string> s_MaskablePropertyNames = new List<string>
|
||||||
{
|
{
|
||||||
"_Stencil",
|
"_Stencil",
|
||||||
@@ -78,21 +85,20 @@ namespace Coffee.UIExtensions
|
|||||||
"_StencilOp",
|
"_StencilOp",
|
||||||
"_StencilWriteMask",
|
"_StencilWriteMask",
|
||||||
"_StencilReadMask",
|
"_StencilReadMask",
|
||||||
"_ColorMask",
|
"_ColorMask"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
[InitializeOnLoadMethod]
|
[InitializeOnLoadMethod]
|
||||||
static void Init()
|
private static void Init()
|
||||||
{
|
{
|
||||||
#if !UNITY_2021_2_OR_NEWER
|
#if !UNITY_2021_2_OR_NEWER
|
||||||
var miSceneViewOverlayWindow = Type.GetType("UnityEditor.SceneViewOverlay, UnityEditor")
|
var miSceneViewOverlayWindow = Type.GetType("UnityEditor.SceneViewOverlay, UnityEditor")
|
||||||
.GetMethods(BindingFlags.Public | BindingFlags.Static)
|
?.GetMethods(BindingFlags.Public | BindingFlags.Static)
|
||||||
.First(x => x.Name == "Window" && 5 <= x.GetParameters().Length);
|
.First(x => x.Name == "Window" && 5 <= x.GetParameters().Length);
|
||||||
var windowFunction = (Action<UnityEngine.Object, SceneView>)WindowFunction;
|
var windowFunction = (Action<Object, SceneView>)WindowFunction;
|
||||||
var windowFunctionType = Type.GetType("UnityEditor.SceneViewOverlay+WindowFunction, UnityEditor");
|
var windowFunctionType = Type.GetType("UnityEditor.SceneViewOverlay+WindowFunction, UnityEditor");
|
||||||
var windowFunctionDelegate = Delegate.CreateDelegate(windowFunctionType, windowFunction.Method);
|
var windowFunctionDelegate = Delegate.CreateDelegate(windowFunctionType, windowFunction.Method);
|
||||||
var windowTitle = new GUIContent(ObjectNames.NicifyVariableName(typeof(UIParticle).Name));
|
var windowTitle = new GUIContent(ObjectNames.NicifyVariableName(nameof(UIParticle)));
|
||||||
#if UNITY_2019_2_OR_NEWER
|
#if UNITY_2019_2_OR_NEWER
|
||||||
//public static void Window(GUIContent title, WindowFunction sceneViewFunc, int order, Object target, WindowDisplayOption option, EditorWindow window = null)
|
//public static void Window(GUIContent title, WindowFunction sceneViewFunc, int order, Object target, WindowDisplayOption option, EditorWindow window = null)
|
||||||
var sceneViewArgs = new object[] { windowTitle, windowFunctionDelegate, 599, null, 2, null };
|
var sceneViewArgs = new object[] { windowTitle, windowFunctionDelegate, 599, null, 2, null };
|
||||||
@@ -102,7 +108,7 @@ namespace Coffee.UIExtensions
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if UNITY_2019_1_OR_NEWER
|
#if UNITY_2019_1_OR_NEWER
|
||||||
SceneView.duringSceneGui += _ => miSceneViewOverlayWindow.Invoke(null, sceneViewArgs);
|
SceneView.duringSceneGui += _ =>
|
||||||
#else
|
#else
|
||||||
SceneView.onSceneGUIDelegate += _ =>
|
SceneView.onSceneGUIDelegate += _ =>
|
||||||
#endif
|
#endif
|
||||||
@@ -114,25 +120,22 @@ namespace Coffee.UIExtensions
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Func<SerializedObject> createSerializeObject = () =>
|
SerializedObject CreateSerializeObject()
|
||||||
{
|
{
|
||||||
var uiParticles = Selection.gameObjects
|
var uiParticles = Selection.gameObjects.Select(x => x.GetComponent<ParticleSystem>())
|
||||||
.Select(x => x.GetComponent<ParticleSystem>())
|
.Where(x => x)
|
||||||
.Where(x => x)
|
.Select(x => x.GetComponentInParent<UIParticle>(true))
|
||||||
.Select(x => x.GetComponentInParent<UIParticle>())
|
.Where(x => x && x.canvas)
|
||||||
.Where(x => x)
|
.Concat(Selection.gameObjects.Select(x => x.GetComponent<UIParticle>())
|
||||||
.Concat(
|
.Where(x => x && x.canvas))
|
||||||
Selection.gameObjects
|
.Distinct()
|
||||||
.Select(x => x.GetComponent<UIParticle>())
|
.OfType<Object>()
|
||||||
.Where(x => x)
|
.ToArray();
|
||||||
)
|
return 0 < uiParticles.Length ? new SerializedObject(uiParticles) : null;
|
||||||
.Distinct()
|
}
|
||||||
.ToArray();
|
|
||||||
return uiParticles.Any() ? new SerializedObject(uiParticles) : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
s_SerializedObject = createSerializeObject();
|
s_SerializedObject = CreateSerializeObject();
|
||||||
Selection.selectionChanged += () => s_SerializedObject = createSerializeObject();
|
Selection.selectionChanged += () => s_SerializedObject = CreateSerializeObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
//################################
|
//################################
|
||||||
@@ -145,69 +148,71 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
base.OnEnable();
|
base.OnEnable();
|
||||||
|
|
||||||
m_Maskable = serializedObject.FindProperty("m_Maskable");
|
_maskable = serializedObject.FindProperty("m_Maskable");
|
||||||
m_Scale3D = serializedObject.FindProperty("m_Scale3D");
|
_scale3D = serializedObject.FindProperty("m_Scale3D");
|
||||||
m_AnimatableProperties = serializedObject.FindProperty("m_AnimatableProperties");
|
_animatableProperties = serializedObject.FindProperty("m_AnimatableProperties");
|
||||||
m_MeshSharing = serializedObject.FindProperty("m_MeshSharing");
|
_meshSharing = serializedObject.FindProperty("m_MeshSharing");
|
||||||
m_GroupId = serializedObject.FindProperty("m_GroupId");
|
_groupId = serializedObject.FindProperty("m_GroupId");
|
||||||
m_GroupMaxId = serializedObject.FindProperty("m_GroupMaxId");
|
_groupMaxId = serializedObject.FindProperty("m_GroupMaxId");
|
||||||
m_AbsoluteMode = serializedObject.FindProperty("m_AbsoluteMode");
|
_positionMode = serializedObject.FindProperty("m_PositionMode");
|
||||||
|
_autoScalingMode = serializedObject.FindProperty("m_AutoScalingMode");
|
||||||
|
|
||||||
var sp = serializedObject.FindProperty("m_Particles");
|
var sp = serializedObject.FindProperty("m_Particles");
|
||||||
_ro = new ReorderableList(sp.serializedObject, sp, true, true, true, true);
|
_ro = new ReorderableList(sp.serializedObject, sp, true, true, true, true)
|
||||||
_ro.elementHeight = EditorGUIUtility.singleLineHeight * 3 + 4;
|
|
||||||
_ro.elementHeightCallback = _ => 3 * (EditorGUIUtility.singleLineHeight + 2);
|
|
||||||
_ro.drawElementCallback = (rect, index, active, focused) =>
|
|
||||||
{
|
{
|
||||||
EditorGUI.BeginDisabledGroup(sp.hasMultipleDifferentValues);
|
elementHeight = EditorGUIUtility.singleLineHeight * 3 + 4,
|
||||||
rect.y += 1;
|
elementHeightCallback = _ => 3 * (EditorGUIUtility.singleLineHeight + 2),
|
||||||
rect.height = EditorGUIUtility.singleLineHeight;
|
drawElementCallback = (rect, index, _, __) =>
|
||||||
var p = sp.GetArrayElementAtIndex(index);
|
|
||||||
EditorGUI.ObjectField(rect, p, GUIContent.none);
|
|
||||||
rect.x += 15;
|
|
||||||
rect.width -= 15;
|
|
||||||
var ps = p.objectReferenceValue as ParticleSystem;
|
|
||||||
var materials = ps
|
|
||||||
? new SerializedObject(ps.GetComponent<ParticleSystemRenderer>()).FindProperty("m_Materials")
|
|
||||||
: null;
|
|
||||||
rect.y += rect.height + 1;
|
|
||||||
MaterialField(rect, s_ContentMaterial, materials, 0);
|
|
||||||
rect.y += rect.height + 1;
|
|
||||||
MaterialField(rect, s_ContentTrailMaterial, materials, 1);
|
|
||||||
EditorGUI.EndDisabledGroup();
|
|
||||||
if (materials != null)
|
|
||||||
{
|
{
|
||||||
materials.serializedObject.ApplyModifiedProperties();
|
EditorGUI.BeginDisabledGroup(sp.hasMultipleDifferentValues);
|
||||||
}
|
rect.y += 1;
|
||||||
};
|
rect.height = EditorGUIUtility.singleLineHeight;
|
||||||
_ro.drawHeaderCallback = rect =>
|
var p = sp.GetArrayElementAtIndex(index);
|
||||||
{
|
EditorGUI.ObjectField(rect, p, GUIContent.none);
|
||||||
#if !UNITY_2019_3_OR_NEWER
|
rect.x += 15;
|
||||||
rect.y -= 1;
|
rect.width -= 15;
|
||||||
#endif
|
var ps = p.objectReferenceValue as ParticleSystem;
|
||||||
EditorGUI.LabelField(new Rect(rect.x, rect.y, 150, rect.height), s_ContentRenderingOrder);
|
var materials = ps
|
||||||
|
? new SerializedObject(ps.GetComponent<ParticleSystemRenderer>()).FindProperty("m_Materials")
|
||||||
if (GUI.Button(new Rect(rect.width - 35, rect.y, 60, rect.height), s_ContentRefresh, EditorStyles.miniButton))
|
: null;
|
||||||
{
|
rect.y += rect.height + 1;
|
||||||
foreach (UIParticle t in targets)
|
MaterialField(rect, s_ContentMaterial, materials, 0);
|
||||||
|
rect.y += rect.height + 1;
|
||||||
|
MaterialField(rect, s_ContentTrailMaterial, materials, 1);
|
||||||
|
EditorGUI.EndDisabledGroup();
|
||||||
|
if (materials != null && materials.serializedObject.hasModifiedProperties)
|
||||||
{
|
{
|
||||||
t.RefreshParticles();
|
materials.serializedObject.ApplyModifiedProperties();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
drawHeaderCallback = rect =>
|
||||||
_ro.onReorderCallback = _ =>
|
|
||||||
{
|
|
||||||
foreach (UIParticle t in targets)
|
|
||||||
{
|
{
|
||||||
t.RefreshParticles(t.particles);
|
#if !UNITY_2019_3_OR_NEWER
|
||||||
|
rect.y -= 1;
|
||||||
|
#endif
|
||||||
|
var pos = new Rect(rect.x, rect.y, 150, rect.height);
|
||||||
|
EditorGUI.LabelField(pos, s_ContentRenderingOrder);
|
||||||
|
|
||||||
|
pos = new Rect(rect.width - 35, rect.y, 60, rect.height);
|
||||||
|
if (GUI.Button(pos, s_ContentRefresh, EditorStyles.miniButton))
|
||||||
|
{
|
||||||
|
foreach (var uip in targets.OfType<UIParticle>())
|
||||||
|
{
|
||||||
|
uip.RefreshParticles();
|
||||||
|
EditorUtility.SetDirty(uip);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// On select UIParticle, refresh particles.
|
// On select UIParticle, refresh particles.
|
||||||
foreach (UIParticle t in targets)
|
if (!Application.isPlaying)
|
||||||
{
|
{
|
||||||
if (Application.isPlaying || PrefabUtility.GetPrefabAssetType(t) != PrefabAssetType.NotAPrefab) continue;
|
foreach (var uip in targets.OfType<UIParticle>())
|
||||||
t.RefreshParticles(t.particles);
|
{
|
||||||
|
if (PrefabUtility.GetPrefabAssetType(uip) != PrefabAssetType.NotAPrefab) continue;
|
||||||
|
uip.RefreshParticles(uip.particles);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,16 +236,16 @@ namespace Coffee.UIExtensions
|
|||||||
public override void OnInspectorGUI()
|
public override void OnInspectorGUI()
|
||||||
{
|
{
|
||||||
var current = target as UIParticle;
|
var current = target as UIParticle;
|
||||||
if (current == null) return;
|
if (!current) return;
|
||||||
|
|
||||||
serializedObject.Update();
|
serializedObject.Update();
|
||||||
|
|
||||||
// Maskable
|
// Maskable
|
||||||
EditorGUILayout.PropertyField(m_Maskable);
|
EditorGUILayout.PropertyField(_maskable);
|
||||||
|
|
||||||
// Scale
|
// Scale
|
||||||
EditorGUI.BeginDisabledGroup(!m_MeshSharing.hasMultipleDifferentValues && m_MeshSharing.intValue == 4);
|
EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4);
|
||||||
_xyzMode = DrawFloatOrVector3Field(m_Scale3D, _xyzMode);
|
s_XYZMode = DrawFloatOrVector3Field(_scale3D, s_XYZMode);
|
||||||
EditorGUI.EndDisabledGroup();
|
EditorGUI.EndDisabledGroup();
|
||||||
|
|
||||||
// AnimatableProperties
|
// AnimatableProperties
|
||||||
@@ -250,12 +255,11 @@ namespace Coffee.UIExtensions
|
|||||||
.Where(x => x)
|
.Where(x => x)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
// Animated properties
|
AnimatablePropertyEditor.Draw(_animatableProperties, mats);
|
||||||
AnimatedPropertiesEditor.DrawAnimatableProperties(m_AnimatableProperties, mats);
|
|
||||||
|
|
||||||
// Mesh sharing
|
// Mesh sharing
|
||||||
EditorGUI.BeginChangeCheck();
|
EditorGUI.BeginChangeCheck();
|
||||||
_showMax = DrawMeshSharing(m_MeshSharing, m_GroupId, m_GroupMaxId, _showMax);
|
_showMax = DrawMeshSharing(_meshSharing, _groupId, _groupMaxId, _showMax);
|
||||||
if (EditorGUI.EndChangeCheck())
|
if (EditorGUI.EndChangeCheck())
|
||||||
{
|
{
|
||||||
serializedObject.ApplyModifiedProperties();
|
serializedObject.ApplyModifiedProperties();
|
||||||
@@ -265,16 +269,42 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Absolute Mode
|
// Position Mode
|
||||||
EditorGUILayout.PropertyField(m_AbsoluteMode);
|
EditorGUILayout.PropertyField(_positionMode);
|
||||||
|
|
||||||
|
// Auto Scaling
|
||||||
|
DrawAutoScaling(_autoScalingMode, targets.OfType<UIParticle>());
|
||||||
|
|
||||||
// Target ParticleSystems.
|
// Target ParticleSystems.
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
EditorGUI.BeginDisabledGroup(targets.OfType<UIParticle>().Any(x => !x.canvas));
|
||||||
_ro.DoLayoutList();
|
_ro.DoLayoutList();
|
||||||
|
EditorGUI.EndDisabledGroup();
|
||||||
serializedObject.ApplyModifiedProperties();
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
if (EditorGUI.EndChangeCheck())
|
||||||
|
{
|
||||||
|
foreach (var uip in targets.OfType<UIParticle>())
|
||||||
|
{
|
||||||
|
uip.RefreshParticles(uip.particles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-UI built-in shader is not supported.
|
||||||
|
foreach (var mat in current.materials)
|
||||||
|
{
|
||||||
|
if (!mat || !mat.shader) continue;
|
||||||
|
var shader = mat.shader;
|
||||||
|
if (IsBuiltInObject(shader) && !shader.name.StartsWith("UI/"))
|
||||||
|
{
|
||||||
|
EditorGUILayout.HelpBox(
|
||||||
|
$"Built-in shader '{shader.name}' in '{mat.name}' is not supported.\n" +
|
||||||
|
"Use UI shaders instead.",
|
||||||
|
MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Does the shader support UI masks?
|
// Does the shader support UI masks?
|
||||||
if (current.maskable && current.GetComponentInParent<Mask>())
|
if (current.maskable && current.GetComponentInParent<Mask>(false))
|
||||||
{
|
{
|
||||||
foreach (var mat in current.materials)
|
foreach (var mat in current.materials)
|
||||||
{
|
{
|
||||||
@@ -286,21 +316,28 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
if (mat.HasProperty(propName)) continue;
|
if (mat.HasProperty(propName)) continue;
|
||||||
|
|
||||||
EditorGUILayout.HelpBox(string.Format("Shader '{0}' doesn't have '{1}' property. This graphic cannot be masked.", shader.name, propName), MessageType.Warning);
|
EditorGUILayout.HelpBox(
|
||||||
|
$"Shader '{shader.name}' doesn't have '{propName}' property." +
|
||||||
|
"\nThis graphic cannot be masked.",
|
||||||
|
MessageType.Warning);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s_Shaders.Clear();
|
s_Shaders.Clear();
|
||||||
|
|
||||||
// UIParticle for trail should be removed.
|
// UIParticle for trail should be removed.
|
||||||
if (FixButton(current.m_IsTrail, "This UIParticle component should be removed. The UIParticle for trails is no longer needed."))
|
var label = "This UIParticle component should be removed. The UIParticle for trails is no longer needed.";
|
||||||
|
#pragma warning disable CS0612
|
||||||
|
if (FixButton(current.m_IsTrail, label))
|
||||||
|
#pragma warning restore CS0612
|
||||||
{
|
{
|
||||||
DestroyUIParticle(current);
|
DestroyUIParticle(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #203: When using linear color space, the particle colors are not output correctly.
|
#if UNITY_2018 || UNITY_2019
|
||||||
// To fix, set 'Apply Active Color Space' in renderer module to false.
|
// (2018, 2019) Check to use 'TEXCOORD*.zw' components as custom vertex stream.
|
||||||
var allPsRenderers = targets.OfType<UIParticle>()
|
var allPsRenderers = targets.OfType<UIParticle>()
|
||||||
.SelectMany(x => x.particles)
|
.SelectMany(x => x.particles)
|
||||||
.Where(x => x)
|
.Where(x => x)
|
||||||
@@ -308,29 +345,34 @@ namespace Coffee.UIExtensions
|
|||||||
.ToArray();
|
.ToArray();
|
||||||
if (0 < allPsRenderers.Length)
|
if (0 < allPsRenderers.Length)
|
||||||
{
|
{
|
||||||
var so = new SerializedObject(allPsRenderers);
|
|
||||||
var sp = so.FindProperty("m_ApplyActiveColorSpace");
|
|
||||||
if (FixButton(sp.boolValue || sp.hasMultipleDifferentValues, "When using linear color space, the particle colors are not output correctly.\nTo fix, set 'Apply Active Color Space' in renderer module to false."))
|
|
||||||
{
|
|
||||||
sp.boolValue = false;
|
|
||||||
so.ApplyModifiedProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check to use 'TEXCOORD*.zw' components as custom vertex stream.
|
// Check to use 'TEXCOORD*.zw' components as custom vertex stream.
|
||||||
foreach (var psr in allPsRenderers)
|
foreach (var psr in allPsRenderers)
|
||||||
{
|
{
|
||||||
if (new SerializedObject(psr).FindProperty("m_UseCustomVertexStreams").boolValue == false) continue;
|
if (!new SerializedObject(psr).FindProperty("m_UseCustomVertexStreams").boolValue) continue;
|
||||||
if (psr.activeVertexStreamsCount == 0) continue;
|
if (psr.activeVertexStreamsCount == 0) continue;
|
||||||
psr.GetActiveVertexStreams(s_Streams);
|
psr.GetActiveVertexStreams(s_Streams);
|
||||||
|
|
||||||
if (2 < s_Streams.Select(GetUsedComponentCount).Sum())
|
if (2 < s_Streams.Select(GetUsedComponentCount).Sum())
|
||||||
{
|
{
|
||||||
EditorGUILayout.HelpBox(string.Format("ParticleSystem '{0}' uses 'TEXCOORD*.zw' components as custom vertex stream.\nUIParticle does not support it (See README.md).", psr.name), MessageType.Warning);
|
EditorGUILayout.HelpBox(
|
||||||
|
$"ParticleSystem '{psr.name}' uses 'TEXCOORD*.zw' components as custom vertex stream.\n" +
|
||||||
|
"UIParticle does not support it (See README.md).",
|
||||||
|
MessageType.Warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s_Streams.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsBuiltInObject(Object obj)
|
||||||
|
{
|
||||||
|
return AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj, out var guid, out long _)
|
||||||
|
&& Regex.IsMatch(guid, "^0{16}.0{15}$", RegexOptions.Compiled);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_2018 || UNITY_2019
|
||||||
private static int GetUsedComponentCount(ParticleSystemVertexStream s)
|
private static int GetUsedComponentCount(ParticleSystemVertexStream s)
|
||||||
{
|
{
|
||||||
switch (s)
|
switch (s)
|
||||||
@@ -386,10 +428,13 @@ namespace Coffee.UIExtensions
|
|||||||
case ParticleSystemVertexStream.Custom2XYZW:
|
case ParticleSystemVertexStream.Custom2XYZW:
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private static bool DrawMeshSharing(SerializedProperty spMeshSharing, SerializedProperty spGroupId, SerializedProperty spGroupMaxId, bool showMax)
|
private static bool DrawMeshSharing(SerializedProperty spMeshSharing, SerializedProperty spGroupId,
|
||||||
|
SerializedProperty spGroupMaxId, bool showMax)
|
||||||
{
|
{
|
||||||
showMax |= spGroupId.intValue != spGroupMaxId.intValue ||
|
showMax |= spGroupId.intValue != spGroupMaxId.intValue ||
|
||||||
spGroupId.hasMultipleDifferentValues ||
|
spGroupId.hasMultipleDifferentValues ||
|
||||||
@@ -401,7 +446,10 @@ namespace Coffee.UIExtensions
|
|||||||
EditorGUI.BeginChangeCheck();
|
EditorGUI.BeginChangeCheck();
|
||||||
showMax = GUILayout.Toggle(showMax, s_ContentRandom, EditorStyles.miniButton, GUILayout.Width(60));
|
showMax = GUILayout.Toggle(showMax, s_ContentRandom, EditorStyles.miniButton, GUILayout.Width(60));
|
||||||
if (EditorGUI.EndChangeCheck() && !showMax)
|
if (EditorGUI.EndChangeCheck() && !showMax)
|
||||||
|
{
|
||||||
spGroupMaxId.intValue = spGroupId.intValue;
|
spGroupMaxId.intValue = spGroupId.intValue;
|
||||||
|
}
|
||||||
|
|
||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
EditorGUI.BeginDisabledGroup(spMeshSharing.intValue == 0);
|
EditorGUI.BeginDisabledGroup(spMeshSharing.intValue == 0);
|
||||||
@@ -414,57 +462,70 @@ namespace Coffee.UIExtensions
|
|||||||
else if (spMeshSharing.intValue == 1 || spMeshSharing.intValue == 4)
|
else if (spMeshSharing.intValue == 1 || spMeshSharing.intValue == 4)
|
||||||
{
|
{
|
||||||
EditorGUI.BeginDisabledGroup(true);
|
EditorGUI.BeginDisabledGroup(true);
|
||||||
EditorGUILayout.ObjectField("Primary", UIParticleUpdater.GetPrimary(spGroupId.intValue), typeof(UIParticle), false);
|
var obj = UIParticleUpdater.GetPrimary(spGroupId.intValue);
|
||||||
|
EditorGUILayout.ObjectField("Primary", obj, typeof(UIParticle), false);
|
||||||
EditorGUI.EndDisabledGroup();
|
EditorGUI.EndDisabledGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorGUI.indentLevel--;
|
EditorGUI.indentLevel--;
|
||||||
EditorGUI.EndDisabledGroup();
|
EditorGUI.EndDisabledGroup();
|
||||||
|
|
||||||
return showMax;
|
return showMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WindowFunction(UnityEngine.Object target, SceneView sceneView)
|
private static void DrawAutoScaling(SerializedProperty prop, IEnumerable<UIParticle> uiParticles)
|
||||||
|
{
|
||||||
|
EditorGUILayout.PropertyField(prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_2021_2_OR_NEWER
|
||||||
|
private static void WindowFunction()
|
||||||
|
#else
|
||||||
|
private static void WindowFunction(Object _, SceneView __)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (s_SerializedObject.targetObjects.Any(x => !x)) return;
|
if (s_SerializedObject == null || !s_SerializedObject.targetObject) return;
|
||||||
|
var uiParticles = s_SerializedObject.targetObjects.OfType<UIParticle>().ToArray();
|
||||||
|
if (uiParticles.Any(x => !x || !x.canvas)) return;
|
||||||
|
|
||||||
s_SerializedObject.Update();
|
s_SerializedObject.Update();
|
||||||
using (new EditorGUILayout.VerticalScope(GUILayout.Width(220f)))
|
using (new EditorGUILayout.VerticalScope(GUILayout.Width(220f)))
|
||||||
{
|
{
|
||||||
var labelWidth = EditorGUIUtility.labelWidth;
|
var labelWidth = EditorGUIUtility.labelWidth;
|
||||||
EditorGUIUtility.labelWidth = 100;
|
EditorGUIUtility.labelWidth = 100;
|
||||||
_xyzMode = DrawFloatOrVector3Field(s_SerializedObject.FindProperty("m_Scale3D"), _xyzMode);
|
EditorGUILayout.PropertyField(s_SerializedObject.FindProperty("m_Enabled"));
|
||||||
EditorGUILayout.PropertyField(s_SerializedObject.FindProperty("m_AbsoluteMode"));
|
s_XYZMode = DrawFloatOrVector3Field(s_SerializedObject.FindProperty("m_Scale3D"), s_XYZMode);
|
||||||
|
EditorGUILayout.PropertyField(s_SerializedObject.FindProperty("m_PositionMode"));
|
||||||
|
DrawAutoScaling(s_SerializedObject.FindProperty("m_AutoScalingMode"), uiParticles);
|
||||||
EditorGUIUtility.labelWidth = labelWidth;
|
EditorGUIUtility.labelWidth = labelWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_SerializedObject.ApplyModifiedProperties();
|
s_SerializedObject.ApplyModifiedProperties();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
// ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DestroyUIParticle(UIParticle p, bool ignoreCurrent = false)
|
private void DestroyUIParticle(UIParticle p, bool ignoreCurrent = false)
|
||||||
{
|
{
|
||||||
if (!p || ignoreCurrent && target == p) return;
|
if (!p || (ignoreCurrent && target == p)) return;
|
||||||
|
|
||||||
var cr = p.canvasRenderer;
|
var cr = p.canvasRenderer;
|
||||||
DestroyImmediate(p);
|
DestroyImmediate(p);
|
||||||
DestroyImmediate(cr);
|
DestroyImmediate(cr);
|
||||||
|
|
||||||
#if UNITY_2021_2_OR_NEWER
|
|
||||||
var stage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
|
|
||||||
#elif UNITY_2018_3_OR_NEWER
|
|
||||||
var stage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
|
|
||||||
#endif
|
|
||||||
#if UNITY_2018_3_OR_NEWER
|
#if UNITY_2018_3_OR_NEWER
|
||||||
|
var stage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||||
if (stage != null && stage.scene.isLoaded)
|
if (stage != null && stage.scene.isLoaded)
|
||||||
{
|
{
|
||||||
#if UNITY_2020_1_OR_NEWER
|
#if UNITY_2020_1_OR_NEWER
|
||||||
string prefabAssetPath = stage.assetPath;
|
var prefabAssetPath = stage.assetPath;
|
||||||
#else
|
#else
|
||||||
string prefabAssetPath = stage.prefabAssetPath;
|
var prefabAssetPath = stage.prefabAssetPath;
|
||||||
#endif
|
#endif
|
||||||
PrefabUtility.SaveAsPrefabAsset(stage.prefabContentsRoot, prefabAssetPath);
|
PrefabUtility.SaveAsPrefabAsset(stage.prefabContentsRoot, prefabAssetPath);
|
||||||
}
|
}
|
||||||
@@ -513,7 +574,10 @@ namespace Coffee.UIExtensions
|
|||||||
EditorGUI.BeginChangeCheck();
|
EditorGUI.BeginChangeCheck();
|
||||||
showXyz = GUILayout.Toggle(showXyz, s_Content3D, EditorStyles.miniButton, GUILayout.Width(30));
|
showXyz = GUILayout.Toggle(showXyz, s_Content3D, EditorStyles.miniButton, GUILayout.Width(30));
|
||||||
if (EditorGUI.EndChangeCheck() && !showXyz)
|
if (EditorGUI.EndChangeCheck() && !showXyz)
|
||||||
|
{
|
||||||
z.floatValue = y.floatValue = x.floatValue;
|
z.floatValue = y.floatValue = x.floatValue;
|
||||||
|
}
|
||||||
|
|
||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
return showXyz;
|
return showXyz;
|
||||||
@@ -34,10 +34,10 @@ namespace Coffee.UIExtensions
|
|||||||
ps.transform.SetParent(uiParticle.transform, false);
|
ps.transform.SetParent(uiParticle.transform, false);
|
||||||
ps.transform.localPosition = Vector3.zero;
|
ps.transform.localPosition = Vector3.zero;
|
||||||
|
|
||||||
// Assign default material.
|
// Assign default material (UIAdditive).
|
||||||
var renderer = ps.GetComponent<ParticleSystemRenderer>();
|
var renderer = ps.GetComponent<ParticleSystemRenderer>();
|
||||||
var defaultMat = AssetDatabase.GetBuiltinExtraResource<Material>("Default-Particle.mat");
|
var path = AssetDatabase.GUIDToAssetPath("9944483a3e009401ba5dcc42f14d5c63");
|
||||||
renderer.material = defaultMat ? defaultMat : renderer.material;
|
renderer.material = AssetDatabase.LoadAssetAtPath<Material>(path);
|
||||||
|
|
||||||
// Refresh particles.
|
// Refresh particles.
|
||||||
uiParticle.RefreshParticles();
|
uiParticle.RefreshParticles();
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: ca0fd7c7ead2c49b1ae139b7963de126
|
guid: 7a55e246f37df405bac88eac692e3a86
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
BIN
Icons/UIParticleIcon.png
Normal file
BIN
Icons/UIParticleIcon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 418 B |
@@ -1,9 +1,9 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: fc4e1d816001842709cf8a393c69dd14
|
guid: 5f0675613942149309588d556e33d990
|
||||||
TextureImporter:
|
TextureImporter:
|
||||||
fileIDToRecycleName: {}
|
internalIDToNameTable: []
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 9
|
serializedVersion: 12
|
||||||
mipmaps:
|
mipmaps:
|
||||||
mipMapMode: 0
|
mipMapMode: 0
|
||||||
enableMipMap: 0
|
enableMipMap: 0
|
||||||
@@ -20,27 +20,30 @@ TextureImporter:
|
|||||||
externalNormalMap: 0
|
externalNormalMap: 0
|
||||||
heightScale: 0.25
|
heightScale: 0.25
|
||||||
normalMapFilter: 0
|
normalMapFilter: 0
|
||||||
|
flipGreenChannel: 0
|
||||||
isReadable: 0
|
isReadable: 0
|
||||||
streamingMipmaps: 0
|
streamingMipmaps: 0
|
||||||
streamingMipmapsPriority: 0
|
streamingMipmapsPriority: 0
|
||||||
|
vTOnly: 0
|
||||||
|
ignoreMipmapLimit: 0
|
||||||
grayScaleToAlpha: 0
|
grayScaleToAlpha: 0
|
||||||
generateCubemap: 6
|
generateCubemap: 6
|
||||||
cubemapConvolution: 0
|
cubemapConvolution: 0
|
||||||
seamlessCubemap: 0
|
seamlessCubemap: 0
|
||||||
textureFormat: -1
|
textureFormat: 1
|
||||||
maxTextureSize: 2048
|
maxTextureSize: 2048
|
||||||
textureSettings:
|
textureSettings:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
filterMode: -1
|
filterMode: 1
|
||||||
aniso: -1
|
aniso: 1
|
||||||
mipBias: -100
|
mipBias: 0
|
||||||
wrapU: 1
|
wrapU: 1
|
||||||
wrapV: 1
|
wrapV: 1
|
||||||
wrapW: 1
|
wrapW: 0
|
||||||
nPOTScale: 0
|
nPOTScale: 0
|
||||||
lightmap: 0
|
lightmap: 0
|
||||||
compressionQuality: 50
|
compressionQuality: 50
|
||||||
spriteMode: 1
|
spriteMode: 0
|
||||||
spriteExtrude: 1
|
spriteExtrude: 1
|
||||||
spriteMeshType: 1
|
spriteMeshType: 1
|
||||||
alignment: 0
|
alignment: 0
|
||||||
@@ -51,16 +54,22 @@ TextureImporter:
|
|||||||
alphaUsage: 1
|
alphaUsage: 1
|
||||||
alphaIsTransparency: 1
|
alphaIsTransparency: 1
|
||||||
spriteTessellationDetail: -1
|
spriteTessellationDetail: -1
|
||||||
textureType: 8
|
textureType: 2
|
||||||
textureShape: 1
|
textureShape: 1
|
||||||
singleChannelComponent: 0
|
singleChannelComponent: 0
|
||||||
|
flipbookRows: 1
|
||||||
|
flipbookColumns: 1
|
||||||
maxTextureSizeSet: 0
|
maxTextureSizeSet: 0
|
||||||
compressionQualitySet: 0
|
compressionQualitySet: 0
|
||||||
textureFormatSet: 0
|
textureFormatSet: 0
|
||||||
|
ignorePngGamma: 0
|
||||||
|
applyGammaDecoding: 0
|
||||||
|
swizzle: 50462976
|
||||||
|
cookieLightType: 0
|
||||||
platformSettings:
|
platformSettings:
|
||||||
- serializedVersion: 2
|
- serializedVersion: 3
|
||||||
buildTarget: DefaultTexturePlatform
|
buildTarget: DefaultTexturePlatform
|
||||||
maxTextureSize: 2048
|
maxTextureSize: 64
|
||||||
resizeAlgorithm: 0
|
resizeAlgorithm: 0
|
||||||
textureFormat: -1
|
textureFormat: -1
|
||||||
textureCompression: 1
|
textureCompression: 1
|
||||||
@@ -68,8 +77,10 @@ TextureImporter:
|
|||||||
crunchedCompression: 0
|
crunchedCompression: 0
|
||||||
allowsAlphaSplitting: 0
|
allowsAlphaSplitting: 0
|
||||||
overridden: 0
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
androidETC2FallbackOverride: 0
|
androidETC2FallbackOverride: 0
|
||||||
- serializedVersion: 2
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 3
|
||||||
buildTarget: Standalone
|
buildTarget: Standalone
|
||||||
maxTextureSize: 2048
|
maxTextureSize: 2048
|
||||||
resizeAlgorithm: 0
|
resizeAlgorithm: 0
|
||||||
@@ -79,31 +90,11 @@ TextureImporter:
|
|||||||
crunchedCompression: 0
|
crunchedCompression: 0
|
||||||
allowsAlphaSplitting: 0
|
allowsAlphaSplitting: 0
|
||||||
overridden: 0
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
androidETC2FallbackOverride: 0
|
androidETC2FallbackOverride: 0
|
||||||
- serializedVersion: 2
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
buildTarget: iPhone
|
- serializedVersion: 3
|
||||||
maxTextureSize: 2048
|
buildTarget: Server
|
||||||
resizeAlgorithm: 0
|
|
||||||
textureFormat: -1
|
|
||||||
textureCompression: 1
|
|
||||||
compressionQuality: 50
|
|
||||||
crunchedCompression: 0
|
|
||||||
allowsAlphaSplitting: 0
|
|
||||||
overridden: 0
|
|
||||||
androidETC2FallbackOverride: 0
|
|
||||||
- serializedVersion: 2
|
|
||||||
buildTarget: Android
|
|
||||||
maxTextureSize: 2048
|
|
||||||
resizeAlgorithm: 0
|
|
||||||
textureFormat: -1
|
|
||||||
textureCompression: 1
|
|
||||||
compressionQuality: 50
|
|
||||||
crunchedCompression: 0
|
|
||||||
allowsAlphaSplitting: 0
|
|
||||||
overridden: 0
|
|
||||||
androidETC2FallbackOverride: 0
|
|
||||||
- serializedVersion: 2
|
|
||||||
buildTarget: WebGL
|
|
||||||
maxTextureSize: 2048
|
maxTextureSize: 2048
|
||||||
resizeAlgorithm: 0
|
resizeAlgorithm: 0
|
||||||
textureFormat: -1
|
textureFormat: -1
|
||||||
@@ -112,21 +103,25 @@ TextureImporter:
|
|||||||
crunchedCompression: 0
|
crunchedCompression: 0
|
||||||
allowsAlphaSplitting: 0
|
allowsAlphaSplitting: 0
|
||||||
overridden: 0
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
androidETC2FallbackOverride: 0
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
spriteSheet:
|
spriteSheet:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
sprites: []
|
sprites: []
|
||||||
outline: []
|
outline: []
|
||||||
physicsShape: []
|
physicsShape: []
|
||||||
bones: []
|
bones: []
|
||||||
spriteID: de8a1691f8aae4be18d66008040aa1a7
|
spriteID:
|
||||||
|
internalID: 0
|
||||||
vertices: []
|
vertices: []
|
||||||
indices:
|
indices:
|
||||||
edges: []
|
edges: []
|
||||||
weights: []
|
weights: []
|
||||||
spritePackingTag:
|
secondaryTextures: []
|
||||||
|
nameFileIdTable: {}
|
||||||
|
mipmapLimitGroupName:
|
||||||
pSDRemoveMatte: 0
|
pSDRemoveMatte: 0
|
||||||
pSDShowRemoveMatteOption: 0
|
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
assetBundleVariant:
|
assetBundleVariant:
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
Copyright 2018-2022 mob-sakai
|
Copyright 2018-2023 mob-sakai
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|||||||
534
README.md
534
README.md
@@ -1,207 +1,176 @@
|
|||||||
Particle Effect For UGUI (UI Particle)
|
# Particle Effect For UGUI (UI Particle)
|
||||||
===
|
|
||||||
|
|
||||||
This plugin provide a component to render particle effect for uGUI in Unity 2018.2 or later.
|
This package provides a component to render particle effects for uGUI in Unity 2018.2 or later.
|
||||||
The particle rendering is maskable and sortable, without Camera, RenderTexture or Canvas.
|
The particle rendering is maskable and sortable, without the need for an extra Camera, RenderTexture, or Canvas.
|
||||||
|
|
||||||
[](https://openupm.com/packages/com.coffee.ui-particle/)
|
[](https://openupm.com/packages/com.coffee.ui-particle/)
|
||||||
[](https://github.com/mob-sakai/ParticleEffectForUGUI/releases)
|
[](https://github.com/mob-sakai/ParticleEffectForUGUI/releases)
|
||||||
[](https://github.com/mob-sakai/ParticleEffectForUGUI/releases) [](https://github.com/mob-sakai/ParticleEffectForUGUI/blob/master/LICENSE.txt)
|
[](https://github.com/mob-sakai/ParticleEffectForUGUI/blob/main/LICENSE.txt)
|
||||||
[](http://makeapullrequest.com)
|

|
||||||

|

|
||||||

|
[](http://makeapullrequest.com)
|
||||||

|
[](https://twitter.com/intent/follow?screen_name=mob_sakai)
|
||||||

|
|
||||||
|
|
||||||
|
<< [📝 Description](#-description) | [🎮 Demo](#-demo) | [⚙ Installation](#-installation) | [🚀 Usage](#-usage) | [🛠 Development Note](#-development-note) | [🤝 Contributing](#-contributing) >>
|
||||||
|
|
||||||
<< [Description](#Description) | [Demo](#demo) | [Installation](#installation) | [Usage](#usage) | [Development Note](#development-note) | [Change log](https://github.com/mob-sakai/ParticleEffectForUGUI/blob/upm/CHANGELOG.md) >>
|
<br><br>
|
||||||
|
|
||||||
|
## 📝 Description
|
||||||
|
|
||||||
<br><br><br><br>
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
This plugin uses new APIs `MeshBake/MashTrailBake` (added with Unity 2018.2) to render particles by CanvasRenderer.
|
This package utilizes the new APIs `MeshBake/MashTrailBake` (introduced with Unity 2018.2) to render particles through
|
||||||
You can mask and sort particles for uGUI without Camera, RenderTexture, Canvas.
|
CanvasRenderer.
|
||||||
|
You can render, mask, and sort your ParticleSystems for UI without the necessity of an additional Camera, RenderTexture,
|
||||||
|
or Canvas.
|
||||||
|
|
||||||
Compares this "Baking mesh" approach with the conventional approach:
|
### Features
|
||||||
[Performance test results](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/193#issuecomment-1160028374)
|
|
||||||
|
|
||||||
|Approach|Good|Bad|Screenshot|
|
* Easy to use: The package is ready to use out of the box.
|
||||||
|-|-|-|-|
|
* Sort particle effects and other UI by sibling index.
|
||||||
|Baking mesh<br>**\(UIParticle\)**|Rendered as is.<br>Maskable.<br>Sortable.<br>Less objects.|[Not support `TEXCOORD*.zw` components for custom vertex stream](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/191#issuecomment-1043409186)|<img src="https://user-images.githubusercontent.com/12690315/41765089-0302b9a2-763e-11e8-88b3-b6ffa306bbb0.gif" width="500px">|
|
* No extra Camera, RenderTexture, or Canvas required.
|
||||||
|Do nothing|Rendered as is.|**Looks like a glitch.**<br>Not maskable.<br>Not sortable.|<img src="https://user-images.githubusercontent.com/12690315/41765090-0329828a-763e-11e8-8d8a-f1d269ea3bc7.gif" width="500px">|
|
* Masking options for Mask or RectMask2D.
|
||||||
|Convert particle to UIVertex<br>[\(UIParticleSystem\)](https://forum.unity.com/threads/free-script-particle-systems-in-ui-screen-space-overlay.406862/)|Maskable.<br>Sortable.<br>Less objects.|**Adjustment is difficult.**<br>Requires UI shaders.<br>Difficult to adjust scale.<br>Force hierarchy scalling.<br>Simulation results are incorrect.<br>Trail, rotation of transform, time scaling are not supported.<br>Generate heavy GC every frame.|<img src="https://user-images.githubusercontent.com/12690315/41765088-02deb9c6-763e-11e8-98d0-9e0c1766ef39.gif" width="500px">|
|
* Support for the Trail module.
|
||||||
|Use Canvas to sort|Rendered as is.<br>Sortable.|**You must to manage sorting orders.**<br>Not maskable.<br>More batches.|<img src="https://user-images.githubusercontent.com/12690315/41765087-02b866ea-763e-11e8-8c33-081c9ad852f8.gif" width="500px">|
|
* Support for CanvasGroup alpha.
|
||||||
|Use RenderTexture|Maskable.<br>Sortable.|**Requires Camera and RenderTexture.**<br>Difficult to adjust position and size.<br>Quality depends on the RenderTexture's setting.|<img src="https://user-images.githubusercontent.com/12690315/41765085-0291b3e2-763e-11e8-827b-72e5ee9bc556.gif" width="500px">|
|
* No allocations needed to render particles.
|
||||||
|
* Compatibility with overlay, camera space, and world space.
|
||||||
|
* Support for Universal Render Pipeline (URP) and High Definition Render Pipeline (HDRP).
|
||||||
|
* Support for disabling `Enter Play Mode Options > Reload Domain`.
|
||||||
|
* Support for changing material property with AnimationClip (AnimatableProperty).
|
||||||
|
![AnimatableProperty.gif][AnimatableProperty.gif]
|
||||||
|
* [4.0.0+] Support for 8+ materials.
|
||||||
|
* [4.0.0+] Correct world space particle position adjustment when changing window size for standalone platforms (Windows,
|
||||||
|
MacOSX, and Linux).
|
||||||
|
* [4.0.0+] Adaptive scaling for UI.
|
||||||
|
* [4.0.0+] Mesh sharing group to improve performance.
|
||||||
|
![MeshSharing.gif][MeshSharing.gif]
|
||||||
|
* [4.0.0+] Particle attractor component.
|
||||||
|
![ParticleAttractor.gif][ParticleAttractor.gif]
|
||||||
|
* [4.1.0+] Relative/Absolute particle position mode.
|
||||||
|
![AbsolutePosition.gif][AbsolutePosition.gif]
|
||||||
|
|
||||||
|Approach|FPS on Editor|FPS on iPhone6|FPS on Xperia XZ|
|
[AnimatableProperty.gif]: https://user-images.githubusercontent.com/12690315/53286323-2d94a980-37b0-11e9-8afb-c4a207805ff2.gif
|
||||||
|--|--|--|--|
|
|
||||||
|Particle System|43|57|22|
|
[MeshSharing.gif]: https://user-images.githubusercontent.com/12690315/174311048-c882df81-6c34-4eba-b0aa-5645457692f1.gif
|
||||||
|UIParticleSystem|4|3|0 (unmeasurable)|
|
|
||||||
|Sorting By Canvas|43|44|18|
|
[ParticleAttractor.gif]: https://user-images.githubusercontent.com/12690315/174311027-462929a4-13f0-4ec4-86ea-9c832f2eecf1.gif
|
||||||
|UIParticle|17|12|4|
|
|
||||||
|UIParticle with MeshSharing|44|45|30|
|
[AbsolutePosition.gif]: https://user-images.githubusercontent.com/12690315/175751579-5a2357e8-2ecf-4afd-83c8-66e9771bde39.gif
|
||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
#### Features
|
## 🎮 Demo
|
||||||
|
|
||||||
* Easy to use: the package is out-of-the-box
|
* [WebGL Demo](https://mob-sakai.github.io/demos/UIParticle_Demo/index.html)
|
||||||
* Sort particle effects and UI by sibling index
|
|
||||||
* No Camera, RenderTexture or Canvas are required
|
|
||||||
* Masking by Mask or RectMask2D
|
|
||||||
* Support Trail module
|
|
||||||
* Support CanvasGroup alpha
|
|
||||||
* No allocations
|
|
||||||
* Support overlay, camera space and world space
|
|
||||||
* Support changing material property with AnimationClip (AnimatableProperty)
|
|
||||||

|
|
||||||
* [4.0.0+] Support 8+ materials
|
|
||||||
* [4.0.0+] Correct world space particle position when changing window size for standalone platforms (Windows, MacOSX and Linux)
|
|
||||||
* [4.0.0+] Adaptive scaling for UI
|
|
||||||
* [4.0.0+] Mesh sharing group to improve performance
|
|
||||||

|
|
||||||
* [4.0.0+] Particle attractor component
|
|
||||||

|
|
||||||
* [4.1.0+] Relative/Absolute particle position mode
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
<br><br><br><br>
|
|
||||||
|
|
||||||
## Demo
|
|
||||||
|
|
||||||
* [WebGL Demo](https://mob-sakai.github.io/demos/UIParticle_Demo/index.html)
|
|
||||||
> 
|
> 
|
||||||
|
|
||||||
* [WebGL Demo (Cartoon FX & War FX)](https://mob-sakai.github.io/Demos/ParticleEffectForUGUI_CFX)
|
* [WebGL Demo (Cartoon FX & War FX)](https://mob-sakai.github.io/Demos/ParticleEffectForUGUI_CFX)
|
||||||
* [Cartoon FX Free][CFX] & [War FX][WFX] (by [Jean Moreno (JMO)][JMO]) with UIParticle
|
* [Cartoon FX Free][CFX] & [War FX][WFX] (by [Jean Moreno (JMO)][JMO]) with UIParticle
|
||||||
|
|
||||||
> 
|
> 
|
||||||
|
|
||||||
[CFX]: https://assetstore.unity.com/packages/vfx/particles/cartoon-fx-free-109565
|
[CFX]: https://assetstore.unity.com/packages/vfx/particles/cartoon-fx-free-109565
|
||||||
|
|
||||||
[WFX]: https://assetstore.unity.com/packages/vfx/particles/war-fx-5669
|
[WFX]: https://assetstore.unity.com/packages/vfx/particles/war-fx-5669
|
||||||
|
|
||||||
[JMO]: https://assetstore.unity.com/publishers/1669
|
[JMO]: https://assetstore.unity.com/publishers/1669
|
||||||
|
|
||||||
|
|
||||||
<br><br><br><br>
|
<br><br>
|
||||||
|
|
||||||
## Installation
|
## ⚙ Installation
|
||||||
|
|
||||||
### Requirement
|
_This package requires Unity 2018.3 or later._
|
||||||
|
|
||||||

|
#### Install via OpenUPM
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
### Using OpenUPM
|
This package is available on [OpenUPM](https://openupm.com) package registry.
|
||||||
|
This is the preferred method of installation, as you can easily receive updates as they're released.
|
||||||
|
|
||||||
This package is available on [OpenUPM](https://openupm.com).
|
If you have [openupm-cli](https://github.com/openupm/openupm-cli) installed, then run the following command in your
|
||||||
You can install it via [openupm-cli](https://github.com/openupm/openupm-cli).
|
project's directory:
|
||||||
```
|
|
||||||
|
```sh
|
||||||
openupm add com.coffee.ui-particle
|
openupm add com.coffee.ui-particle
|
||||||
```
|
```
|
||||||
|
|
||||||
### Using Git
|
#### Install via UPM (using Git URL)
|
||||||
|
|
||||||
Find the manifest.json file in the Packages folder of your project and add a line to `dependencies` field.
|
Navigate to your project's Packages folder and open the `manifest.json` file. Then add this package somewhere in
|
||||||
|
the `dependencies` block:
|
||||||
|
|
||||||
* `"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git"`
|
```json
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git",
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
To update the package, change suffix `#{version}` to the target version.
|
To update the package, change suffix `#{version}` to the target version.
|
||||||
|
|
||||||
* `"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git#4.0.0",`
|
* e.g. `"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git#4.6.0",`
|
||||||
|
|
||||||
Or, use [UpmGitExtension](https://github.com/mob-sakai/UpmGitExtension) to install and update the package.
|
Or, use [UpmGitExtension](https://github.com/mob-sakai/UpmGitExtension) to install and update the package.
|
||||||
|
|
||||||
### For Unity 2018.2
|
<br><br>
|
||||||
|
|
||||||
Unity 2018.2 supports embedded packages.
|
## 🚀 Usage
|
||||||
|
|
||||||
1. Download a source code zip file from [Releases](https://github.com/mob-sakai/ParticleEffectForUGUI/releases) page
|
### UIParticle Component
|
||||||
2. Extract it
|
|
||||||
3. Import it under `Packages` directory in your Unity project
|
|
||||||
|
|
||||||
|
`UIParticle` controls the ParticleSystems that are attached to its own game objects and child game objects.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
<br><br><br><br>
|
- **Maskable**: Does this graphic allow masking.
|
||||||
|
- **Scale**: Scale the rendering. When the `3D` toggle is enabled, 3D scale (x, y, z) is supported.
|
||||||
|
- **Animatable Properties**: If you want to update material properties (e.g., `_MainTex_ST`, `_Color`) in AnimationClip,
|
||||||
|
use this to mark the changes.
|
||||||
|
- **Mesh Sharing**: Particle simulation results are shared within the same group. A large number of the same effects can
|
||||||
|
be displayed with a small load. When the `Random` toggle is enabled, it will be grouped randomly.
|
||||||
|
- **Position Mode**: Emission position mode.
|
||||||
|
- **Absolute:** Emit from the world position of the `ParticleSystem`.
|
||||||
|
- **Relative:** Emit from the scaled position of the `ParticleSystem`.
|
||||||
|
- **Auto Scaling**: `Transform.lossyScale` (=world scale) will be set to `(1, 1, 1)` on update. It prevents the
|
||||||
|
root-Canvas scale from affecting the hierarchy-scaled `ParticleSystem`.
|
||||||
|
- **Rendering Order**: The ParticleSystem list to be rendered. You can change the order and the materials.
|
||||||
|
|
||||||
## How to play demo
|
**NOTE:** Press the `Refresh` button to reconstruct the rendering order based on children ParticleSystem's sorting order
|
||||||
|
and z-position.
|
||||||
### For Unity 2019.1 or later
|
|
||||||
|
|
||||||
1. Open `Package Manager` window
|
|
||||||
2. Select `UI Particle` package in package list
|
|
||||||
3. Click `Import Sample` button
|
|
||||||

|
|
||||||
4. The demo project is imported into `Assets/Samples/UI Particle/{version}/Demo`
|
|
||||||
5. Open `UIParticle_Demo` scene and play it
|
|
||||||
|
|
||||||
### For Unity 2018.4 or earlier
|
|
||||||
|
|
||||||
1. Select `Assets/Samples/UI Particle Demo` from menu
|
|
||||||
2. The demo project is imported into `Assets/Samples/UI Particle/{version}/Demo`
|
|
||||||
3. Open `UIParticle_Demo` scene and play it
|
|
||||||
|
|
||||||
### About `Cartoon FX & War Fx Demo`
|
|
||||||
|
|
||||||
* It requires free assets ([Cartoon FX Free][CFX] & [War FX][WFX])
|
|
||||||
* by [Jean Moreno (JMO)][JMO]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br><br><br><br>
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### UIParticle component
|
|
||||||
|
|
||||||
`UIParticle` controls the ParticleSystems that is attached to its own game objects and child game objects.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
| Properties | Description |
|
|
||||||
| -- | -- |
|
|
||||||
| Maskable | Does this graphic allow masking. |
|
|
||||||
| Ignore Canvas Scale | Ignore the scale of the root canvas.<br>This prevents it from displaying small even in hierarchy scaling mode of `ParticleSystem`. |
|
|
||||||
| Scale | Scale the rendering.<br>When the `3D` toggle is enabled, 3D scale (x,y,z) is supported. |
|
|
||||||
| Animatable Properties | If you want update material properties (e.g. `_MainTex_ST`, `_Color`) in AnimationClip, use this to mark the changes. |
|
|
||||||
| Mesh Sharing | Particle simulation results are shared within the same group.<br>A large number of the same effects can be displayed with a small load.<br>When the `Random` toggle is enabled, it will be grouped randomaly. |
|
|
||||||
| Absolute Mode | The particles will be emitted at the ParticleSystem position.<br>Move the UIParticle/ParticleSystem to move the particle. |
|
|
||||||
| Rendering Order | The ParticleSystems to be rendered.<br>You can change the rendering order and the materials. |
|
|
||||||
|
|
||||||
NOTE: Press `Refresh` button to reconstruct rendering order based on children ParticleSystem's sorting order and z position.
|
|
||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
### Basically usage
|
#### Basic Usage
|
||||||
|
|
||||||
1. Select `Game Object/UI/ParticleSystem` to create UIParticle with a ParticleSystem.
|
1. Select `GameObject/UI/ParticleSystem` to create UIParticle with a ParticleSystem.
|
||||||

|

|
||||||
2. Adjust the ParticleSystem as you like.
|
2. Adjust the ParticleSystem as you like.
|
||||||

|

|
||||||
|
|
||||||
<br><br>
|
<br>
|
||||||
|
|
||||||
### With your existing ParticleSystem prefab
|
#### With Your Existing ParticleSystem Prefab
|
||||||
|
|
||||||
1. Select `Game Object/UI/ParticleSystem (Empty)` to create UIParticle.
|
1. Select `GameObject/UI/ParticleSystem (Empty)` to create UIParticle.
|
||||||

|

|
||||||
2. Drag & drop your ParticleSystem prefab on UIParticle.
|
2. Drag and drop your ParticleSystem prefab onto UIParticle.
|
||||||

|

|
||||||
|
|
||||||
<br><br>
|
<br>
|
||||||
|
|
||||||
### With `Mask` or `MaskRect2D` component
|
#### With `Mask` or `RectMask2D` Component
|
||||||
|
|
||||||
If you want to mask particles, set a stencil supported shader (such as `UI/UIAdditive`) to material for ParticleSystem.
|
If you want to mask particles, set a stencil-supported shader (such as `UI/UIAdditive`) to the material for
|
||||||
|
ParticleSystem.
|
||||||
|
If you use some custom shaders, see
|
||||||
|
the [How to Make a Custom Shader to Support Mask/RectMask2D Component](#how-to-make-a-custom-shader-to-support-maskrectmask2d-component)
|
||||||
|
section.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
### Script usage
|
### Script usage
|
||||||
@@ -226,90 +195,289 @@ uiParticle.Stop();
|
|||||||
|
|
||||||
`UIParticleAttractor` attracts particles generated by the specified ParticleSystem.
|
`UIParticleAttractor` attracts particles generated by the specified ParticleSystem.
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
| Properties | Description |
|
- **Particle System**: Attracts particles generated by the specified particle system.
|
||||||
| -- | -- |
|
- **Destination Radius**: Once the particle is within the radius, the particle lifetime will become 0, and `OnAttracted`
|
||||||
| Particle System | Attracts particles generated by the specified particle system. |
|
will be called.
|
||||||
| Distination Radius | Once the particle is within the radius, the particle lifetime will become 0 and `OnAttracted` will be called. |
|
- **Delay Rate**: Delay to start attracting. It is a percentage of the particle's start lifetime.
|
||||||
| Delay Rate | Delay to start attracting.<br>It is a percentage of the particle's start lifetime. |
|
- **Max Speed**: Maximum speed of attracting. If this value is too small, attracting may not be completed by the end of
|
||||||
| Max Speed | Maximum speed of attracting.<br> If this value is too small, attracting may not be completed by the end of the lifetime and `OnAttracted` may not be called. |
|
the lifetime, and `OnAttracted` may not be called.
|
||||||
| Movement | Attracting movement type. (Linear, Smooth, Sphere) |
|
- **Movement**: Attracting movement type. (`Linear`, `Smooth`, `Sphere`)
|
||||||
| OnAttracted | An event called when attracting is complete (per particle). |
|
- **Update Mode**: Update mode.
|
||||||
|
- **Normal:** Update with scaled delta time.
|
||||||
|
- **Unscaled Time:** Update with unscaled delta time.
|
||||||
|
- **OnAttracted**: An event called when attracting is complete (per particle).
|
||||||
|
|
||||||
<br><br><br><br>
|
<br><br>
|
||||||
|
|
||||||
## Development Note
|
## 🛠 Development Note
|
||||||
|
|
||||||
|
### Compares the Baking mesh approach with the conventional approach
|
||||||
|
|
||||||
|
- **Baking mesh approach (=UIParticle)**
|
||||||
|

|
||||||
|
- ✅ Rendered as is.
|
||||||
|
- ✅ Maskable.
|
||||||
|
- ✅ Sortable.
|
||||||
|
- ✅ Less objects.
|
||||||
|
|
||||||
|
- **Do nothing (=Plain ParticleSystem)**
|
||||||
|

|
||||||
|
- ✅ Rendered as is.
|
||||||
|
- ❌ Looks like a glitch.
|
||||||
|
- ❌ Not maskable.
|
||||||
|
- ❌ Not sortable.
|
||||||
|
|
||||||
|
- **Convert particle to UIVertex (=[UIParticleSystem][UIParticleSystem])**
|
||||||
|

|
||||||
|
- ✅ Maskable.
|
||||||
|
- ✅ Sortable.
|
||||||
|
- ❌ Adjustment is difficult.
|
||||||
|
- ❌ Requires UI shaders.
|
||||||
|
- ❌ Difficult to adjust scale.
|
||||||
|
- ❌ Force hierarchy scalling.
|
||||||
|
- ❌ Simulation results are incorrect.
|
||||||
|
- ❌ Trail, rotation of transform, time scaling are not supported.
|
||||||
|
- ❌ Generate heavy GC every frame.
|
||||||
|
|
||||||
|
- **Use Canvas to sort (Sorting By Canvas )**
|
||||||
|

|
||||||
|
- ✅ Rendered as is.
|
||||||
|
- ✅ Sortable.
|
||||||
|
- ❌ You must to manage sorting orders.
|
||||||
|
- ❌ Not maskable.
|
||||||
|
- ❌ More batches.
|
||||||
|
- ❌ Requires Canvas.
|
||||||
|
|
||||||
|
- **Use RenderTexture**
|
||||||
|

|
||||||
|
- ✅ Maskable.
|
||||||
|
- ✅ Sortable.
|
||||||
|
- ❌ Requires Camera and RenderTexture.
|
||||||
|
- ❌ Difficult to adjust position and size.
|
||||||
|
- ❌ Quality depends on the RenderTexture's setting.
|
||||||
|
|
||||||
|
[UIParticleSystem]: https://forum.unity.com/threads/free-script-particle-systems-in-ui-screen-space-overlay.406862/
|
||||||
|
|
||||||
|
#### [Performance test results](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/193#issuecomment-1160028374)
|
||||||
|
|
||||||
|
| Approach | FPS on Editor | FPS on iPhone6 | FPS on Xperia XZ |
|
||||||
|
|-----------------------------|---------------|----------------|------------------|
|
||||||
|
| Particle System | 43 | 57 | 22 |
|
||||||
|
| UIParticleSystem | 4 | 3 | 0 (unmeasurable) |
|
||||||
|
| Sorting By Canvas | 43 | 44 | 18 |
|
||||||
|
| UIParticle | 17 | 12 | 4 |
|
||||||
|
| UIParticle with MeshSharing | 44 | 45 | 30 |
|
||||||
|
|
||||||
|
### 🔍 FAQ: Why Are My UIParticles Not Displayed Correctly?
|
||||||
|
|
||||||
|
If `ParticleSystem` alone displays particles correctly but `UIParticle` does not, please check the following points:
|
||||||
|
|
||||||
|
- [Shader Limitation](#shader-limitation)
|
||||||
|
- `UIParticle` does not support all built-in shaders except for `UI/Default`.
|
||||||
|
- Most cases can be solved by using `UI/Additive` or `UI/Default`.
|
||||||
|
- Particles are not masked
|
||||||
|
- `UIParticle` is maskable.
|
||||||
|
- Set `Mask` or `RectMask2D` component properly.
|
||||||
|
- [Use maskable/clipable shader](#how-to-make-a-custom-shader-to-support-maskrectmask2d-component) (such
|
||||||
|
as `UI/Additive` or `UI/Default`)
|
||||||
|
- Particles are too small
|
||||||
|
- If particles are small enough, they will not appear on the screen.
|
||||||
|
- Increase the `Scale` value.
|
||||||
|
- If you don't want to change the apparent size depending on the resolution, try the `Auto Scaling` option.
|
||||||
|
- Particles are too many
|
||||||
|
- No more than 65535 vertices can be displayed (for mesh combination limitations).
|
||||||
|
- Please set `Emission` module and `Max Particles` of ParticleSystem properly.
|
||||||
|
- Particles are emitted off-screen.
|
||||||
|
- When `Position Mode = Relative`, particles are emitted from the scaled position of the ParticleSystem, not from
|
||||||
|
the screen point of the ParticleSystem.
|
||||||
|
- Place the ParticleSystem in the proper position or try `Position Mode = Absolute`.
|
||||||
|
- Attaching `UIParticle` to the same object as `ParticleSystem`
|
||||||
|
- `Transform.localScale` will be overridden by the `Auto Scaling` option.
|
||||||
|
- It is recommended to place `ParticleSystem` under `UIParticle`.
|
||||||
|
- If `Transform.localScale` contains 0, rendering will be skipped.
|
||||||
|
- Displayed particles are in the correct position but too large/too small
|
||||||
|
- Adjust `ParticleSystem.renderer.Min/MaxParticleSize`.
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
### Shader Limitation
|
### Shader Limitation
|
||||||
|
|
||||||
UIParticles are based on UIVertex.
|
The use of UI shaders is recommended.
|
||||||
Therefore, only xy components is available for each UV in the shader. (zw components will be ignored).
|
|
||||||
So unfortunately UIParticles will not work well with some shaders.
|
|
||||||
When using custom vertex streams, you can fill zw components with "unnecessary" data.
|
|
||||||
https://github.com/mob-sakai/ParticleEffectForUGUI/issues/191
|
|
||||||
|
|
||||||
- If you need a simple Additive shader, use the `UI/Additive` shader instead.
|
- If you need a simple Additive shader, use the `UI/Additive` shader instead.
|
||||||
- If you need a simple alpha-blend shader, use the `UI/Default` shader instead.
|
- If you need a simple alpha-blend shader, use the `UI/Default` shader instead.
|
||||||
|
- If your custom shader does not work properly with UIParticle, consider creating a custom UI shader.
|
||||||
|
|
||||||
|
#### Built-in shaders are not supported
|
||||||
|
|
||||||
|
`UIParticle` does not support all built-in shaders except for `UI/Default`.
|
||||||
|
If their use is detected, an error is displayed in the inspector.
|
||||||
|
Use UI shaders instead.
|
||||||
|
|
||||||
|
#### (Unity 2018 or 2019) UV.zw components will be discarded
|
||||||
|
|
||||||
|
UIParticleRenderer renders the particles based on UIVertex.
|
||||||
|
Therefore, only the xy components are available for each UV in the shader. (zw components will be discarded).
|
||||||
|
So unfortunately, UIParticles will not work well with some shaders.
|
||||||
|
|
||||||
|
#### (Unity 2018 or 2019) Custom vertex streams
|
||||||
|
|
||||||
|
When using custom vertex streams, you can fill zw components with "unnecessary" data.
|
||||||
|
Refer to [this issue](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/191) for more information.
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
### Overheads
|
### Overheads
|
||||||
|
|
||||||
UIParticle has some overheads and the batching depends on uGUI.
|
UIParticle has some overheads, and the batching depends on uGUI.
|
||||||
When improving performance, keep the following in mind:
|
When improving performance, keep the following in mind:
|
||||||
- If you are displaying a large number of the same effect, consider `Mesh Sharing` feature in [UIParticle Component](#uiparticle-component).
|
|
||||||
- If you don't like the uniform output, consider `Random Group` feature.
|
- If you are displaying a large number of the same effect, consider the `Mesh Sharing` feature in
|
||||||

|
the [UIParticle Component](#uiparticle-component).
|
||||||
|
- If you don't like the uniform output, consider the `Random Group` feature.
|
||||||
|

|
||||||
- If you are using multiple materials, you will have more draw calls.
|
- If you are using multiple materials, you will have more draw calls.
|
||||||
- Consider single material, atlasing the sprites, and using `Sprite` mode in the `Texture Sheet Animation` module in ParticleSystem.
|
- Consider a single material, atlasing the sprites, and using `Sprite` mode in the `Texture Sheet Animation` module
|
||||||
|
in the ParticleSystem.
|
||||||
|
|
||||||
|
### How to Make a Custom Shader to Support Mask/RectMask2D Component
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Shader tips</summary>
|
||||||
|
|
||||||
<br><br><br><br>
|
```ShaderLab
|
||||||
|
Shader "Your/Custom/Shader"
|
||||||
|
{
|
||||||
|
Properties
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
// #### required for Mask ####
|
||||||
|
_StencilComp ("Stencil Comparison", Float) = 8
|
||||||
|
_Stencil ("Stencil ID", Float) = 0
|
||||||
|
_StencilOp ("Stencil Operation", Float) = 0
|
||||||
|
_StencilWriteMask ("Stencil Write Mask", Float) = 255
|
||||||
|
_StencilReadMask ("Stencil Read Mask", Float) = 255
|
||||||
|
_ColorMask ("Color Mask", Float) = 15
|
||||||
|
[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
|
||||||
|
}
|
||||||
|
|
||||||
## Contributing
|
SubShader
|
||||||
|
{
|
||||||
|
Tags
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// #### required for Mask ####
|
||||||
|
Stencil
|
||||||
|
{
|
||||||
|
Ref [_Stencil]
|
||||||
|
Comp [_StencilComp]
|
||||||
|
Pass [_StencilOp]
|
||||||
|
ReadMask [_StencilReadMask]
|
||||||
|
WriteMask [_StencilWriteMask]
|
||||||
|
}
|
||||||
|
ColorMask [_ColorMask]
|
||||||
|
// ...
|
||||||
|
|
||||||
|
Pass
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
// #### required for RectMask2D ####
|
||||||
|
#include "UnityUI.cginc"
|
||||||
|
#pragma multi_compile __ UNITY_UI_CLIP_RECT
|
||||||
|
float4 _ClipRect;
|
||||||
|
|
||||||
|
// #### required for Mask ####
|
||||||
|
#pragma multi_compile __ UNITY_UI_ALPHACLIP
|
||||||
|
|
||||||
|
struct appdata_t
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
|
||||||
|
struct v2f
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
// #### required for RectMask2D ####
|
||||||
|
float4 worldPosition : TEXCOORD1;
|
||||||
|
};
|
||||||
|
|
||||||
|
v2f vert(appdata_t v)
|
||||||
|
{
|
||||||
|
v2f OUT;
|
||||||
|
// ...
|
||||||
|
// #### required for RectMask2D ####
|
||||||
|
OUT.worldPosition = v.vertex;
|
||||||
|
return OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
fixed4 frag(v2f IN) : SV_Target
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
// #### required for RectMask2D ####
|
||||||
|
#ifdef UNITY_UI_CLIP_RECT
|
||||||
|
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// #### required for Mask ####
|
||||||
|
#ifdef UNITY_UI_ALPHACLIP
|
||||||
|
clip (color.a - 0.001);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
ENDCG
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
## 🤝 Contributing
|
||||||
|
|
||||||
### Issues
|
### Issues
|
||||||
|
|
||||||
Issues are very valuable to this project.
|
Issues are incredibly valuable to this project:
|
||||||
|
|
||||||
- Ideas are a valuable source of contributions others can make
|
- Ideas provide a valuable source of contributions that others can make.
|
||||||
- Problems show where this project is lacking
|
- Problems help identify areas where this project needs improvement.
|
||||||
- With a question you show where contributors can improve the user experience
|
- Questions indicate where contributors can enhance the user experience.
|
||||||
|
|
||||||
### Pull Requests
|
### Pull Requests
|
||||||
|
|
||||||
Pull requests are, a great way to get your ideas into this repository.
|
Pull requests offer a fantastic way to contribute your ideas to this repository.
|
||||||
See [CONTRIBUTING.md](/../../blob/develop/CONTRIBUTING.md).
|
Please refer to [CONTRIBUTING.md](https://github.com/mob-sakai/ParticleEffectForUGUI/blob/main/CONTRIBUTING.md)
|
||||||
|
and [develop branch](https://github.com/mob-sakai/ParticleEffectForUGUI/tree/develop) for guidelines.
|
||||||
|
|
||||||
### Support
|
### Support
|
||||||
|
|
||||||
This is an open source project that I am developing in my spare time.
|
This is an open-source project developed during my spare time.
|
||||||
If you like it, please support me.
|
If you appreciate it, consider supporting me.
|
||||||
With your support, I can spend more time on development. :)
|
Your support allows me to dedicate more time to development. 😊
|
||||||
|
|
||||||
[](https://www.patreon.com/join/mob_sakai?)
|
[](https://www.patreon.com/join/2343451?)
|
||||||
[](https://github.com/users/mob-sakai/sponsorship)
|
[](https://github.com/users/mob-sakai/sponsorship)
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
|
||||||
<br><br><br><br>
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
* MIT
|
* MIT
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
*  [mob-sakai](https://github.com/mob-sakai) [](https://twitter.com/intent/follow?screen_name=mob_sakai) 
|
*  [mob-sakai](https://github.com/mob-sakai) [](https://twitter.com/intent/follow?screen_name=mob_sakai) 
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## See Also
|
## See Also
|
||||||
|
|
||||||
* GitHub page : https://github.com/mob-sakai/ParticleEffectForUGUI
|
* GitHub page : https://github.com/mob-sakai/ParticleEffectForUGUI
|
||||||
* Releases : https://github.com/mob-sakai/ParticleEffectForUGUI/releases
|
* Releases : https://github.com/mob-sakai/ParticleEffectForUGUI/releases
|
||||||
* Issue tracker : https://github.com/mob-sakai/ParticleEffectForUGUI/issues
|
* Issue tracker : https://github.com/mob-sakai/ParticleEffectForUGUI/issues
|
||||||
* Change log : https://github.com/mob-sakai/ParticleEffectForUGUI/blob/upm/CHANGELOG.md
|
* Change log : https://github.com/mob-sakai/ParticleEffectForUGUI/blob/main/CHANGELOG.md
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
using UnityEngine;
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Coffee.UIExtensions
|
namespace Coffee.UIExtensions
|
||||||
{
|
{
|
||||||
[System.Serializable]
|
[Serializable]
|
||||||
public class AnimatableProperty : ISerializationCallbackReceiver
|
public class AnimatableProperty : ISerializationCallbackReceiver
|
||||||
{
|
{
|
||||||
public enum ShaderPropertyType
|
public enum ShaderPropertyType
|
||||||
@@ -11,16 +12,22 @@ namespace Coffee.UIExtensions
|
|||||||
Vector,
|
Vector,
|
||||||
Float,
|
Float,
|
||||||
Range,
|
Range,
|
||||||
Texture,
|
Texture
|
||||||
}
|
}
|
||||||
|
|
||||||
[SerializeField] string m_Name = "";
|
[SerializeField] private string m_Name = "";
|
||||||
[SerializeField] ShaderPropertyType m_Type = ShaderPropertyType.Vector;
|
[SerializeField] private ShaderPropertyType m_Type = ShaderPropertyType.Vector;
|
||||||
public int id { get; private set; }
|
public int id { get; private set; }
|
||||||
|
|
||||||
public ShaderPropertyType type
|
public ShaderPropertyType type => m_Type;
|
||||||
|
|
||||||
|
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
||||||
{
|
{
|
||||||
get { return m_Type; }
|
}
|
||||||
|
|
||||||
|
void ISerializationCallbackReceiver.OnAfterDeserialize()
|
||||||
|
{
|
||||||
|
id = Shader.PropertyToID(m_Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateMaterialProperties(Material material, MaterialPropertyBlock mpb)
|
public void UpdateMaterialProperties(Material material, MaterialPropertyBlock mpb)
|
||||||
@@ -31,35 +38,38 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
case ShaderPropertyType.Color:
|
case ShaderPropertyType.Color:
|
||||||
var color = mpb.GetColor(id);
|
var color = mpb.GetColor(id);
|
||||||
if (color != default(Color))
|
if (color != default)
|
||||||
|
{
|
||||||
material.SetColor(id, color);
|
material.SetColor(id, color);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ShaderPropertyType.Vector:
|
case ShaderPropertyType.Vector:
|
||||||
var vector = mpb.GetVector(id);
|
var vector = mpb.GetVector(id);
|
||||||
if (vector != default(Vector4))
|
if (vector != default)
|
||||||
|
{
|
||||||
material.SetVector(id, vector);
|
material.SetVector(id, vector);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ShaderPropertyType.Float:
|
case ShaderPropertyType.Float:
|
||||||
case ShaderPropertyType.Range:
|
case ShaderPropertyType.Range:
|
||||||
var value = mpb.GetFloat(id);
|
var value = mpb.GetFloat(id);
|
||||||
if (value != default(float))
|
if (!Mathf.Approximately(value, 0))
|
||||||
|
{
|
||||||
material.SetFloat(id, value);
|
material.SetFloat(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ShaderPropertyType.Texture:
|
case ShaderPropertyType.Texture:
|
||||||
var tex = mpb.GetTexture(id);
|
var tex = mpb.GetTexture(id);
|
||||||
if (tex != default(Texture))
|
if (tex != default(Texture))
|
||||||
|
{
|
||||||
material.SetTexture(id, tex);
|
material.SetTexture(id, tex);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnBeforeSerialize()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnAfterDeserialize()
|
|
||||||
{
|
|
||||||
id = Shader.PropertyToID(m_Name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Coffee.UIParticleExtensions
|
namespace Coffee.UIParticleExtensions
|
||||||
@@ -7,26 +7,31 @@ namespace Coffee.UIParticleExtensions
|
|||||||
{
|
{
|
||||||
private static readonly List<MatEntry> s_Entries = new List<MatEntry>();
|
private static readonly List<MatEntry> s_Entries = new List<MatEntry>();
|
||||||
|
|
||||||
public static Material Add(Material baseMat, Texture texture, int id)
|
public static Material Add(Material baseMat, Texture texture, int id, int props)
|
||||||
{
|
{
|
||||||
MatEntry e;
|
MatEntry e;
|
||||||
for (var i = 0; i < s_Entries.Count; ++i)
|
for (var i = 0; i < s_Entries.Count; i++)
|
||||||
{
|
{
|
||||||
e = s_Entries[i];
|
e = s_Entries[i];
|
||||||
if (e.baseMat != baseMat || e.texture != texture || e.id != id) continue;
|
if (e.baseMat != baseMat || e.texture != texture || e.id != id || e.props != props) continue;
|
||||||
++e.count;
|
++e.count;
|
||||||
return e.customMat;
|
return e.customMat;
|
||||||
}
|
}
|
||||||
|
|
||||||
e = new MatEntry();
|
e = new MatEntry
|
||||||
e.count = 1;
|
{
|
||||||
e.baseMat = baseMat;
|
count = 1,
|
||||||
e.texture = texture;
|
baseMat = baseMat,
|
||||||
e.id = id;
|
texture = texture,
|
||||||
e.customMat = new Material(baseMat);
|
id = id,
|
||||||
e.customMat.hideFlags = HideFlags.HideAndDontSave;
|
props = props,
|
||||||
if (texture)
|
customMat = new Material(baseMat)
|
||||||
e.customMat.mainTexture = texture;
|
{
|
||||||
|
name = $"{baseMat.name}_{id}",
|
||||||
|
hideFlags = HideFlags.DontSave | HideFlags.NotEditable,
|
||||||
|
mainTexture = texture ? texture : baseMat.mainTexture
|
||||||
|
}
|
||||||
|
};
|
||||||
s_Entries.Add(e);
|
s_Entries.Add(e);
|
||||||
//Debug.LogFormat(">>>> ModifiedMaterial.Add -> count = count:{0}, mat:{1}, tex:{2}, id:{3}", s_Entries.Count, baseMat, texture, id);
|
//Debug.LogFormat(">>>> ModifiedMaterial.Add -> count = count:{0}, mat:{1}, tex:{2}, id:{3}", s_Entries.Count, baseMat, texture, id);
|
||||||
return e.customMat;
|
return e.customMat;
|
||||||
@@ -43,7 +48,8 @@ namespace Coffee.UIParticleExtensions
|
|||||||
if (--e.count == 0)
|
if (--e.count == 0)
|
||||||
{
|
{
|
||||||
//Debug.LogFormat(">>>> ModifiedMaterial.Remove -> count:{0}, mat:{1}, tex:{2}, id:{3}", s_Entries.Count - 1, e.customMat, e.texture, e.id);
|
//Debug.LogFormat(">>>> ModifiedMaterial.Remove -> count:{0}, mat:{1}, tex:{2}, id:{3}", s_Entries.Count - 1, e.customMat, e.texture, e.id);
|
||||||
DestroyImmediate(e.customMat);
|
Misc.DestroyImmediate(e.customMat);
|
||||||
|
e.customMat = null;
|
||||||
e.baseMat = null;
|
e.baseMat = null;
|
||||||
e.texture = null;
|
e.texture = null;
|
||||||
s_Entries.RemoveAt(i);
|
s_Entries.RemoveAt(i);
|
||||||
@@ -53,22 +59,14 @@ namespace Coffee.UIParticleExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DestroyImmediate(Object obj)
|
|
||||||
{
|
|
||||||
if (!obj) return;
|
|
||||||
if (Application.isEditor)
|
|
||||||
Object.DestroyImmediate(obj);
|
|
||||||
else
|
|
||||||
Object.Destroy(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class MatEntry
|
private class MatEntry
|
||||||
{
|
{
|
||||||
public Material baseMat;
|
public Material baseMat;
|
||||||
public Material customMat;
|
|
||||||
public int count;
|
public int count;
|
||||||
public Texture texture;
|
public Material customMat;
|
||||||
public int id;
|
public int id;
|
||||||
|
public int props;
|
||||||
|
public Texture texture;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
636
Runtime/UIParticle.cs
Normal file
636
Runtime/UIParticle.cs
Normal file
@@ -0,0 +1,636 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using Coffee.UIParticleExtensions;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Rendering;
|
||||||
|
using UnityEngine.Serialization;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
using Random = UnityEngine.Random;
|
||||||
|
|
||||||
|
[assembly: InternalsVisibleTo("Coffee.UIParticle.Editor")]
|
||||||
|
|
||||||
|
namespace Coffee.UIExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Render maskable and sortable particle effect ,without Camera, RenderTexture or Canvas.
|
||||||
|
/// </summary>
|
||||||
|
[ExecuteAlways]
|
||||||
|
[RequireComponent(typeof(RectTransform))]
|
||||||
|
[RequireComponent(typeof(CanvasRenderer))]
|
||||||
|
public class UIParticle : MaskableGraphic, ISerializationCallbackReceiver
|
||||||
|
{
|
||||||
|
public enum AutoScalingMode
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
UIParticle,
|
||||||
|
Transform
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum MeshSharing
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Auto,
|
||||||
|
Primary,
|
||||||
|
PrimarySimulator,
|
||||||
|
Replica
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PositionMode
|
||||||
|
{
|
||||||
|
Relative,
|
||||||
|
Absolute
|
||||||
|
}
|
||||||
|
|
||||||
|
[HideInInspector]
|
||||||
|
[SerializeField]
|
||||||
|
internal bool m_IsTrail;
|
||||||
|
|
||||||
|
[HideInInspector]
|
||||||
|
[FormerlySerializedAs("m_IgnoreParent")]
|
||||||
|
[SerializeField]
|
||||||
|
private bool m_IgnoreCanvasScaler;
|
||||||
|
|
||||||
|
[HideInInspector]
|
||||||
|
[SerializeField]
|
||||||
|
private bool m_AbsoluteMode;
|
||||||
|
|
||||||
|
[Tooltip("Particle effect scale")]
|
||||||
|
[SerializeField]
|
||||||
|
private Vector3 m_Scale3D = new Vector3(10, 10, 10);
|
||||||
|
|
||||||
|
[Tooltip("Animatable material properties.\n" +
|
||||||
|
"If you want to change the material properties of the ParticleSystem in Animation, enable it.")]
|
||||||
|
[SerializeField]
|
||||||
|
internal AnimatableProperty[] m_AnimatableProperties = new AnimatableProperty[0];
|
||||||
|
|
||||||
|
[Tooltip("Particles")]
|
||||||
|
[SerializeField]
|
||||||
|
private List<ParticleSystem> m_Particles = new List<ParticleSystem>();
|
||||||
|
|
||||||
|
[Tooltip("Mesh sharing.\n" +
|
||||||
|
"None: disable mesh sharing.\n" +
|
||||||
|
"Auto: automatically select Primary/Replica.\n" +
|
||||||
|
"Primary: provides particle simulation results to the same group.\n" +
|
||||||
|
"Primary Simulator: Primary, but do not render the particle (simulation only).\n" +
|
||||||
|
"Replica: render simulation results provided by the primary.")]
|
||||||
|
[SerializeField]
|
||||||
|
private MeshSharing m_MeshSharing = MeshSharing.None;
|
||||||
|
|
||||||
|
[Tooltip("Mesh sharing group ID.\n" +
|
||||||
|
"If non-zero is specified, particle simulation results are shared within the group.")]
|
||||||
|
[SerializeField]
|
||||||
|
private int m_GroupId;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private int m_GroupMaxId;
|
||||||
|
|
||||||
|
[Tooltip("Relative: The particles will be emitted from the scaled position of ParticleSystem.\n" +
|
||||||
|
"Absolute: The particles will be emitted from the world position of ParticleSystem.")]
|
||||||
|
[SerializeField]
|
||||||
|
private PositionMode m_PositionMode = PositionMode.Relative;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("Prevent the root-Canvas scale from affecting the hierarchy-scaled ParticleSystem.")]
|
||||||
|
private bool m_AutoScaling = true;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("Transform: Transform.lossyScale (=world scale) will be set to (1, 1, 1)." +
|
||||||
|
"UIParticle: UIParticle.scale will be adjusted.")]
|
||||||
|
private AutoScalingMode m_AutoScalingMode = AutoScalingMode.Transform;
|
||||||
|
|
||||||
|
private readonly List<UIParticleRenderer> _renderers = new List<UIParticleRenderer>();
|
||||||
|
private int _groupId;
|
||||||
|
private Camera _orthoCamera;
|
||||||
|
private DrivenRectTransformTracker _tracker;
|
||||||
|
private Vector3 _storedScale;
|
||||||
|
private bool _isScaleStored;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Should this graphic be considered a target for ray-casting?
|
||||||
|
/// </summary>
|
||||||
|
public override bool raycastTarget
|
||||||
|
{
|
||||||
|
get => false;
|
||||||
|
set { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mesh sharing.
|
||||||
|
/// None: disable mesh sharing.
|
||||||
|
/// Auto: automatically select Primary/Replica.
|
||||||
|
/// Primary: provides particle simulation results to the same group.
|
||||||
|
/// Primary Simulator: Primary, but do not render the particle (simulation only).
|
||||||
|
/// Replica: render simulation results provided by the primary.
|
||||||
|
/// </summary>
|
||||||
|
public MeshSharing meshSharing
|
||||||
|
{
|
||||||
|
get => m_MeshSharing;
|
||||||
|
set => m_MeshSharing = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mesh sharing group ID.
|
||||||
|
/// If non-zero is specified, particle simulation results are shared within the group.
|
||||||
|
/// </summary>
|
||||||
|
public int groupId
|
||||||
|
{
|
||||||
|
get => _groupId;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (m_GroupId == value) return;
|
||||||
|
m_GroupId = value;
|
||||||
|
if (m_GroupId != m_GroupMaxId)
|
||||||
|
{
|
||||||
|
ResetGroupId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int groupMaxId
|
||||||
|
{
|
||||||
|
get => m_GroupMaxId;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (m_GroupMaxId == value) return;
|
||||||
|
m_GroupMaxId = value;
|
||||||
|
ResetGroupId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Particle position mode.
|
||||||
|
/// Relative: The particles will be emitted from the scaled position of the ParticleSystem.
|
||||||
|
/// Absolute: The particles will be emitted from the world position of the ParticleSystem.
|
||||||
|
/// </summary>
|
||||||
|
public PositionMode positionMode
|
||||||
|
{
|
||||||
|
get => m_PositionMode;
|
||||||
|
set => m_PositionMode = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Particle position mode.
|
||||||
|
/// Relative: The particles will be emitted from the scaled position of the ParticleSystem.
|
||||||
|
/// Absolute: The particles will be emitted from the world position of the ParticleSystem.
|
||||||
|
/// </summary>
|
||||||
|
public bool absoluteMode
|
||||||
|
{
|
||||||
|
get => m_PositionMode == PositionMode.Absolute;
|
||||||
|
set => positionMode = value ? PositionMode.Absolute : PositionMode.Relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prevents the root-Canvas scale from affecting the hierarchy-scaled ParticleSystem.
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("The autoScaling is now obsolete. Please use the autoScalingMode instead.", false)]
|
||||||
|
public bool autoScaling
|
||||||
|
{
|
||||||
|
get => m_AutoScalingMode != AutoScalingMode.None;
|
||||||
|
set => autoScalingMode = value ? AutoScalingMode.Transform : AutoScalingMode.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Auto scaling mode.
|
||||||
|
/// Transform: Transform.lossyScale (=world scale) will be set to (1, 1, 1).
|
||||||
|
/// UIParticle: UIParticle.scale will be adjusted.
|
||||||
|
/// </summary>
|
||||||
|
public AutoScalingMode autoScalingMode
|
||||||
|
{
|
||||||
|
get => m_AutoScalingMode;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (m_AutoScalingMode == value) return;
|
||||||
|
m_AutoScalingMode = value;
|
||||||
|
|
||||||
|
if (autoScalingMode != AutoScalingMode.Transform && _isScaleStored)
|
||||||
|
{
|
||||||
|
transform.localScale = _storedScale;
|
||||||
|
_isScaleStored = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool useMeshSharing => m_MeshSharing != MeshSharing.None;
|
||||||
|
|
||||||
|
internal bool isPrimary =>
|
||||||
|
m_MeshSharing == MeshSharing.Primary
|
||||||
|
|| m_MeshSharing == MeshSharing.PrimarySimulator;
|
||||||
|
|
||||||
|
internal bool canSimulate =>
|
||||||
|
m_MeshSharing == MeshSharing.None
|
||||||
|
|| m_MeshSharing == MeshSharing.Auto
|
||||||
|
|| m_MeshSharing == MeshSharing.Primary
|
||||||
|
|| m_MeshSharing == MeshSharing.PrimarySimulator;
|
||||||
|
|
||||||
|
internal bool canRender =>
|
||||||
|
m_MeshSharing == MeshSharing.None
|
||||||
|
|| m_MeshSharing == MeshSharing.Auto
|
||||||
|
|| m_MeshSharing == MeshSharing.Primary
|
||||||
|
|| m_MeshSharing == MeshSharing.Replica;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Particle effect scale.
|
||||||
|
/// </summary>
|
||||||
|
public float scale
|
||||||
|
{
|
||||||
|
get => m_Scale3D.x;
|
||||||
|
set => m_Scale3D = new Vector3(value, value, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Particle effect scale.
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 scale3D
|
||||||
|
{
|
||||||
|
get => m_Scale3D;
|
||||||
|
set => m_Scale3D = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Particle effect scale.
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 scale3DForCalc => autoScalingMode == AutoScalingMode.Transform
|
||||||
|
? m_Scale3D
|
||||||
|
: m_Scale3D.GetScaled(canvasScale, transform.localScale);
|
||||||
|
|
||||||
|
public List<ParticleSystem> particles => m_Particles;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get all base materials to render.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<Material> materials
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
for (var i = 0; i < _renderers.Count; i++)
|
||||||
|
{
|
||||||
|
var r = _renderers[i];
|
||||||
|
if (!r || !r.material) continue;
|
||||||
|
yield return r.material;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Material materialForRendering => null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Paused.
|
||||||
|
/// </summary>
|
||||||
|
public bool isPaused { get; private set; }
|
||||||
|
|
||||||
|
public Vector3 parentScale { get; private set; }
|
||||||
|
|
||||||
|
public Vector3 canvasScale { get; private set; }
|
||||||
|
|
||||||
|
protected override void OnEnable()
|
||||||
|
{
|
||||||
|
_isScaleStored = false;
|
||||||
|
ResetGroupId();
|
||||||
|
UIParticleUpdater.Register(this);
|
||||||
|
RegisterDirtyMaterialCallback(UpdateRendererMaterial);
|
||||||
|
|
||||||
|
if (0 < particles.Count)
|
||||||
|
{
|
||||||
|
RefreshParticles(particles);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RefreshParticles();
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnEnable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This function is called when the behaviour becomes disabled.
|
||||||
|
/// </summary>
|
||||||
|
protected override void OnDisable()
|
||||||
|
{
|
||||||
|
_tracker.Clear();
|
||||||
|
if (autoScalingMode == AutoScalingMode.Transform && _isScaleStored)
|
||||||
|
{
|
||||||
|
transform.localScale = _storedScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isScaleStored = false;
|
||||||
|
UIParticleUpdater.Unregister(this);
|
||||||
|
_renderers.ForEach(r => r.Reset());
|
||||||
|
UnregisterDirtyMaterialCallback(UpdateRendererMaterial);
|
||||||
|
|
||||||
|
base.OnDisable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Callback for when properties have been changed by animation.
|
||||||
|
/// </summary>
|
||||||
|
protected override void OnDidApplyAnimationProperties()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISerializationCallbackReceiver.OnAfterDeserialize()
|
||||||
|
{
|
||||||
|
if (m_IgnoreCanvasScaler || m_AutoScaling)
|
||||||
|
{
|
||||||
|
m_IgnoreCanvasScaler = false;
|
||||||
|
m_AutoScaling = false;
|
||||||
|
m_AutoScalingMode = AutoScalingMode.Transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_AbsoluteMode)
|
||||||
|
{
|
||||||
|
m_AbsoluteMode = false;
|
||||||
|
m_PositionMode = PositionMode.Absolute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Play()
|
||||||
|
{
|
||||||
|
particles.Exec(p => p.Simulate(0, false, true));
|
||||||
|
isPaused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Pause()
|
||||||
|
{
|
||||||
|
particles.Exec(p => p.Pause());
|
||||||
|
isPaused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Resume()
|
||||||
|
{
|
||||||
|
isPaused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
particles.Exec(p => p.Stop());
|
||||||
|
isPaused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartEmission()
|
||||||
|
{
|
||||||
|
particles.Exec(p =>
|
||||||
|
{
|
||||||
|
var emission = p.emission;
|
||||||
|
emission.enabled = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopEmission()
|
||||||
|
{
|
||||||
|
particles.Exec(p =>
|
||||||
|
{
|
||||||
|
var emission = p.emission;
|
||||||
|
emission.enabled = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
particles.Exec(p => p.Clear());
|
||||||
|
isPaused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetParticleSystemInstance(GameObject instance)
|
||||||
|
{
|
||||||
|
SetParticleSystemInstance(instance, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetParticleSystemInstance(GameObject instance, bool destroyOldParticles)
|
||||||
|
{
|
||||||
|
if (!instance) return;
|
||||||
|
|
||||||
|
foreach (Transform child in transform)
|
||||||
|
{
|
||||||
|
var go = child.gameObject;
|
||||||
|
go.SetActive(false);
|
||||||
|
if (destroyOldParticles)
|
||||||
|
{
|
||||||
|
Misc.Destroy(go);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var tr = instance.transform;
|
||||||
|
tr.SetParent(transform, false);
|
||||||
|
tr.localPosition = Vector3.zero;
|
||||||
|
|
||||||
|
RefreshParticles(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetParticleSystemPrefab(GameObject prefab)
|
||||||
|
{
|
||||||
|
if (!prefab) return;
|
||||||
|
|
||||||
|
SetParticleSystemInstance(Instantiate(prefab.gameObject), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RefreshParticles()
|
||||||
|
{
|
||||||
|
RefreshParticles(gameObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshParticles(GameObject root)
|
||||||
|
{
|
||||||
|
if (!root) return;
|
||||||
|
root.GetComponentsInChildren(true, particles);
|
||||||
|
particles.RemoveAll(x => x.GetComponentInParent<UIParticle>(true) != this);
|
||||||
|
|
||||||
|
for (var i = 0; i < particles.Count; i++)
|
||||||
|
{
|
||||||
|
var ps = particles[i];
|
||||||
|
var tsa = ps.textureSheetAnimation;
|
||||||
|
if (tsa.mode == ParticleSystemAnimationMode.Sprites && tsa.uvChannelMask == 0)
|
||||||
|
{
|
||||||
|
tsa.uvChannelMask = UVChannelFlags.UV0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RefreshParticles(particles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RefreshParticles(List<ParticleSystem> particles)
|
||||||
|
{
|
||||||
|
// #246: Nullptr exceptions when using nested UIParticle components in hierarchy
|
||||||
|
_renderers.Clear();
|
||||||
|
foreach (Transform child in transform)
|
||||||
|
{
|
||||||
|
var uiParticleRenderer = child.GetComponent<UIParticleRenderer>();
|
||||||
|
|
||||||
|
if (uiParticleRenderer != null)
|
||||||
|
{
|
||||||
|
_renderers.Add(uiParticleRenderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < _renderers.Count; i++)
|
||||||
|
{
|
||||||
|
_renderers[i].Reset(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
var j = 0;
|
||||||
|
for (var i = 0; i < particles.Count; i++)
|
||||||
|
{
|
||||||
|
var ps = particles[i];
|
||||||
|
if (!ps) continue;
|
||||||
|
GetRenderer(j++).Set(this, ps, false);
|
||||||
|
if (ps.trails.enabled)
|
||||||
|
{
|
||||||
|
GetRenderer(j++).Set(this, ps, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void UpdateTransformScale()
|
||||||
|
{
|
||||||
|
_tracker.Clear();
|
||||||
|
canvasScale = canvas.rootCanvas.transform.localScale.Inverse();
|
||||||
|
parentScale = transform.parent.lossyScale;
|
||||||
|
if (autoScalingMode != AutoScalingMode.Transform)
|
||||||
|
{
|
||||||
|
if (_isScaleStored)
|
||||||
|
{
|
||||||
|
transform.localScale = _storedScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isScaleStored = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentScale = transform.localScale;
|
||||||
|
_storedScale = currentScale;
|
||||||
|
_isScaleStored = true;
|
||||||
|
_tracker.Add(this, rectTransform, DrivenTransformProperties.Scale);
|
||||||
|
var newScale = parentScale.Inverse();
|
||||||
|
if (currentScale != newScale)
|
||||||
|
{
|
||||||
|
transform.localScale = newScale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void UpdateRenderers()
|
||||||
|
{
|
||||||
|
if (!isActiveAndEnabled) return;
|
||||||
|
|
||||||
|
for (var i = 0; i < _renderers.Count; i++)
|
||||||
|
{
|
||||||
|
var r = _renderers[i];
|
||||||
|
if (!r)
|
||||||
|
{
|
||||||
|
RefreshParticles(particles);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var bakeCamera = GetBakeCamera();
|
||||||
|
for (var i = 0; i < _renderers.Count; i++)
|
||||||
|
{
|
||||||
|
var r = _renderers[i];
|
||||||
|
if (!r) continue;
|
||||||
|
r.UpdateMesh(bakeCamera);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void ResetGroupId()
|
||||||
|
{
|
||||||
|
_groupId = m_GroupId == m_GroupMaxId
|
||||||
|
? m_GroupId
|
||||||
|
: 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) continue;
|
||||||
|
r.maskable = maskable;
|
||||||
|
r.SetMaterialDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal UIParticleRenderer GetRenderer(int index)
|
||||||
|
{
|
||||||
|
if (_renderers.Count <= index)
|
||||||
|
{
|
||||||
|
_renderers.Add(UIParticleRenderer.AddRenderer(this, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_renderers[index])
|
||||||
|
{
|
||||||
|
_renderers[index] = UIParticleRenderer.AddRenderer(this, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _renderers[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
private Camera GetBakeCamera()
|
||||||
|
{
|
||||||
|
if (!canvas) return Camera.main;
|
||||||
|
|
||||||
|
// When render mode is ScreenSpaceCamera or WorldSpace, use world camera.
|
||||||
|
var root = canvas.rootCanvas;
|
||||||
|
if (root.renderMode != RenderMode.ScreenSpaceOverlay)
|
||||||
|
{
|
||||||
|
return root.worldCamera ? root.worldCamera : Camera.main;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When render mode is ScreenSpaceOverlay, use ortho-camera.
|
||||||
|
if (!_orthoCamera)
|
||||||
|
{
|
||||||
|
// Find existing ortho-camera.
|
||||||
|
foreach (Transform child in transform)
|
||||||
|
{
|
||||||
|
var cam = child.GetComponent<Camera>();
|
||||||
|
if (cam && cam.name == "[generated] UIParticleOverlayCamera")
|
||||||
|
{
|
||||||
|
_orthoCamera = cam;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create ortho-camera.
|
||||||
|
if (!_orthoCamera)
|
||||||
|
{
|
||||||
|
var go = new GameObject("[generated] UIParticleOverlayCamera")
|
||||||
|
{
|
||||||
|
hideFlags = HideFlags.HideAndDontSave
|
||||||
|
};
|
||||||
|
go.SetActive(false);
|
||||||
|
go.transform.SetParent(transform, false);
|
||||||
|
_orthoCamera = go.AddComponent<Camera>();
|
||||||
|
_orthoCamera.enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
var size = ((RectTransform)root.transform).rect.size;
|
||||||
|
_orthoCamera.orthographicSize = Mathf.Max(size.x, size.y) * root.scaleFactor;
|
||||||
|
_orthoCamera.transform.SetPositionAndRotation(new Vector3(0, 0, -1000), Quaternion.identity);
|
||||||
|
_orthoCamera.orthographic = true;
|
||||||
|
_orthoCamera.farClipPlane = 2000f;
|
||||||
|
_orthoCamera.clearFlags = CameraClearFlags.Nothing;
|
||||||
|
_orthoCamera.cullingMask = 0; // Nothing
|
||||||
|
_orthoCamera.allowHDR = false;
|
||||||
|
_orthoCamera.allowMSAA = false;
|
||||||
|
_orthoCamera.renderingPath = RenderingPath.Forward;
|
||||||
|
_orthoCamera.useOcclusionCulling = false;
|
||||||
|
|
||||||
|
return _orthoCamera;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ MonoImporter:
|
|||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
defaultReferences: []
|
defaultReferences: []
|
||||||
executionOrder: 0
|
executionOrder: 0
|
||||||
icon: {instanceID: 0}
|
icon: {fileID: 2800000, guid: 5f0675613942149309588d556e33d990, type: 3}
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
assetBundleVariant:
|
assetBundleVariant:
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using UnityEngine;
|
|
||||||
using Coffee.UIParticleExtensions;
|
|
||||||
using UnityEngine.Events;
|
|
||||||
using System;
|
using System;
|
||||||
|
using Coffee.UIParticleExtensions;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
|
||||||
namespace Coffee.UIExtensions
|
namespace Coffee.UIExtensions
|
||||||
{
|
{
|
||||||
@@ -12,7 +12,13 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
Linear,
|
Linear,
|
||||||
Smooth,
|
Smooth,
|
||||||
Sphere,
|
Sphere
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum UpdateMode
|
||||||
|
{
|
||||||
|
Normal,
|
||||||
|
UnscaledTime
|
||||||
}
|
}
|
||||||
|
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
@@ -24,7 +30,7 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
[Range(0f, 0.95f)]
|
[Range(0f, 0.95f)]
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
private float m_DelayRate = 0;
|
private float m_DelayRate;
|
||||||
|
|
||||||
[Range(0.001f, 100f)]
|
[Range(0.001f, 100f)]
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
@@ -33,70 +39,84 @@ namespace Coffee.UIExtensions
|
|||||||
[SerializeField]
|
[SerializeField]
|
||||||
private Movement m_Movement;
|
private Movement m_Movement;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private UpdateMode m_UpdateMode;
|
||||||
|
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
private UnityEvent m_OnAttracted;
|
private UnityEvent m_OnAttracted;
|
||||||
|
|
||||||
|
private UIParticle _uiParticle;
|
||||||
|
|
||||||
|
public float destinationRadius
|
||||||
|
{
|
||||||
|
get => m_DestinationRadius;
|
||||||
|
set => m_DestinationRadius = Mathf.Clamp(value, 0.1f, 10f);
|
||||||
|
}
|
||||||
|
|
||||||
public float delay
|
public float delay
|
||||||
{
|
{
|
||||||
get
|
get => m_DelayRate;
|
||||||
{
|
set => m_DelayRate = value;
|
||||||
return m_DelayRate;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
m_DelayRate = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public float maxSpeed
|
public float maxSpeed
|
||||||
{
|
{
|
||||||
get
|
get => m_MaxSpeed;
|
||||||
{
|
set => m_MaxSpeed = value;
|
||||||
return m_MaxSpeed;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
m_MaxSpeed = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Movement movement
|
public Movement movement
|
||||||
{
|
{
|
||||||
get
|
get => m_Movement;
|
||||||
{
|
set => m_Movement = value;
|
||||||
return m_Movement;
|
}
|
||||||
}
|
|
||||||
|
public UpdateMode updateMode
|
||||||
|
{
|
||||||
|
get => m_UpdateMode;
|
||||||
|
set => m_UpdateMode = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnityEvent onAttracted
|
||||||
|
{
|
||||||
|
get => m_OnAttracted;
|
||||||
|
set => m_OnAttracted = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The target ParticleSystem to attract.
|
||||||
|
/// </summary>
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
public new ParticleSystem particleSystem
|
||||||
|
#else
|
||||||
|
public ParticleSystem particleSystem
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
get => m_ParticleSystem;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
m_Movement = value;
|
m_ParticleSystem = value;
|
||||||
|
ApplyParticleSystem();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private UIParticle _uiParticle;
|
|
||||||
|
|
||||||
private void OnEnable()
|
private void OnEnable()
|
||||||
{
|
{
|
||||||
if (m_ParticleSystem == null)
|
ApplyParticleSystem();
|
||||||
{
|
|
||||||
Debug.LogError("No particle system attached to particle attractor script", this);
|
|
||||||
enabled = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_uiParticle = m_ParticleSystem.GetComponentInParent<UIParticle>();
|
|
||||||
if (_uiParticle && !_uiParticle.particles.Contains(m_ParticleSystem))
|
|
||||||
{
|
|
||||||
_uiParticle = null;
|
|
||||||
}
|
|
||||||
UIParticleUpdater.Register(this);
|
UIParticleUpdater.Register(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDisable()
|
private void OnDisable()
|
||||||
{
|
{
|
||||||
_uiParticle = null;
|
|
||||||
UIParticleUpdater.Unregister(this);
|
UIParticleUpdater.Unregister(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnDestroy()
|
||||||
|
{
|
||||||
|
_uiParticle = null;
|
||||||
|
m_ParticleSystem = null;
|
||||||
|
}
|
||||||
|
|
||||||
internal void Attract()
|
internal void Attract()
|
||||||
{
|
{
|
||||||
if (m_ParticleSystem == null) return;
|
if (m_ParticleSystem == null) return;
|
||||||
@@ -128,6 +148,7 @@ namespace Coffee.UIExtensions
|
|||||||
Debug.LogException(e);
|
Debug.LogException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,36 +175,52 @@ namespace Coffee.UIExtensions
|
|||||||
var psPos = m_ParticleSystem.transform.position;
|
var psPos = m_ParticleSystem.transform.position;
|
||||||
var attractorPos = transform.position;
|
var attractorPos = transform.position;
|
||||||
var dstPos = attractorPos;
|
var dstPos = attractorPos;
|
||||||
if (m_ParticleSystem.main.simulationSpace == ParticleSystemSimulationSpace.Local)
|
var isLocalSpace = m_ParticleSystem.IsLocalSpace();
|
||||||
|
|
||||||
|
if (isLocalSpace)
|
||||||
{
|
{
|
||||||
dstPos = m_ParticleSystem.transform.InverseTransformPoint(dstPos);
|
dstPos = m_ParticleSystem.transform.InverseTransformPoint(dstPos);
|
||||||
if (isUI)
|
|
||||||
{
|
|
||||||
dstPos = dstPos.GetScaled(_uiParticle.transform.localScale, _uiParticle.scale3D.Inverse());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (isUI)
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
var inverseScale = _uiParticle.parentScale.Inverse();
|
||||||
if (!Application.isPlaying && isUI)
|
var scale3d = _uiParticle.scale3DForCalc;
|
||||||
|
dstPos = dstPos.GetScaled(inverseScale, scale3d.Inverse());
|
||||||
|
|
||||||
|
// Relative mode
|
||||||
|
if (_uiParticle.positionMode == UIParticle.PositionMode.Relative)
|
||||||
{
|
{
|
||||||
var diff = dstPos - psPos;
|
var diff = _uiParticle.transform.position - psPos;
|
||||||
diff = diff.GetScaled(_uiParticle.transform.localScale, _uiParticle.scale3D.Inverse());
|
diff.Scale(scale3d - inverseScale);
|
||||||
return psPos + diff;
|
diff.Scale(scale3d.Inverse());
|
||||||
|
dstPos += diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (!Application.isPlaying && !isLocalSpace)
|
||||||
|
{
|
||||||
|
dstPos += psPos - psPos.GetScaled(inverseScale, scale3d.Inverse());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (isUI)
|
|
||||||
{
|
|
||||||
dstPos.Scale(_uiParticle.transform.localScale);
|
|
||||||
dstPos.Scale(_uiParticle.scale3D.Inverse());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dstPos;
|
return dstPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector3 GetAttractedPosition(Vector3 current, Vector3 target, float duration, float time)
|
private Vector3 GetAttractedPosition(Vector3 current, Vector3 target, float duration, float time)
|
||||||
{
|
{
|
||||||
var speed = m_MaxSpeed;
|
var speed = m_MaxSpeed;
|
||||||
|
switch (m_UpdateMode)
|
||||||
|
{
|
||||||
|
case UpdateMode.Normal:
|
||||||
|
speed *= 60 * Time.deltaTime;
|
||||||
|
break;
|
||||||
|
case UpdateMode.UnscaledTime:
|
||||||
|
speed *= 60 * Time.unscaledDeltaTime;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
switch (m_Movement)
|
switch (m_Movement)
|
||||||
{
|
{
|
||||||
case Movement.Linear:
|
case Movement.Linear:
|
||||||
@@ -200,5 +237,26 @@ namespace Coffee.UIExtensions
|
|||||||
return Vector3.MoveTowards(current, target, speed);
|
return Vector3.MoveTowards(current, target, speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ApplyParticleSystem()
|
||||||
|
{
|
||||||
|
_uiParticle = null;
|
||||||
|
if (m_ParticleSystem == null)
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (Application.isPlaying)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
Debug.LogError("No particle system attached to particle attractor script", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_uiParticle = m_ParticleSystem.GetComponentInParent<UIParticle>(true);
|
||||||
|
if (_uiParticle && !_uiParticle.particles.Contains(m_ParticleSystem))
|
||||||
|
{
|
||||||
|
_uiParticle = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,17 @@
|
|||||||
using UnityEngine;
|
#if UNITY_2022_3_0 || UNITY_2022_3_1 || UNITY_2022_3_2 || UNITY_2022_3_3 || UNITY_2022_3_4 || UNITY_2022_3_5 || UNITY_2022_3_6 || UNITY_2022_3_7 || UNITY_2022_3_8 || UNITY_2022_3_9 || UNITY_2022_3_10
|
||||||
using UnityEngine.UI;
|
#elif UNITY_2023_1_0 || UNITY_2023_1_1 || UNITY_2023_1_2 || UNITY_2023_1_3 || UNITY_2023_1_4 || UNITY_2023_1_5 || UNITY_2023_1_6 || UNITY_2023_1_7 || UNITY_2023_1_8 || UNITY_2023_1_9
|
||||||
|
#elif UNITY_2023_1_10 || UNITY_2023_1_11 || UNITY_2023_1_12 || UNITY_2023_1_13 || UNITY_2023_1_14 || UNITY_2023_1_15 || UNITY_2023_1_16
|
||||||
|
#elif UNITY_2022_3_OR_NEWER
|
||||||
|
#define PS_BAKE_API_V2
|
||||||
|
#endif
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Coffee.UIParticleExtensions;
|
using Coffee.UIParticleExtensions;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
using UnityEngine.Profiling;
|
using UnityEngine.Profiling;
|
||||||
using UnityEngine.Rendering;
|
using UnityEngine.Rendering;
|
||||||
using System.Collections.Generic;
|
using UnityEngine.UI;
|
||||||
|
|
||||||
namespace Coffee.UIExtensions
|
namespace Coffee.UIExtensions
|
||||||
{
|
{
|
||||||
@@ -13,50 +21,142 @@ namespace Coffee.UIExtensions
|
|||||||
[AddComponentMenu("")]
|
[AddComponentMenu("")]
|
||||||
internal class UIParticleRenderer : MaskableGraphic
|
internal class UIParticleRenderer : MaskableGraphic
|
||||||
{
|
{
|
||||||
private static readonly CombineInstance[] s_CombineInstances = new CombineInstance[] { new CombineInstance() };
|
private static readonly List<Component> s_Components = new List<Component>();
|
||||||
//private static ParticleSystem.Particle[] s_Particles = new ParticleSystem.Particle[2048];
|
private static readonly CombineInstance[] s_CombineInstances = { new CombineInstance() };
|
||||||
private static readonly List<Material> s_Materials = new List<Material>(2);
|
private static readonly List<Material> s_Materials = new List<Material>(2);
|
||||||
private static MaterialPropertyBlock s_Mpb;
|
private static MaterialPropertyBlock s_Mpb;
|
||||||
private static readonly List<UIParticleRenderer> s_Renderers = new List<UIParticleRenderer>();
|
private static readonly List<UIParticleRenderer> s_Renderers = new List<UIParticleRenderer>();
|
||||||
|
private static readonly List<Color32> s_Colors = new List<Color32>();
|
||||||
private ParticleSystemRenderer _renderer;
|
private static readonly Vector3[] s_Corners = new Vector3[4];
|
||||||
private ParticleSystem _particleSystem;
|
private Material _currentMaterialForRendering;
|
||||||
internal int _prevParticleCount = 0;
|
private bool _delay;
|
||||||
//private ParticleSystem _emitter;
|
|
||||||
private UIParticle _parent;
|
|
||||||
private int _index;
|
private int _index;
|
||||||
private bool _isTrail;
|
private bool _isTrail;
|
||||||
|
private Bounds _lastBounds;
|
||||||
private Material _modifiedMaterial;
|
private Material _modifiedMaterial;
|
||||||
private Vector3 _prevScale;
|
private UIParticle _parent;
|
||||||
|
private ParticleSystem _particleSystem;
|
||||||
|
private float _prevCanvasScale;
|
||||||
private Vector3 _prevPsPos;
|
private Vector3 _prevPsPos;
|
||||||
|
private Vector3 _prevScale;
|
||||||
|
private bool _isPrevStored;
|
||||||
private Vector2Int _prevScreenSize;
|
private Vector2Int _prevScreenSize;
|
||||||
private bool _delay = false;
|
private bool _prewarm;
|
||||||
private bool _prewarm = false;
|
private ParticleSystemRenderer _renderer;
|
||||||
private Material _currentMaterialForRendering;
|
|
||||||
|
|
||||||
public override Texture mainTexture
|
public override Texture mainTexture => _isTrail ? null : _particleSystem.GetTextureForSprite();
|
||||||
|
|
||||||
|
public override bool raycastTarget => false;
|
||||||
|
|
||||||
|
private Rect rootCanvasRect
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return _isTrail ? null : _particleSystem.GetTextureForSprite();
|
s_Corners[0] = transform.TransformPoint(_lastBounds.min.x, _lastBounds.min.y, 0);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
var worldToLocalMatrix = canvas.rootCanvas.transform.worldToLocalMatrix;
|
||||||
|
for (var i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
s_Corners[i] = worldToLocalMatrix.MultiplyPoint(s_Corners[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var corner1 = (Vector2)s_Corners[0];
|
||||||
|
var corner2 = (Vector2)s_Corners[0];
|
||||||
|
for (var i = 1; i < 4; ++i)
|
||||||
|
{
|
||||||
|
if (s_Corners[i].x < corner1.x)
|
||||||
|
{
|
||||||
|
corner1.x = s_Corners[i].x;
|
||||||
|
}
|
||||||
|
else if (s_Corners[i].x > corner2.x)
|
||||||
|
{
|
||||||
|
corner2.x = s_Corners[i].x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_Corners[i].y < corner1.y)
|
||||||
|
{
|
||||||
|
corner1.y = s_Corners[i].y;
|
||||||
|
}
|
||||||
|
else if (s_Corners[i].y > corner2.y)
|
||||||
|
{
|
||||||
|
corner2.y = s_Corners[i].y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Rect(corner1, corner2 - corner1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool raycastTarget
|
public void Reset(int index = -1)
|
||||||
{
|
{
|
||||||
get
|
if (_renderer)
|
||||||
{
|
{
|
||||||
return false;
|
_renderer.enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_parent = null;
|
||||||
|
_particleSystem = null;
|
||||||
|
_renderer = null;
|
||||||
|
if (0 <= index)
|
||||||
|
{
|
||||||
|
_index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
//_emitter = null;
|
||||||
|
if (this && isActiveAndEnabled)
|
||||||
|
{
|
||||||
|
material = null;
|
||||||
|
workerMesh.Clear();
|
||||||
|
canvasRenderer.SetMesh(workerMesh);
|
||||||
|
_lastBounds = new Bounds();
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ModifiedMaterial.Remove(_modifiedMaterial);
|
||||||
|
_modifiedMaterial = null;
|
||||||
|
_currentMaterialForRendering = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnEnable()
|
||||||
|
{
|
||||||
|
base.OnEnable();
|
||||||
|
|
||||||
|
if (!s_CombineInstances[0].mesh)
|
||||||
|
{
|
||||||
|
s_CombineInstances[0].mesh = new Mesh
|
||||||
|
{
|
||||||
|
name = "[UIParticleRenderer] Combine Instance Mesh",
|
||||||
|
hideFlags = HideFlags.HideAndDontSave
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentMaterialForRendering = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDisable()
|
||||||
|
{
|
||||||
|
base.OnDisable();
|
||||||
|
|
||||||
|
ModifiedMaterial.Remove(_modifiedMaterial);
|
||||||
|
_modifiedMaterial = null;
|
||||||
|
_currentMaterialForRendering = null;
|
||||||
|
_isPrevStored = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UIParticleRenderer AddRenderer(UIParticle parent, int index)
|
public static UIParticleRenderer AddRenderer(UIParticle parent, int index)
|
||||||
{
|
{
|
||||||
// Create renderer object.
|
// Create renderer object.
|
||||||
var go = new GameObject("UIParticleRenderer", typeof(UIParticleRenderer))
|
var go = new GameObject("[generated] UIParticleRenderer", typeof(UIParticleRenderer))
|
||||||
{
|
{
|
||||||
hideFlags = HideFlags.DontSave,
|
hideFlags = HideFlags.HideAndDontSave,
|
||||||
layer = parent.gameObject.layer,
|
layer = parent.gameObject.layer
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set parent.
|
// Set parent.
|
||||||
@@ -81,11 +181,16 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
_currentMaterialForRendering = null;
|
_currentMaterialForRendering = null;
|
||||||
|
|
||||||
if (!IsActive()) return baseMaterial;
|
if (!IsActive() || !_parent)
|
||||||
|
{
|
||||||
|
ModifiedMaterial.Remove(_modifiedMaterial);
|
||||||
|
_modifiedMaterial = null;
|
||||||
|
return baseMaterial;
|
||||||
|
}
|
||||||
|
|
||||||
var modifiedMaterial = base.GetModifiedMaterial(baseMaterial);
|
var modifiedMaterial = base.GetModifiedMaterial(baseMaterial);
|
||||||
|
|
||||||
//
|
//
|
||||||
var texture = mainTexture;
|
var texture = mainTexture;
|
||||||
if (texture == null && _parent.m_AnimatableProperties.Length == 0)
|
if (texture == null && _parent.m_AnimatableProperties.Length == 0)
|
||||||
{
|
{
|
||||||
@@ -96,56 +201,40 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
//
|
//
|
||||||
var id = _parent.m_AnimatableProperties.Length == 0 ? 0 : GetInstanceID();
|
var id = _parent.m_AnimatableProperties.Length == 0 ? 0 : GetInstanceID();
|
||||||
modifiedMaterial = ModifiedMaterial.Add(modifiedMaterial, texture, id);
|
#if UNITY_EDITOR
|
||||||
|
var props = EditorJsonUtility.ToJson(modifiedMaterial).GetHashCode();
|
||||||
|
#else
|
||||||
|
var props = 0;
|
||||||
|
#endif
|
||||||
|
modifiedMaterial = ModifiedMaterial.Add(modifiedMaterial, texture, id, props);
|
||||||
ModifiedMaterial.Remove(_modifiedMaterial);
|
ModifiedMaterial.Remove(_modifiedMaterial);
|
||||||
_modifiedMaterial = modifiedMaterial;
|
_modifiedMaterial = modifiedMaterial;
|
||||||
|
|
||||||
return modifiedMaterial;
|
return modifiedMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear(int index = -1)
|
public void Set(UIParticle parent, ParticleSystem ps, bool isTrail)
|
||||||
{
|
|
||||||
if (_renderer)
|
|
||||||
{
|
|
||||||
_renderer.enabled = true;
|
|
||||||
}
|
|
||||||
_parent = null;
|
|
||||||
_particleSystem = null;
|
|
||||||
_renderer = null;
|
|
||||||
_prevParticleCount = 0;
|
|
||||||
if (0 <= index)
|
|
||||||
{
|
|
||||||
_index = index;
|
|
||||||
}
|
|
||||||
//_emitter = null;
|
|
||||||
if (this && isActiveAndEnabled)
|
|
||||||
{
|
|
||||||
material = null;
|
|
||||||
workerMesh.Clear();
|
|
||||||
canvasRenderer.SetMesh(workerMesh);
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Set(UIParticle parent, ParticleSystem particleSystem, bool isTrail)
|
|
||||||
{
|
{
|
||||||
_parent = parent;
|
_parent = parent;
|
||||||
maskable = parent.maskable;
|
maskable = parent.maskable;
|
||||||
|
|
||||||
gameObject.layer = parent.gameObject.layer;
|
gameObject.layer = parent.gameObject.layer;
|
||||||
|
|
||||||
_particleSystem = particleSystem;
|
_particleSystem = ps;
|
||||||
|
_prewarm = _particleSystem.main.prewarm;
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
if (Application.isPlaying)
|
if (Application.isPlaying)
|
||||||
#endif
|
#endif
|
||||||
if (_particleSystem.isPlaying)
|
|
||||||
{
|
{
|
||||||
_particleSystem.Clear();
|
if (_particleSystem.isPlaying || _prewarm)
|
||||||
_particleSystem.Pause();
|
{
|
||||||
|
_particleSystem.Clear();
|
||||||
|
_particleSystem.Pause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_prewarm = _particleSystem.main.prewarm;
|
|
||||||
|
|
||||||
_renderer = particleSystem.GetComponent<ParticleSystemRenderer>();
|
_renderer = ps.GetComponent<ParticleSystemRenderer>();
|
||||||
_renderer.enabled = false;
|
_renderer.enabled = false;
|
||||||
|
|
||||||
//_emitter = emitter;
|
//_emitter = emitter;
|
||||||
@@ -156,15 +245,17 @@ namespace Coffee.UIExtensions
|
|||||||
s_Materials.Clear();
|
s_Materials.Clear();
|
||||||
|
|
||||||
// Support sprite.
|
// Support sprite.
|
||||||
var tsa = particleSystem.textureSheetAnimation;
|
var tsa = ps.textureSheetAnimation;
|
||||||
if (tsa.mode == ParticleSystemAnimationMode.Sprites && tsa.uvChannelMask == 0)
|
if (tsa.mode == ParticleSystemAnimationMode.Sprites && tsa.uvChannelMask == 0)
|
||||||
|
{
|
||||||
tsa.uvChannelMask = UVChannelFlags.UV0;
|
tsa.uvChannelMask = UVChannelFlags.UV0;
|
||||||
|
}
|
||||||
|
|
||||||
_prevScale = GetWorldScale();
|
_prevScale = GetWorldScale();
|
||||||
_prevPsPos = _particleSystem.transform.position;
|
_prevPsPos = _particleSystem.transform.position;
|
||||||
_prevScreenSize = new Vector2Int(Screen.width, Screen.height);
|
_prevScreenSize = new Vector2Int(Screen.width, Screen.height);
|
||||||
|
_prevCanvasScale = canvas ? canvas.scaleFactor : 1f;
|
||||||
_delay = true;
|
_delay = true;
|
||||||
_prevParticleCount = 0;
|
|
||||||
|
|
||||||
canvasRenderer.SetTexture(null);
|
canvasRenderer.SetTexture(null);
|
||||||
|
|
||||||
@@ -175,19 +266,22 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
// No particle to render: Clear mesh.
|
// No particle to render: Clear mesh.
|
||||||
if (
|
if (
|
||||||
!isActiveAndEnabled || !_particleSystem || !_parent || !canvasRenderer || !canvas || !bakeCamera
|
!isActiveAndEnabled || !_particleSystem || !_parent
|
||||||
|| _parent.meshSharing == UIParticle.MeshSharing.Reprica
|
|| !canvasRenderer || !canvas || !bakeCamera
|
||||||
|| !transform.lossyScale.GetScaled(_parent.scale3D).IsVisible() // Scale is not visible.
|
|| _parent.meshSharing == UIParticle.MeshSharing.Replica
|
||||||
|| (!_particleSystem.IsAlive() && !_particleSystem.isPlaying) // No particle.
|
|| !transform.lossyScale.GetScaled(_parent.scale3DForCalc).IsVisible() // Scale is not visible.
|
||||||
|| (_isTrail && !_particleSystem.trails.enabled) // Trail, but it is not enabled.
|
|| (!_particleSystem.IsAlive() && !_particleSystem.isPlaying) // No particle.
|
||||||
|
|| (_isTrail && !_particleSystem.trails.enabled) // Trail, but it is not enabled.
|
||||||
#if UNITY_2018_3_OR_NEWER
|
#if UNITY_2018_3_OR_NEWER
|
||||||
|| canvasRenderer.GetInheritedAlpha() < 0.01f // #102: Do not bake particle system to mesh when the alpha is zero.
|
|| canvasRenderer.GetInheritedAlpha() <
|
||||||
|
0.01f // #102: Do not bake particle system to mesh when the alpha is zero.
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Profiler.BeginSample("[UIParticleRenderer] Clear Mesh");
|
Profiler.BeginSample("[UIParticleRenderer] Clear Mesh");
|
||||||
workerMesh.Clear();
|
workerMesh.Clear();
|
||||||
canvasRenderer.SetMesh(workerMesh);
|
canvasRenderer.SetMesh(workerMesh);
|
||||||
|
_lastBounds = new Bounds();
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -218,46 +312,86 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
// When the ParticleSystem simulation is complete, stop it.
|
// When the ParticleSystem simulation is complete, stop it.
|
||||||
if (!main.loop && main.duration <= _particleSystem.time && (_particleSystem.IsAlive() || _particleSystem.particleCount == 0))
|
if (!main.loop
|
||||||
|
&& main.duration <= _particleSystem.time
|
||||||
|
&& (_particleSystem.IsAlive() || _particleSystem.particleCount == 0)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
_particleSystem.Stop(false);
|
_particleSystem.Stop(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_prevScale = scale;
|
_prevScale = scale;
|
||||||
_prevPsPos = psPos;
|
_prevPsPos = psPos;
|
||||||
_delay = false;
|
_delay = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
|
|
||||||
// Bake mesh.
|
// Bake mesh.
|
||||||
Profiler.BeginSample("[UIParticleRenderer] Bake Mesh");
|
Profiler.BeginSample("[UIParticleRenderer] Bake Mesh");
|
||||||
if (_isTrail && _parent.canSimulate)
|
s_CombineInstances[0].mesh.Clear(false);
|
||||||
|
|
||||||
|
// Assertion failed on expression: 'ps->array_size()' #278
|
||||||
|
var extends = s_CombineInstances[0].mesh.bounds.extents.x;
|
||||||
|
if (!float.IsNaN(extends) && !float.IsInfinity(extends) && 0 < extends)
|
||||||
{
|
{
|
||||||
|
s_CombineInstances[0].mesh.RecalculateBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_isTrail && _parent.canSimulate && 0 < _particleSystem.particleCount)
|
||||||
|
{
|
||||||
|
#if PS_BAKE_API_V2
|
||||||
|
_renderer.BakeTrailsMesh(s_CombineInstances[0].mesh, bakeCamera,
|
||||||
|
ParticleSystemBakeMeshOptions.BakeRotationAndScale);
|
||||||
|
#else
|
||||||
_renderer.BakeTrailsMesh(s_CombineInstances[0].mesh, bakeCamera, true);
|
_renderer.BakeTrailsMesh(s_CombineInstances[0].mesh, bakeCamera, true);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else if (_renderer.CanBakeMesh())
|
else if (!_isTrail && _renderer.CanBakeMesh())
|
||||||
{
|
{
|
||||||
|
_particleSystem.ValidateShape();
|
||||||
|
#if PS_BAKE_API_V2
|
||||||
|
_renderer.BakeMesh(s_CombineInstances[0].mesh, bakeCamera,
|
||||||
|
ParticleSystemBakeMeshOptions.BakeRotationAndScale);
|
||||||
|
#else
|
||||||
_renderer.BakeMesh(s_CombineInstances[0].mesh, bakeCamera, true);
|
_renderer.BakeMesh(s_CombineInstances[0].mesh, bakeCamera, true);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// Too many vertices to render.
|
||||||
|
if (65535 <= s_CombineInstances[0].mesh.vertexCount)
|
||||||
{
|
{
|
||||||
s_CombineInstances[0].mesh.Clear();
|
Debug.LogErrorFormat(this,
|
||||||
|
"Too many vertices to render. index={0}, isTrail={1}, vertexCount={2}(>=65535)",
|
||||||
|
_index,
|
||||||
|
_isTrail,
|
||||||
|
s_CombineInstances[0].mesh.vertexCount
|
||||||
|
);
|
||||||
|
s_CombineInstances[0].mesh.Clear(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
|
|
||||||
// Combine mesh to transform. ([ParticleSystem local ->] world -> renderer local)
|
// Combine mesh to transform. ([ParticleSystem local ->] world -> renderer local)
|
||||||
Profiler.BeginSample("[UIParticleRenderer] Combine Mesh");
|
Profiler.BeginSample("[UIParticleRenderer] Combine Mesh");
|
||||||
if (_parent.canSimulate)
|
if (_parent.canSimulate)
|
||||||
{
|
{
|
||||||
if (_parent.absoluteMode)
|
if (_parent.positionMode == UIParticle.PositionMode.Absolute)
|
||||||
{
|
{
|
||||||
s_CombineInstances[0].transform = canvasRenderer.transform.worldToLocalMatrix * GetWorldMatrix(psPos, scale);
|
s_CombineInstances[0].transform =
|
||||||
|
canvasRenderer.transform.worldToLocalMatrix
|
||||||
|
* GetWorldMatrix(psPos, scale);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var diff = _particleSystem.transform.position - _parent.transform.position;
|
var diff = _particleSystem.transform.position - _parent.transform.position;
|
||||||
s_CombineInstances[0].transform = canvasRenderer.transform.worldToLocalMatrix * Matrix4x4.Translate(diff.GetScaled(scale - Vector3.one)) * GetWorldMatrix(psPos, scale);
|
s_CombineInstances[0].transform =
|
||||||
|
canvasRenderer.transform.worldToLocalMatrix
|
||||||
|
* Matrix4x4.Translate(diff.GetScaled(scale - Vector3.one))
|
||||||
|
* GetWorldMatrix(psPos, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
workerMesh.CombineMeshes(s_CombineInstances, true, true);
|
workerMesh.CombineMeshes(s_CombineInstances, true, true);
|
||||||
|
|
||||||
workerMesh.RecalculateBounds();
|
workerMesh.RecalculateBounds();
|
||||||
@@ -269,7 +403,38 @@ namespace Coffee.UIExtensions
|
|||||||
extents.z = 0;
|
extents.z = 0;
|
||||||
bounds.extents = extents;
|
bounds.extents = extents;
|
||||||
workerMesh.bounds = bounds;
|
workerMesh.bounds = bounds;
|
||||||
|
_lastBounds = bounds;
|
||||||
|
|
||||||
|
// Convert linear color to gamma color.
|
||||||
|
if (QualitySettings.activeColorSpace == ColorSpace.Linear)
|
||||||
|
{
|
||||||
|
Profiler.BeginSample("[UIParticleRenderer] Convert Linear to Gamma");
|
||||||
|
workerMesh.GetColors(s_Colors);
|
||||||
|
var count_c = s_Colors.Count;
|
||||||
|
for (var i = 0; i < count_c; i++)
|
||||||
|
{
|
||||||
|
var c = s_Colors[i];
|
||||||
|
c.r = c.r.LinearToGamma();
|
||||||
|
c.g = c.g.LinearToGamma();
|
||||||
|
c.b = c.b.LinearToGamma();
|
||||||
|
s_Colors[i] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
workerMesh.SetColors(s_Colors);
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
GetComponents(typeof(IMeshModifier), s_Components);
|
||||||
|
for (var i = 0; i < s_Components.Count; i++)
|
||||||
|
{
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
|
((IMeshModifier)s_Components[i]).ModifyMesh(workerMesh);
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
|
}
|
||||||
|
|
||||||
|
s_Components.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
|
|
||||||
|
|
||||||
@@ -282,29 +447,43 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
// Set mesh to the CanvasRenderer.
|
// Set mesh to the CanvasRenderer.
|
||||||
Profiler.BeginSample("[UIParticleRenderer] Set Mesh");
|
Profiler.BeginSample("[UIParticleRenderer] Set Mesh");
|
||||||
for (int i = 0; i < s_Renderers.Count; i++)
|
for (var i = 0; i < s_Renderers.Count; i++)
|
||||||
{
|
{
|
||||||
if (s_Renderers[i] == this) continue;
|
if (s_Renderers[i] == this) continue;
|
||||||
s_Renderers[i].canvasRenderer.SetMesh(workerMesh);
|
s_Renderers[i].canvasRenderer.SetMesh(workerMesh);
|
||||||
|
s_Renderers[i]._lastBounds = _lastBounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_parent.canRender)
|
if (!_parent.canRender)
|
||||||
{
|
{
|
||||||
workerMesh.Clear();
|
workerMesh.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
canvasRenderer.SetMesh(workerMesh);
|
canvasRenderer.SetMesh(workerMesh);
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
|
|
||||||
// Update animatable material properties.
|
// Update animatable material properties.
|
||||||
Profiler.BeginSample("[UIParticleRenderer] Update Animatable Material Properties");
|
Profiler.BeginSample("[UIParticleRenderer] Update Animatable Material Properties");
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (_modifiedMaterial != material)
|
||||||
|
{
|
||||||
|
_renderer.GetSharedMaterials(s_Materials);
|
||||||
|
material = s_Materials[_isTrail ? 1 : 0];
|
||||||
|
s_Materials.Clear();
|
||||||
|
SetMaterialDirty();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
UpdateMaterialProperties();
|
UpdateMaterialProperties();
|
||||||
if (!_parent.useMeshSharing)
|
if (_parent.useMeshSharing)
|
||||||
{
|
{
|
||||||
if (!_currentMaterialForRendering)
|
if (!_currentMaterialForRendering)
|
||||||
{
|
{
|
||||||
_currentMaterialForRendering = materialForRendering;
|
_currentMaterialForRendering = materialForRendering;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < s_Renderers.Count; i++)
|
|
||||||
|
for (var i = 0; i < s_Renderers.Count; i++)
|
||||||
{
|
{
|
||||||
if (s_Renderers[i] == this) continue;
|
if (s_Renderers[i] == this) continue;
|
||||||
|
|
||||||
@@ -312,41 +491,12 @@ namespace Coffee.UIExtensions
|
|||||||
s_Renderers[i].canvasRenderer.SetMaterial(_currentMaterialForRendering, 0);
|
s_Renderers[i].canvasRenderer.SetMaterial(_currentMaterialForRendering, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
|
|
||||||
s_Renderers.Clear();
|
s_Renderers.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void UpdateParticleCount()
|
|
||||||
{
|
|
||||||
if (!_particleSystem) return;
|
|
||||||
_prevParticleCount = _particleSystem.particleCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnEnable()
|
|
||||||
{
|
|
||||||
base.OnEnable();
|
|
||||||
|
|
||||||
if (!s_CombineInstances[0].mesh)
|
|
||||||
{
|
|
||||||
s_CombineInstances[0].mesh = new Mesh()
|
|
||||||
{
|
|
||||||
name = "[UIParticleRenderer] Combine Instance Mesh",
|
|
||||||
hideFlags = HideFlags.HideAndDontSave,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
_currentMaterialForRendering = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnDisable()
|
|
||||||
{
|
|
||||||
base.OnDisable();
|
|
||||||
|
|
||||||
ModifiedMaterial.Remove(_modifiedMaterial);
|
|
||||||
_modifiedMaterial = null;
|
|
||||||
_currentMaterialForRendering = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Call to update the geometry of the Graphic onto the CanvasRenderer.
|
/// Call to update the geometry of the Graphic onto the CanvasRenderer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -354,19 +504,31 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Cull(Rect clipRect, bool validRect)
|
||||||
|
{
|
||||||
|
var cull = _lastBounds.extents == Vector3.zero
|
||||||
|
|| !validRect
|
||||||
|
|| !clipRect.Overlaps(rootCanvasRect, true);
|
||||||
|
if (canvasRenderer.cull == cull) return;
|
||||||
|
|
||||||
|
canvasRenderer.cull = cull;
|
||||||
|
UISystemProfilerApi.AddMarker("MaskableGraphic.cullingChanged", this);
|
||||||
|
onCullStateChanged.Invoke(cull);
|
||||||
|
OnCullingChanged();
|
||||||
|
}
|
||||||
|
|
||||||
private Vector3 GetWorldScale()
|
private Vector3 GetWorldScale()
|
||||||
{
|
{
|
||||||
Profiler.BeginSample("[UIParticleRenderer] GetWorldScale");
|
Profiler.BeginSample("[UIParticleRenderer] GetWorldScale");
|
||||||
var scale = _parent.scale3D;
|
var scale = _parent.scale3DForCalc.GetScaled(_parent.parentScale);
|
||||||
//if (_parent.uiScaling)
|
|
||||||
|
if (_parent.autoScalingMode == UIParticle.AutoScalingMode.UIParticle
|
||||||
|
&& _particleSystem.main.scalingMode == ParticleSystemScalingMode.Local
|
||||||
|
&& _parent.canvas)
|
||||||
{
|
{
|
||||||
scale.Scale(_parent.transform.localScale.Inverse());
|
scale = scale.GetScaled(_parent.canvas.rootCanvas.transform.localScale);
|
||||||
}
|
}
|
||||||
//else if (_parent.scalingMode == UIParticle.ScalingMode.UI && _particleSystem.main.scalingMode != ParticleSystemScalingMode.Hierarchy)
|
|
||||||
//{
|
|
||||||
// var gscale = _parent.transform.lossyScale.GetScaled(canvas.transform.lossyScale.Inverse());
|
|
||||||
// scale.Scale(gscale * canvas.scaleFactor);
|
|
||||||
//}
|
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
return scale;
|
return scale;
|
||||||
}
|
}
|
||||||
@@ -386,8 +548,8 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
case ParticleSystemSimulationSpace.World:
|
case ParticleSystemSimulationSpace.World:
|
||||||
return Matrix4x4.Translate(psPos)
|
return Matrix4x4.Translate(psPos)
|
||||||
* Matrix4x4.Scale(scale)
|
* Matrix4x4.Scale(scale)
|
||||||
* Matrix4x4.Translate(-psPos);
|
* Matrix4x4.Translate(-psPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -396,17 +558,17 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
case ParticleSystemSimulationSpace.Local:
|
case ParticleSystemSimulationSpace.Local:
|
||||||
return Matrix4x4.Translate(psPos)
|
return Matrix4x4.Translate(psPos)
|
||||||
* Matrix4x4.Scale(scale);
|
* Matrix4x4.Scale(scale);
|
||||||
case ParticleSystemSimulationSpace.World:
|
case ParticleSystemSimulationSpace.World:
|
||||||
return Matrix4x4.Scale(scale);
|
return Matrix4x4.Scale(scale);
|
||||||
case ParticleSystemSimulationSpace.Custom:
|
case ParticleSystemSimulationSpace.Custom:
|
||||||
return Matrix4x4.Translate(_particleSystem.main.customSimulationSpace.position.GetScaled(scale))
|
return Matrix4x4.Translate(_particleSystem.main.customSimulationSpace.position.GetScaled(scale))
|
||||||
//* Matrix4x4.Translate(wpos)
|
//* Matrix4x4.Translate(wpos)
|
||||||
* Matrix4x4.Scale(scale)
|
* Matrix4x4.Scale(scale)
|
||||||
//* Matrix4x4.Translate(-wpos)
|
//* Matrix4x4.Translate(-wpos)
|
||||||
;
|
;
|
||||||
default:
|
default:
|
||||||
throw new System.NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,8 +580,10 @@ namespace Coffee.UIExtensions
|
|||||||
private void ResolveResolutionChange(Vector3 psPos, Vector3 scale)
|
private void ResolveResolutionChange(Vector3 psPos, Vector3 scale)
|
||||||
{
|
{
|
||||||
var screenSize = new Vector2Int(Screen.width, Screen.height);
|
var screenSize = new Vector2Int(Screen.width, Screen.height);
|
||||||
//if ((_prevScreenSize != screenSize || _prevScale != scale) && _particleSystem.main.simulationSpace == ParticleSystemSimulationSpace.World && _parent.uiScaling)
|
var isWorldSpace = _particleSystem.IsWorldSpace();
|
||||||
if ((_prevScreenSize != screenSize || _prevScale != scale) && _particleSystem.main.simulationSpace == ParticleSystemSimulationSpace.World)
|
var canvasScale = _parent.canvas ? _parent.canvas.scaleFactor : 1f;
|
||||||
|
var resolutionChanged = _prevScreenSize != screenSize || _prevCanvasScale != canvasScale;
|
||||||
|
if (resolutionChanged && isWorldSpace && _isPrevStored)
|
||||||
{
|
{
|
||||||
// Update particle array size and get particles.
|
// Update particle array size and get particles.
|
||||||
var size = _particleSystem.particleCount;
|
var size = _particleSystem.particleCount;
|
||||||
@@ -428,20 +592,27 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
// Resolusion resolver:
|
// Resolusion resolver:
|
||||||
// (psPos / scale) / (prevPsPos / prevScale) -> psPos * scale.inv * prevPsPos.inv * prevScale
|
// (psPos / scale) / (prevPsPos / prevScale) -> psPos * scale.inv * prevPsPos.inv * prevScale
|
||||||
var modifier = psPos.GetScaled(scale.Inverse(), _prevPsPos.Inverse(), _prevScale);
|
var modifier = psPos.GetScaled(
|
||||||
|
scale.Inverse(),
|
||||||
|
_prevPsPos.Inverse(),
|
||||||
|
_prevScale);
|
||||||
for (var i = 0; i < size; i++)
|
for (var i = 0; i < size; i++)
|
||||||
{
|
{
|
||||||
var particle = particles[i];
|
var particle = particles[i];
|
||||||
particle.position = particle.position.GetScaled(modifier);
|
particle.position = particle.position.GetScaled(modifier);
|
||||||
particles[i] = particle;
|
particles[i] = particle;
|
||||||
}
|
}
|
||||||
|
|
||||||
_particleSystem.SetParticles(particles, size);
|
_particleSystem.SetParticles(particles, size);
|
||||||
|
|
||||||
// Delay: Do not progress in the frame where the resolution has been changed.
|
// Delay: Do not progress in the frame where the resolution has been changed.
|
||||||
_delay = true;
|
_delay = true;
|
||||||
_prevScale = scale;
|
_prevScale = scale;
|
||||||
_prevPsPos = psPos;
|
_prevPsPos = psPos;
|
||||||
|
_isPrevStored = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_prevCanvasScale = canvas ? canvas.scaleFactor : 1f;
|
||||||
_prevScreenSize = screenSize;
|
_prevScreenSize = screenSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,56 +625,50 @@ namespace Coffee.UIExtensions
|
|||||||
? Time.unscaledDeltaTime
|
? Time.unscaledDeltaTime
|
||||||
: Time.deltaTime;
|
: Time.deltaTime;
|
||||||
|
|
||||||
// Prewarm:
|
// Prewarm:
|
||||||
if (0 < deltaTime && _prewarm)
|
if (0 < deltaTime && _prewarm)
|
||||||
{
|
{
|
||||||
deltaTime += main.duration;
|
deltaTime += main.duration;
|
||||||
_prewarm = false;
|
_prewarm = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emitted particles found.
|
|
||||||
if (_prevParticleCount != _particleSystem.particleCount)
|
|
||||||
{
|
|
||||||
var size = _particleSystem.particleCount;
|
|
||||||
var particles = ParticleSystemExtensions.GetParticleArray(size);
|
|
||||||
_particleSystem.GetParticles(particles, size);
|
|
||||||
for (var i = _prevParticleCount; i < size; i++)
|
|
||||||
{
|
|
||||||
var p = particles[i];
|
|
||||||
p.position = p.position.GetScaled(scale.Inverse());
|
|
||||||
particles[i] = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
_particleSystem.SetParticles(particles, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get world position.
|
// get world position.
|
||||||
|
var isLocalSpace = _particleSystem.IsLocalSpace();
|
||||||
var psTransform = _particleSystem.transform;
|
var psTransform = _particleSystem.transform;
|
||||||
|
var originLocalPosition = psTransform.localPosition;
|
||||||
|
var originLocalRotation = psTransform.localRotation;
|
||||||
var originWorldPosition = psTransform.position;
|
var originWorldPosition = psTransform.position;
|
||||||
var originWorldRotation = psTransform.rotation;
|
var originWorldRotation = psTransform.rotation;
|
||||||
|
|
||||||
var emission = _particleSystem.emission;
|
var emission = _particleSystem.emission;
|
||||||
var rateOverDistance = emission.enabled && 0 < emission.rateOverDistance.constant && 0 < emission.rateOverDistanceMultiplier;
|
var rateOverDistance = emission.enabled
|
||||||
if (rateOverDistance)
|
&& 0 < emission.rateOverDistance.constant
|
||||||
|
&& 0 < emission.rateOverDistanceMultiplier;
|
||||||
|
if (rateOverDistance && !paused && _isPrevStored)
|
||||||
{
|
{
|
||||||
// (For rate-over-distance emission,) Move to previous scaled position, simulate (delta = 0).
|
// (For rate-over-distance emission,) Move to previous scaled position, simulate (delta = 0).
|
||||||
Vector3 prevScaledPos = _prevPsPos.GetScaled(_prevScale.Inverse());
|
var prevScaledPos = isLocalSpace
|
||||||
|
? _prevPsPos
|
||||||
|
: _prevPsPos.GetScaled(_prevScale.Inverse());
|
||||||
psTransform.SetPositionAndRotation(prevScaledPos, originWorldRotation);
|
psTransform.SetPositionAndRotation(prevScaledPos, originWorldRotation);
|
||||||
_particleSystem.Simulate(0, false, false, false);
|
_particleSystem.Simulate(0, false, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move to scaled position, simulate, revert to origin position.
|
// Move to scaled position, simulate, revert to origin position.
|
||||||
var scaledPos = originWorldPosition.GetScaled(scale.Inverse());
|
var scaledPos = isLocalSpace
|
||||||
|
? originWorldPosition
|
||||||
|
: originWorldPosition.GetScaled(scale.Inverse());
|
||||||
psTransform.SetPositionAndRotation(scaledPos, originWorldRotation);
|
psTransform.SetPositionAndRotation(scaledPos, originWorldRotation);
|
||||||
_particleSystem.Simulate(deltaTime, false, false, false);
|
_particleSystem.Simulate(deltaTime, false, false, false);
|
||||||
psTransform.SetPositionAndRotation(originWorldPosition, originWorldRotation);
|
psTransform.localPosition = originLocalPosition;
|
||||||
|
psTransform.localRotation = originLocalRotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
private void SimulateForEditor(Vector3 diffPos, Vector3 scale)
|
private void SimulateForEditor(Vector3 diffPos, Vector3 scale)
|
||||||
{
|
{
|
||||||
// Extra world simulation.
|
// Extra world simulation.
|
||||||
if (_particleSystem.main.simulationSpace == ParticleSystemSimulationSpace.World && 0 < Vector3.SqrMagnitude(diffPos))
|
var isWorldSpace = _particleSystem.IsWorldSpace();
|
||||||
|
if (isWorldSpace && 0 < Vector3.SqrMagnitude(diffPos))
|
||||||
{
|
{
|
||||||
Profiler.BeginSample("[UIParticle] Bake Mesh > Extra world simulation");
|
Profiler.BeginSample("[UIParticle] Bake Mesh > Extra world simulation");
|
||||||
diffPos.x *= 1f - 1f / Mathf.Max(0.001f, scale.x);
|
diffPos.x *= 1f - 1f / Mathf.Max(0.001f, scale.x);
|
||||||
@@ -531,7 +696,9 @@ namespace Coffee.UIExtensions
|
|||||||
if (_parent.m_AnimatableProperties.Length == 0) return;
|
if (_parent.m_AnimatableProperties.Length == 0) return;
|
||||||
|
|
||||||
if (s_Mpb == null)
|
if (s_Mpb == null)
|
||||||
|
{
|
||||||
s_Mpb = new MaterialPropertyBlock();
|
s_Mpb = new MaterialPropertyBlock();
|
||||||
|
}
|
||||||
|
|
||||||
_renderer.GetPropertyBlock(s_Mpb);
|
_renderer.GetPropertyBlock(s_Mpb);
|
||||||
if (s_Mpb.isEmpty) return;
|
if (s_Mpb.isEmpty) return;
|
||||||
@@ -539,12 +706,13 @@ namespace Coffee.UIExtensions
|
|||||||
// #41: Copy the value from MaterialPropertyBlock to CanvasRenderer
|
// #41: Copy the value from MaterialPropertyBlock to CanvasRenderer
|
||||||
if (!_modifiedMaterial) return;
|
if (!_modifiedMaterial) return;
|
||||||
|
|
||||||
foreach (var ap in _parent.m_AnimatableProperties)
|
for (var i = 0; i < _parent.m_AnimatableProperties.Length; i++)
|
||||||
{
|
{
|
||||||
|
var ap = _parent.m_AnimatableProperties[i];
|
||||||
ap.UpdateMaterialProperties(_modifiedMaterial, s_Mpb);
|
ap.UpdateMaterialProperties(_modifiedMaterial, s_Mpb);
|
||||||
}
|
}
|
||||||
|
|
||||||
s_Mpb.Clear();
|
s_Mpb.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,22 +1,17 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Coffee.UIExtensions
|
namespace Coffee.UIExtensions
|
||||||
{
|
{
|
||||||
internal static class UIParticleUpdater
|
internal static class UIParticleUpdater
|
||||||
{
|
{
|
||||||
static readonly List<UIParticle> s_ActiveParticles = new List<UIParticle>();
|
private static readonly List<UIParticle> s_ActiveParticles = new List<UIParticle>();
|
||||||
static readonly List<UIParticleAttractor> s_ActiveAttractors = new List<UIParticleAttractor>();
|
private static readonly List<UIParticleAttractor> s_ActiveAttractors = new List<UIParticleAttractor>();
|
||||||
static readonly HashSet<int> s_UpdatedGroupIds = new HashSet<int>();
|
private static readonly HashSet<int> s_UpdatedGroupIds = new HashSet<int>();
|
||||||
private static int frameCount = 0;
|
private static int s_FrameCount;
|
||||||
|
|
||||||
public static int uiParticleCount
|
public static int uiParticleCount => s_ActiveParticles.Count;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return s_ActiveParticles.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Register(UIParticle particle)
|
public static void Register(UIParticle particle)
|
||||||
{
|
{
|
||||||
@@ -43,7 +38,7 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
[UnityEditor.InitializeOnLoadMethod]
|
[InitializeOnLoadMethod]
|
||||||
#endif
|
#endif
|
||||||
[RuntimeInitializeOnLoadMethod]
|
[RuntimeInitializeOnLoadMethod]
|
||||||
private static void InitializeOnLoad()
|
private static void InitializeOnLoad()
|
||||||
@@ -55,16 +50,15 @@ namespace Coffee.UIExtensions
|
|||||||
private static void Refresh()
|
private static void Refresh()
|
||||||
{
|
{
|
||||||
// Do not allow it to be called in the same frame.
|
// Do not allow it to be called in the same frame.
|
||||||
if (frameCount == Time.frameCount) return;
|
if (s_FrameCount == Time.frameCount) return;
|
||||||
frameCount = Time.frameCount;
|
s_FrameCount = Time.frameCount;
|
||||||
|
|
||||||
// Simulate -> Primary
|
// Simulate -> Primary
|
||||||
for (var i = 0; i < s_ActiveParticles.Count; i++)
|
for (var i = 0; i < s_ActiveParticles.Count; i++)
|
||||||
{
|
{
|
||||||
var uip = s_ActiveParticles[i];
|
var uip = s_ActiveParticles[i];
|
||||||
if (!uip || !uip.canvas || !uip.isPrimary || s_UpdatedGroupIds.Contains(uip.groupId)) continue;
|
if (!uip || !uip.canvas || !uip.isPrimary || !s_UpdatedGroupIds.Add(uip.groupId)) continue;
|
||||||
|
|
||||||
s_UpdatedGroupIds.Add(uip.groupId);
|
|
||||||
uip.UpdateTransformScale();
|
uip.UpdateTransformScale();
|
||||||
uip.UpdateRenderers();
|
uip.UpdateRenderers();
|
||||||
}
|
}
|
||||||
@@ -81,9 +75,8 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
uip.UpdateRenderers();
|
uip.UpdateRenderers();
|
||||||
}
|
}
|
||||||
else if (!s_UpdatedGroupIds.Contains(uip.groupId))
|
else if (s_UpdatedGroupIds.Add(uip.groupId))
|
||||||
{
|
{
|
||||||
s_UpdatedGroupIds.Add(uip.groupId);
|
|
||||||
uip.UpdateRenderers();
|
uip.UpdateRenderers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,15 +88,6 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
s_ActiveAttractors[i].Attract();
|
s_ActiveAttractors[i].Attract();
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateParticleCount.
|
|
||||||
for (var i = 0; i < s_ActiveParticles.Count; i++)
|
|
||||||
{
|
|
||||||
var uip = s_ActiveParticles[i];
|
|
||||||
if (!uip || !uip.canvas) continue;
|
|
||||||
|
|
||||||
uip.UpdateParticleCount();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void GetGroupedRenderers(int groupId, int index, List<UIParticleRenderer> results)
|
public static void GetGroupedRenderers(int groupId, int index, List<UIParticleRenderer> results)
|
||||||
@@ -129,6 +113,7 @@ namespace Coffee.UIExtensions
|
|||||||
if (uip.isPrimary) return uip;
|
if (uip.isPrimary) return uip;
|
||||||
if (!primary && uip.canSimulate) primary = uip;
|
if (!primary && uip.canSimulate) primary = uip;
|
||||||
}
|
}
|
||||||
|
|
||||||
return primary;
|
return primary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -6,6 +6,25 @@ using Object = UnityEngine.Object;
|
|||||||
|
|
||||||
namespace Coffee.UIParticleExtensions
|
namespace Coffee.UIParticleExtensions
|
||||||
{
|
{
|
||||||
|
public static class Color32Extensions
|
||||||
|
{
|
||||||
|
private static byte[] s_LinearToGammaLut;
|
||||||
|
|
||||||
|
public static byte LinearToGamma(this byte self)
|
||||||
|
{
|
||||||
|
if (s_LinearToGammaLut == null)
|
||||||
|
{
|
||||||
|
s_LinearToGammaLut = new byte[256];
|
||||||
|
for (var i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
s_LinearToGammaLut[i] = (byte)(Mathf.LinearToGammaSpace(i / 255f) * 255f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_LinearToGammaLut[self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class Vector3Extensions
|
public static class Vector3Extensions
|
||||||
{
|
{
|
||||||
public static Vector3 Inverse(this Vector3 self)
|
public static Vector3 Inverse(this Vector3 self)
|
||||||
@@ -46,11 +65,11 @@ namespace Coffee.UIParticleExtensions
|
|||||||
internal static class SpriteExtensions
|
internal static class SpriteExtensions
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
private static Type tSpriteEditorExtension =
|
private static readonly Type s_SpriteEditorExtensionType =
|
||||||
Type.GetType("UnityEditor.Experimental.U2D.SpriteEditorExtension, UnityEditor")
|
Type.GetType("UnityEditor.Experimental.U2D.SpriteEditorExtension, UnityEditor")
|
||||||
?? Type.GetType("UnityEditor.U2D.SpriteEditorExtension, UnityEditor");
|
?? Type.GetType("UnityEditor.U2D.SpriteEditorExtension, UnityEditor");
|
||||||
|
|
||||||
private static MethodInfo miGetActiveAtlasTexture = tSpriteEditorExtension
|
private static readonly MethodInfo s_GetActiveAtlasTextureMethodInfo = s_SpriteEditorExtensionType
|
||||||
.GetMethod("GetActiveAtlasTexture", BindingFlags.Static | BindingFlags.NonPublic);
|
.GetMethod("GetActiveAtlasTexture", BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
|
||||||
public static Texture2D GetActualTexture(this Sprite self)
|
public static Texture2D GetActualTexture(this Sprite self)
|
||||||
@@ -58,8 +77,10 @@ namespace Coffee.UIParticleExtensions
|
|||||||
if (!self) return null;
|
if (!self) return null;
|
||||||
|
|
||||||
if (Application.isPlaying) return self.texture;
|
if (Application.isPlaying) return self.texture;
|
||||||
var ret = miGetActiveAtlasTexture.Invoke(null, new[] { self }) as Texture2D;
|
var ret = s_GetActiveAtlasTextureMethodInfo.Invoke(null, new object[] { self }) as Texture2D;
|
||||||
return ret ? ret : self.texture;
|
return ret
|
||||||
|
? ret
|
||||||
|
: self.texture;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
internal static Texture2D GetActualTexture(this Sprite self)
|
internal static Texture2D GetActualTexture(this Sprite self)
|
||||||
@@ -77,15 +98,40 @@ namespace Coffee.UIParticleExtensions
|
|||||||
{
|
{
|
||||||
if (s_TmpParticles.Length < size)
|
if (s_TmpParticles.Length < size)
|
||||||
{
|
{
|
||||||
while(s_TmpParticles.Length < size)
|
while (s_TmpParticles.Length < size)
|
||||||
{
|
{
|
||||||
size = Mathf.NextPowerOfTwo(size);
|
size = Mathf.NextPowerOfTwo(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
s_TmpParticles = new ParticleSystem.Particle[size];
|
s_TmpParticles = new ParticleSystem.Particle[size];
|
||||||
}
|
}
|
||||||
|
|
||||||
return s_TmpParticles;
|
return s_TmpParticles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ValidateShape(this ParticleSystem self)
|
||||||
|
{
|
||||||
|
var shape = self.shape;
|
||||||
|
if (shape.enabled && shape.alignToDirection)
|
||||||
|
{
|
||||||
|
if (Mathf.Approximately(shape.scale.x * shape.scale.y * shape.scale.z, 0))
|
||||||
|
{
|
||||||
|
if (Mathf.Approximately(shape.scale.x, 0))
|
||||||
|
{
|
||||||
|
shape.scale.Set(0.0001f, shape.scale.y, shape.scale.z);
|
||||||
|
}
|
||||||
|
else if (Mathf.Approximately(shape.scale.y, 0))
|
||||||
|
{
|
||||||
|
shape.scale.Set(shape.scale.x, 0.0001f, shape.scale.z);
|
||||||
|
}
|
||||||
|
else if (Mathf.Approximately(shape.scale.z, 0))
|
||||||
|
{
|
||||||
|
shape.scale.Set(shape.scale.x, shape.scale.y, 0.0001f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static bool CanBakeMesh(this ParticleSystemRenderer self)
|
public static bool CanBakeMesh(this ParticleSystemRenderer self)
|
||||||
{
|
{
|
||||||
// #69: Editor crashes when mesh is set to null when `ParticleSystem.RenderMode = Mesh`
|
// #69: Editor crashes when mesh is set to null when `ParticleSystem.RenderMode = Mesh`
|
||||||
@@ -102,47 +148,69 @@ namespace Coffee.UIParticleExtensions
|
|||||||
var main = self.main;
|
var main = self.main;
|
||||||
var space = main.simulationSpace;
|
var space = main.simulationSpace;
|
||||||
if (space == ParticleSystemSimulationSpace.Custom && !main.customSimulationSpace)
|
if (space == ParticleSystemSimulationSpace.Custom && !main.customSimulationSpace)
|
||||||
|
{
|
||||||
space = ParticleSystemSimulationSpace.Local;
|
space = ParticleSystemSimulationSpace.Local;
|
||||||
|
}
|
||||||
|
|
||||||
return space;
|
return space;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsLocalSpace(this ParticleSystem self)
|
||||||
|
{
|
||||||
|
return GetActualSimulationSpace(self) == ParticleSystemSimulationSpace.Local;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsWorldSpace(this ParticleSystem self)
|
||||||
|
{
|
||||||
|
return GetActualSimulationSpace(self) == ParticleSystemSimulationSpace.World;
|
||||||
|
}
|
||||||
|
|
||||||
public static void SortForRendering(this List<ParticleSystem> self, Transform transform, bool sortByMaterial)
|
public static void SortForRendering(this List<ParticleSystem> self, Transform transform, bool sortByMaterial)
|
||||||
{
|
{
|
||||||
self.Sort((a, b) =>
|
self.Sort((a, b) =>
|
||||||
{
|
{
|
||||||
var tr = transform;
|
|
||||||
var aRenderer = a.GetComponent<ParticleSystemRenderer>();
|
var aRenderer = a.GetComponent<ParticleSystemRenderer>();
|
||||||
var bRenderer = b.GetComponent<ParticleSystemRenderer>();
|
var bRenderer = b.GetComponent<ParticleSystemRenderer>();
|
||||||
|
|
||||||
// Render queue: ascending
|
// Render queue: ascending
|
||||||
var aMat = aRenderer.sharedMaterial ?? aRenderer.trailMaterial;
|
var aMat = aRenderer.sharedMaterial ? aRenderer.sharedMaterial : aRenderer.trailMaterial;
|
||||||
var bMat = bRenderer.sharedMaterial ?? bRenderer.trailMaterial;
|
var bMat = bRenderer.sharedMaterial ? bRenderer.sharedMaterial : bRenderer.trailMaterial;
|
||||||
if (!aMat && !bMat) return 0;
|
if (!aMat && !bMat) return 0;
|
||||||
if (!aMat) return -1;
|
if (!aMat) return -1;
|
||||||
if (!bMat) return 1;
|
if (!bMat) return 1;
|
||||||
|
|
||||||
if (sortByMaterial)
|
if (sortByMaterial)
|
||||||
|
{
|
||||||
return aMat.GetInstanceID() - bMat.GetInstanceID();
|
return aMat.GetInstanceID() - bMat.GetInstanceID();
|
||||||
|
}
|
||||||
|
|
||||||
if (aMat.renderQueue != bMat.renderQueue)
|
if (aMat.renderQueue != bMat.renderQueue)
|
||||||
|
{
|
||||||
return aMat.renderQueue - bMat.renderQueue;
|
return aMat.renderQueue - bMat.renderQueue;
|
||||||
|
}
|
||||||
|
|
||||||
// Sorting layer: ascending
|
// Sorting layer: ascending
|
||||||
if (aRenderer.sortingLayerID != bRenderer.sortingLayerID)
|
if (aRenderer.sortingLayerID != bRenderer.sortingLayerID)
|
||||||
return SortingLayer.GetLayerValueFromID(aRenderer.sortingLayerID) - SortingLayer.GetLayerValueFromID(bRenderer.sortingLayerID);
|
{
|
||||||
|
return SortingLayer.GetLayerValueFromID(aRenderer.sortingLayerID) -
|
||||||
|
SortingLayer.GetLayerValueFromID(bRenderer.sortingLayerID);
|
||||||
|
}
|
||||||
|
|
||||||
// Sorting order: ascending
|
// Sorting order: ascending
|
||||||
if (aRenderer.sortingOrder != bRenderer.sortingOrder)
|
if (aRenderer.sortingOrder != bRenderer.sortingOrder)
|
||||||
|
{
|
||||||
return aRenderer.sortingOrder - bRenderer.sortingOrder;
|
return aRenderer.sortingOrder - bRenderer.sortingOrder;
|
||||||
|
}
|
||||||
|
|
||||||
// Z position & sortingFudge: descending
|
// Z position & sortingFudge: descending
|
||||||
var aTransform = a.transform;
|
var aTransform = a.transform;
|
||||||
var bTransform = b.transform;
|
var bTransform = b.transform;
|
||||||
var aPos = tr.InverseTransformPoint(aTransform.position).z + aRenderer.sortingFudge;
|
var aPos = transform.InverseTransformPoint(aTransform.position).z + aRenderer.sortingFudge;
|
||||||
var bPos = tr.InverseTransformPoint(bTransform.position).z + bRenderer.sortingFudge;
|
var bPos = transform.InverseTransformPoint(bTransform.position).z + bRenderer.sortingFudge;
|
||||||
if (!Mathf.Approximately(aPos, bPos))
|
if (!Mathf.Approximately(aPos, bPos))
|
||||||
|
{
|
||||||
return (int)Mathf.Sign(bPos - aPos);
|
return (int)Mathf.Sign(bPos - aPos);
|
||||||
|
}
|
||||||
|
|
||||||
return (int)Mathf.Sign(GetIndex(self, a) - GetIndex(self, b));
|
return (int)Mathf.Sign(GetIndex(self, a) - GetIndex(self, b));
|
||||||
});
|
});
|
||||||
@@ -152,7 +220,10 @@ namespace Coffee.UIParticleExtensions
|
|||||||
{
|
{
|
||||||
for (var i = 0; i < list.Count; i++)
|
for (var i = 0; i < list.Count; i++)
|
||||||
{
|
{
|
||||||
if (list[i].GetInstanceID() == ps.GetInstanceID()) return i;
|
if (list[i].GetInstanceID() == ps.GetInstanceID())
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -183,4 +254,55 @@ namespace Coffee.UIParticleExtensions
|
|||||||
self.ForEach(action);
|
self.ForEach(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static class Misc
|
||||||
|
{
|
||||||
|
public static void Destroy(Object obj)
|
||||||
|
{
|
||||||
|
if (!obj) return;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (!Application.isPlaying)
|
||||||
|
{
|
||||||
|
Object.DestroyImmediate(obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
Object.Destroy(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DestroyImmediate(Object obj)
|
||||||
|
{
|
||||||
|
if (!obj) return;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (Application.isEditor)
|
||||||
|
{
|
||||||
|
Object.DestroyImmediate(obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
Object.Destroy(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !UNITY_2021_2_OR_NEWER && !UNITY_2020_3_45 && !UNITY_2020_3_46 && !UNITY_2020_3_47 && !UNITY_2020_3_48
|
||||||
|
public static T GetComponentInParent<T>(this Component self, bool includeInactive) where T : Component
|
||||||
|
{
|
||||||
|
if (!self) return null;
|
||||||
|
if (!includeInactive) return self.GetComponentInParent<T>();
|
||||||
|
|
||||||
|
var current = self.transform;
|
||||||
|
while (current)
|
||||||
|
{
|
||||||
|
var component = current.GetComponent<T>();
|
||||||
|
if (component) return component;
|
||||||
|
current = current.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 15e5409f0334e479e91e672ae14567d3
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 064daa6b97d6846ec9334e98d642f081
|
|
||||||
DefaultImporter:
|
|
||||||
userData:
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Coffee.CFX_Demo_With_UIParticle",
|
|
||||||
"references": [
|
|
||||||
"Coffee.UIParticle"
|
|
||||||
],
|
|
||||||
"optionalUnityReferences": [],
|
|
||||||
"includePlatforms": [],
|
|
||||||
"excludePlatforms": [],
|
|
||||||
"allowUnsafeCode": false,
|
|
||||||
"overrideReferences": false,
|
|
||||||
"precompiledReferences": [],
|
|
||||||
"autoReferenced": true,
|
|
||||||
"defineConstraints": []
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 67b89587ad4f645e18aa12053a6cc9b7
|
|
||||||
AssemblyDefinitionImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using Coffee.UIExtensions;
|
|
||||||
using UnityEditor;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.SceneManagement;
|
|
||||||
using UnityEngine.UI;
|
|
||||||
using Object = UnityEngine.Object;
|
|
||||||
|
|
||||||
public class CFX_Demo_With_UIParticle : MonoBehaviour
|
|
||||||
{
|
|
||||||
private UIParticle UiParticle;
|
|
||||||
private Toggle spawnOnUI;
|
|
||||||
private MonoBehaviour demo;
|
|
||||||
|
|
||||||
// Start is called before the first frame update
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
UiParticle = GetComponentInChildren<UIParticle>();
|
|
||||||
spawnOnUI = GetComponentInChildren<Toggle>();
|
|
||||||
|
|
||||||
demo = FindObjectOfType("CFX_Demo_New") as MonoBehaviour
|
|
||||||
?? FindObjectOfType("WFX_Demo_New") as MonoBehaviour;
|
|
||||||
|
|
||||||
SetCanvasWidth(800);
|
|
||||||
SetCanvasRenderOverlay(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object FindObjectOfType(string typeName)
|
|
||||||
{
|
|
||||||
var type = AppDomain.CurrentDomain.GetAssemblies()
|
|
||||||
.SelectMany(x => x.GetTypes())
|
|
||||||
.FirstOrDefault(x => x.Name == typeName);
|
|
||||||
|
|
||||||
return type == null ? null : FindObjectOfType(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update is called once per frame
|
|
||||||
private void Update()
|
|
||||||
{
|
|
||||||
if (!spawnOnUI.isOn || !demo || !Input.GetMouseButtonDown(0)) return;
|
|
||||||
|
|
||||||
foreach (Transform child in UiParticle.transform)
|
|
||||||
{
|
|
||||||
Destroy(child.gameObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
var particle = demo.GetType()
|
|
||||||
.GetMethod("spawnParticle", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
|
|
||||||
.Invoke(demo, new object[0]) as GameObject;
|
|
||||||
particle.transform.localScale = Vector3.one;
|
|
||||||
UiParticle.SetParticleSystemInstance(particle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetCanvasWidth(int width)
|
|
||||||
{
|
|
||||||
var scaler = GetComponentInParent<CanvasScaler>();
|
|
||||||
scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
|
|
||||||
scaler.matchWidthOrHeight = 0;
|
|
||||||
var resolution = scaler.referenceResolution;
|
|
||||||
resolution.x = width;
|
|
||||||
scaler.referenceResolution = resolution;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetCanvasRenderOverlay(bool enable)
|
|
||||||
{
|
|
||||||
var canvas = GetComponentInParent<Canvas>();
|
|
||||||
if (enable)
|
|
||||||
{
|
|
||||||
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
canvas.worldCamera = Camera.main;
|
|
||||||
canvas.renderMode = RenderMode.ScreenSpaceCamera;
|
|
||||||
canvas.planeDistance = 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadScene(string scene)
|
|
||||||
{
|
|
||||||
SceneManager.LoadScene(scene);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: a845100b226da488ab9037ad254b5860
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 3432d66abba624d4fad1150154199656
|
|
||||||
PrefabImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
Cartoon FX & War FX Demo
|
|
||||||
===
|
|
||||||
|
|
||||||
Please import assets "Cartoon FX Free" and/or "War FX Free" from Unity asset store.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 8f3407e8e4c3c4cf0a8717c25bc1c790
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: a81f9cd434f104e1fad7ffa20eb7a3d4
|
|
||||||
DefaultImporter:
|
|
||||||
userData:
|
|
||||||
@@ -1,25 +1,31 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.Serialization;
|
||||||
|
|
||||||
namespace Coffee.UIExtensions.Demo
|
namespace Coffee.UIExtensions.Demo
|
||||||
{
|
{
|
||||||
public class CopyItemOnStart : MonoBehaviour
|
public class CopyItemOnStart : MonoBehaviour
|
||||||
{
|
{
|
||||||
public GameObject origin;
|
[FormerlySerializedAs("origin")]
|
||||||
public int count;
|
[SerializeField]
|
||||||
|
private GameObject m_Origin;
|
||||||
|
|
||||||
|
[FormerlySerializedAs("count")]
|
||||||
|
[SerializeField]
|
||||||
|
private int m_Count;
|
||||||
|
|
||||||
private void Start()
|
private void Start()
|
||||||
{
|
{
|
||||||
if (!origin) return;
|
if (!m_Origin) return;
|
||||||
origin.SetActive(false);
|
m_Origin.SetActive(false);
|
||||||
|
|
||||||
var parent = origin.transform.parent;
|
var parent = m_Origin.transform.parent;
|
||||||
for (var i = 0; i < count; i++)
|
for (var i = 0; i < m_Count; i++)
|
||||||
{
|
{
|
||||||
var go = Instantiate(origin, parent, false);
|
var go = Instantiate(m_Origin, parent, false);
|
||||||
go.name = string.Format("{0} {1}", origin.name, i + 1);
|
go.name = $"{m_Origin.name} {i + 1}";
|
||||||
go.hideFlags = HideFlags.DontSave;
|
go.hideFlags = HideFlags.DontSave;
|
||||||
go.SetActive(true);
|
go.SetActive(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,31 @@
|
|||||||
using UnityEngine;
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
|
using UnityEngine.Serialization;
|
||||||
|
|
||||||
public class UIElementDragger : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
|
public class UIElementDragger : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
|
||||||
{
|
{
|
||||||
public enum Target
|
[SerializeField]
|
||||||
{
|
private Target m_Target;
|
||||||
Self,
|
|
||||||
Parent,
|
|
||||||
Custom,
|
|
||||||
}
|
|
||||||
|
|
||||||
private RectTransform rectTransform;
|
[SerializeField]
|
||||||
private Canvas canvas;
|
private Transform m_CustomTarget;
|
||||||
public Target m_Target;
|
|
||||||
public Transform m_CustomTarget;
|
[FormerlySerializedAs("ex2")]
|
||||||
public bool ex2;
|
[SerializeField]
|
||||||
|
private bool m_UseCanvasScale;
|
||||||
|
|
||||||
|
private Canvas _canvas;
|
||||||
|
private RectTransform _rectTransform;
|
||||||
|
|
||||||
private void OnEnable()
|
private void OnEnable()
|
||||||
{
|
{
|
||||||
rectTransform = GetComponent<RectTransform>();
|
_rectTransform = GetComponent<RectTransform>();
|
||||||
canvas = GetComponentInParent<Canvas>();
|
_canvas = GetComponentInParent<Canvas>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnBeginDrag(PointerEventData eventData)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnDrag(PointerEventData eventData)
|
public void OnDrag(PointerEventData eventData)
|
||||||
@@ -29,57 +35,59 @@ public class UIElementDragger : MonoBehaviour, IBeginDragHandler, IDragHandler,
|
|||||||
switch (m_Target)
|
switch (m_Target)
|
||||||
{
|
{
|
||||||
case Target.Self:
|
case Target.Self:
|
||||||
rectTransform.localPosition += delta;
|
_rectTransform.localPosition += delta;
|
||||||
break;
|
break;
|
||||||
case Target.Parent:
|
case Target.Parent:
|
||||||
rectTransform.parent.localPosition += delta;
|
_rectTransform.parent.localPosition += delta;
|
||||||
break;
|
break;
|
||||||
case Target.Custom:
|
case Target.Custom:
|
||||||
rectTransform.localPosition += delta;
|
_rectTransform.localPosition += delta;
|
||||||
if (m_CustomTarget)
|
if (m_CustomTarget)
|
||||||
{
|
{
|
||||||
if (ex2)
|
if (m_UseCanvasScale)
|
||||||
delta.Scale(canvas.rootCanvas.transform.localScale);
|
{
|
||||||
|
delta.Scale(_canvas.rootCanvas.transform.localScale);
|
||||||
|
}
|
||||||
|
|
||||||
m_CustomTarget.localPosition += delta;
|
m_CustomTarget.localPosition += delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnBeginDrag(PointerEventData eventData)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnEndDrag(PointerEventData eventData)
|
public void OnEndDrag(PointerEventData eventData)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector2 GetLocalDelta(Vector2 evDelta)
|
private Vector2 GetLocalDelta(Vector2 evDelta)
|
||||||
{
|
{
|
||||||
switch (canvas.renderMode)
|
switch (_canvas.renderMode)
|
||||||
{
|
{
|
||||||
case RenderMode.ScreenSpaceOverlay:
|
case RenderMode.ScreenSpaceOverlay:
|
||||||
{
|
{
|
||||||
var zero = transform.InverseTransformPoint(Vector2.zero);
|
var zero = transform.InverseTransformPoint(Vector2.zero);
|
||||||
var delta = transform.InverseTransformPoint(evDelta);
|
var delta = transform.InverseTransformPoint(evDelta);
|
||||||
return delta - zero;
|
return delta - zero;
|
||||||
}
|
}
|
||||||
case RenderMode.ScreenSpaceCamera:
|
case RenderMode.ScreenSpaceCamera:
|
||||||
{
|
|
||||||
Vector2 zero, delta;
|
|
||||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, Vector2.zero, canvas.worldCamera, out zero);
|
|
||||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, evDelta, canvas.worldCamera, out delta);
|
|
||||||
return delta - zero;
|
|
||||||
}
|
|
||||||
case RenderMode.WorldSpace:
|
case RenderMode.WorldSpace:
|
||||||
{
|
{
|
||||||
Vector3 zero, delta;
|
RectTransformUtility.ScreenPointToLocalPointInRectangle(_rectTransform, Vector2.zero,
|
||||||
RectTransformUtility.ScreenPointToWorldPointInRectangle(rectTransform, Vector2.zero, canvas.worldCamera, out zero);
|
_canvas.worldCamera, out var zero);
|
||||||
RectTransformUtility.ScreenPointToWorldPointInRectangle(rectTransform, evDelta, canvas.worldCamera, out delta);
|
RectTransformUtility.ScreenPointToLocalPointInRectangle(_rectTransform, evDelta,
|
||||||
return delta - zero;
|
_canvas.worldCamera, out var delta);
|
||||||
}
|
return delta - zero;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
throw new System.NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private enum Target
|
||||||
|
{
|
||||||
|
Self,
|
||||||
|
Parent,
|
||||||
|
Custom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.Serialization;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
|
||||||
namespace Coffee.UIExtensions.Demo
|
namespace Coffee.UIExtensions.Demo
|
||||||
{
|
{
|
||||||
public class UIParticle_Demo : MonoBehaviour
|
public class UIParticle_Demo : MonoBehaviour
|
||||||
{
|
{
|
||||||
public Canvas root;
|
[FormerlySerializedAs("root")]
|
||||||
|
[SerializeField]
|
||||||
|
private Canvas m_RootCanvas;
|
||||||
|
|
||||||
private int _width;
|
|
||||||
private int _height;
|
private int _height;
|
||||||
|
private int _score;
|
||||||
|
private int _width;
|
||||||
|
|
||||||
private void Start()
|
private void Start()
|
||||||
{
|
{
|
||||||
@@ -24,11 +28,18 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
case RuntimePlatform.WindowsPlayer:
|
case RuntimePlatform.WindowsPlayer:
|
||||||
case RuntimePlatform.LinuxPlayer:
|
case RuntimePlatform.LinuxPlayer:
|
||||||
if (Screen.width == _width && Screen.height == _height)
|
if (Screen.width == _width && Screen.height == _height)
|
||||||
|
{
|
||||||
Screen.SetResolution(_height, _width, Screen.fullScreen);
|
Screen.SetResolution(_height, _width, Screen.fullScreen);
|
||||||
|
}
|
||||||
else if (Screen.width == _height && Screen.height == _width)
|
else if (Screen.width == _height && Screen.height == _width)
|
||||||
|
{
|
||||||
Screen.SetResolution(Mathf.Min(_width, _height), Mathf.Min(_width, _height), Screen.fullScreen);
|
Screen.SetResolution(Mathf.Min(_width, _height), Mathf.Min(_width, _height), Screen.fullScreen);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
Screen.SetResolution(_width, _height, Screen.fullScreen);
|
Screen.SetResolution(_width, _height, Screen.fullScreen);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,27 +49,31 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
Screen.fullScreen = !Screen.fullScreen;
|
Screen.fullScreen = !Screen.fullScreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EnableAnimations(bool enabled)
|
public void EnableAnimations(bool flag)
|
||||||
{
|
{
|
||||||
foreach (var animator in FindObjectsOfType<Animator>())
|
foreach (var animator in FindObjectsOfType<Animator>())
|
||||||
{
|
{
|
||||||
animator.enabled = enabled;
|
animator.enabled = flag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UIParticle_MeshSharing(bool enabled)
|
public void UIParticle_MeshSharing(bool flag)
|
||||||
{
|
{
|
||||||
foreach (var uip in root.GetComponentsInChildren<UIParticle>(true))
|
foreach (var uip in m_RootCanvas.GetComponentsInChildren<UIParticle>(true))
|
||||||
{
|
{
|
||||||
uip.meshSharing = enabled ? UIParticle.MeshSharing.Auto : UIParticle.MeshSharing.None;
|
uip.meshSharing = flag
|
||||||
|
? UIParticle.MeshSharing.Auto
|
||||||
|
: UIParticle.MeshSharing.None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UIParticle_RandomGroup(bool enabled)
|
public void UIParticle_RandomGroup(bool flag)
|
||||||
{
|
{
|
||||||
foreach (var uip in root.GetComponentsInChildren<UIParticle>(true))
|
foreach (var uip in m_RootCanvas.GetComponentsInChildren<UIParticle>(true))
|
||||||
{
|
{
|
||||||
uip.groupMaxId = enabled ? 4 : 0;
|
uip.groupMaxId = flag
|
||||||
|
? 4
|
||||||
|
: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,38 +85,40 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ParticleSystem_WorldSpaseSimulation(bool enabled)
|
public void ParticleSystem_WorldSpaseSimulation(bool flag)
|
||||||
{
|
{
|
||||||
foreach (var ps in FindObjectsOfType<ParticleSystem>())
|
foreach (var p in FindObjectsOfType<ParticleSystem>())
|
||||||
{
|
{
|
||||||
var main = ps.main;
|
var main = p.main;
|
||||||
main.simulationSpace = enabled ? ParticleSystemSimulationSpace.World : ParticleSystemSimulationSpace.Local;
|
main.simulationSpace = flag
|
||||||
|
? ParticleSystemSimulationSpace.World
|
||||||
|
: ParticleSystemSimulationSpace.Local;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ParticleSystem_WorldSpaseSimulation(ParticleSystem particleSystem)
|
public void ParticleSystem_WorldSpaseSimulation(ParticleSystem ps)
|
||||||
{
|
{
|
||||||
foreach (var ps in particleSystem.GetComponentsInChildren<ParticleSystem>())
|
foreach (var p in ps.GetComponentsInChildren<ParticleSystem>())
|
||||||
{
|
{
|
||||||
var main = ps.main;
|
var main = p.main;
|
||||||
main.simulationSpace = ParticleSystemSimulationSpace.World;
|
main.simulationSpace = ParticleSystemSimulationSpace.World;
|
||||||
ps.Clear();
|
p.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ParticleSystem_LocalSpaseSimulation(ParticleSystem particleSystem)
|
public void ParticleSystem_LocalSpaseSimulation(ParticleSystem ps)
|
||||||
{
|
{
|
||||||
foreach (var ps in particleSystem.GetComponentsInChildren<ParticleSystem>())
|
foreach (var p in ps.GetComponentsInChildren<ParticleSystem>())
|
||||||
{
|
{
|
||||||
var main = ps.main;
|
var main = p.main;
|
||||||
main.simulationSpace = ParticleSystemSimulationSpace.Local;
|
main.simulationSpace = ParticleSystemSimulationSpace.Local;
|
||||||
ps.Clear();
|
p.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ParticleSystem_Emit(ParticleSystem particleSystem)
|
public void ParticleSystem_Emit(ParticleSystem ps)
|
||||||
{
|
{
|
||||||
particleSystem.Emit(5);
|
ps.Emit(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ParticleSystem_SetScale(float scale)
|
public void ParticleSystem_SetScale(float scale)
|
||||||
@@ -127,41 +144,34 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
attractor.movement = UIParticleAttractor.Movement.Sphere;
|
attractor.movement = UIParticleAttractor.Movement.Sphere;
|
||||||
}
|
}
|
||||||
|
|
||||||
int score = 0;
|
|
||||||
public void UIParticleAttractor_OnAttract(Text scoreText)
|
public void UIParticleAttractor_OnAttract(Text scoreText)
|
||||||
{
|
{
|
||||||
score++;
|
_score++;
|
||||||
scoreText.text = score.ToString();
|
scoreText.text = _score.ToString();
|
||||||
scoreText.GetComponent<Animator>().Play(0);
|
scoreText.GetComponent<Animator>().Play(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Canvas_WorldSpace(bool flag)
|
public void Canvas_WorldSpace(bool flag)
|
||||||
{
|
{
|
||||||
if (flag)
|
if (!flag) return;
|
||||||
{
|
|
||||||
var canvas = FindObjectOfType<Canvas>();
|
m_RootCanvas.renderMode = RenderMode.ScreenSpaceCamera;
|
||||||
canvas.renderMode = RenderMode.ScreenSpaceCamera;
|
m_RootCanvas.renderMode = RenderMode.WorldSpace;
|
||||||
canvas.renderMode = RenderMode.WorldSpace;
|
m_RootCanvas.transform.rotation = Quaternion.Euler(new Vector3(0, 10, 0));
|
||||||
canvas.transform.rotation = Quaternion.Euler(new Vector3(0, 10, 0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Canvas_CameraSpace(bool flag)
|
public void Canvas_CameraSpace(bool flag)
|
||||||
{
|
{
|
||||||
if (flag)
|
if (!flag) return;
|
||||||
{
|
|
||||||
var canvas = FindObjectOfType<Canvas>();
|
m_RootCanvas.renderMode = RenderMode.ScreenSpaceCamera;
|
||||||
canvas.renderMode = RenderMode.ScreenSpaceCamera;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Canvas_Overlay(bool flag)
|
public void Canvas_Overlay(bool flag)
|
||||||
{
|
{
|
||||||
if (flag)
|
if (!flag) return;
|
||||||
{
|
|
||||||
var canvas = FindObjectOfType<Canvas>();
|
m_RootCanvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||||||
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +1,37 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.Serialization;
|
||||||
|
|
||||||
namespace Coffee.UIExtensions.Demo
|
namespace Coffee.UIExtensions.Demo
|
||||||
{
|
{
|
||||||
public class UIParticle_Demo_UIParticleController : MonoBehaviour
|
public class UIParticle_Demo_UIParticleController : MonoBehaviour
|
||||||
{
|
{
|
||||||
public Transform root;
|
[FormerlySerializedAs("root")]
|
||||||
|
[SerializeField]
|
||||||
|
private Transform m_RootTransform;
|
||||||
|
|
||||||
public void UIParticle_MeshSharing(bool enabled)
|
public void UIParticle_MeshSharing(bool flag)
|
||||||
{
|
{
|
||||||
foreach (var uip in root.GetComponentsInChildren<UIParticle>(true))
|
foreach (var uip in m_RootTransform.GetComponentsInChildren<UIParticle>(true))
|
||||||
{
|
{
|
||||||
uip.meshSharing = enabled ? UIParticle.MeshSharing.Auto : UIParticle.MeshSharing.None;
|
uip.meshSharing = flag
|
||||||
|
? UIParticle.MeshSharing.Auto
|
||||||
|
: UIParticle.MeshSharing.None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UIParticle_RandomGroup(bool enabled)
|
public void UIParticle_RandomGroup(bool flag)
|
||||||
{
|
{
|
||||||
foreach (var uip in root.GetComponentsInChildren<UIParticle>(true))
|
foreach (var uip in m_RootTransform.GetComponentsInChildren<UIParticle>(true))
|
||||||
{
|
{
|
||||||
uip.groupMaxId = enabled ? 4 : 0;
|
uip.groupMaxId = flag
|
||||||
|
? 4
|
||||||
|
: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UIParticle_Scale(float scale)
|
public void UIParticle_Scale(float scale)
|
||||||
{
|
{
|
||||||
foreach (var uip in root.GetComponentsInChildren<UIParticle>(true))
|
foreach (var uip in m_RootTransform.GetComponentsInChildren<UIParticle>(true))
|
||||||
{
|
{
|
||||||
uip.scale = scale;
|
uip.scale = scale;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 839afb79f79094e6c942050ec5413ebf
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!21 &2100000
|
|
||||||
Material:
|
|
||||||
serializedVersion: 6
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_Name: UIParticle_PerformanceDemo_Fire
|
|
||||||
m_Shader: {fileID: 4800000, guid: ecfa8f5732b504ef98fba10aa18d0326, type: 3}
|
|
||||||
m_ShaderKeywords:
|
|
||||||
m_LightmapFlags: 4
|
|
||||||
m_EnableInstancingVariants: 0
|
|
||||||
m_DoubleSidedGI: 0
|
|
||||||
m_CustomRenderQueue: -1
|
|
||||||
stringTagMap: {}
|
|
||||||
disabledShaderPasses: []
|
|
||||||
m_SavedProperties:
|
|
||||||
serializedVersion: 3
|
|
||||||
m_TexEnvs:
|
|
||||||
- _BumpMap:
|
|
||||||
m_Texture: {fileID: 0}
|
|
||||||
m_Scale: {x: 1, y: 1}
|
|
||||||
m_Offset: {x: 0, y: 0}
|
|
||||||
- _DetailAlbedoMap:
|
|
||||||
m_Texture: {fileID: 0}
|
|
||||||
m_Scale: {x: 1, y: 1}
|
|
||||||
m_Offset: {x: 0, y: 0}
|
|
||||||
- _DetailMask:
|
|
||||||
m_Texture: {fileID: 0}
|
|
||||||
m_Scale: {x: 1, y: 1}
|
|
||||||
m_Offset: {x: 0, y: 0}
|
|
||||||
- _DetailNormalMap:
|
|
||||||
m_Texture: {fileID: 0}
|
|
||||||
m_Scale: {x: 1, y: 1}
|
|
||||||
m_Offset: {x: 0, y: 0}
|
|
||||||
- _EmissionMap:
|
|
||||||
m_Texture: {fileID: 0}
|
|
||||||
m_Scale: {x: 1, y: 1}
|
|
||||||
m_Offset: {x: 0, y: 0}
|
|
||||||
- _MainTex:
|
|
||||||
m_Texture: {fileID: 2800000, guid: 294c5667b05cc4edcac3885a5899cc65, type: 3}
|
|
||||||
m_Scale: {x: 1, y: 1}
|
|
||||||
m_Offset: {x: 0, y: 0}
|
|
||||||
- _MetallicGlossMap:
|
|
||||||
m_Texture: {fileID: 0}
|
|
||||||
m_Scale: {x: 1, y: 1}
|
|
||||||
m_Offset: {x: 0, y: 0}
|
|
||||||
- _OcclusionMap:
|
|
||||||
m_Texture: {fileID: 0}
|
|
||||||
m_Scale: {x: 1, y: 1}
|
|
||||||
m_Offset: {x: 0, y: 0}
|
|
||||||
- _ParallaxMap:
|
|
||||||
m_Texture: {fileID: 0}
|
|
||||||
m_Scale: {x: 1, y: 1}
|
|
||||||
m_Offset: {x: 0, y: 0}
|
|
||||||
m_Floats:
|
|
||||||
- _BumpScale: 1
|
|
||||||
- _ColorMask: 15
|
|
||||||
- _Cutoff: 0.5
|
|
||||||
- _DetailNormalMapScale: 1
|
|
||||||
- _DstBlend: 0
|
|
||||||
- _GlossMapScale: 1
|
|
||||||
- _Glossiness: 0.5
|
|
||||||
- _GlossyReflections: 1
|
|
||||||
- _Glow: 1
|
|
||||||
- _InvFade: 1
|
|
||||||
- _Metallic: 0
|
|
||||||
- _Mode: 0
|
|
||||||
- _OcclusionStrength: 1
|
|
||||||
- _Parallax: 0.02
|
|
||||||
- _SmoothnessTextureChannel: 0
|
|
||||||
- _SpecularHighlights: 1
|
|
||||||
- _SrcBlend: 1
|
|
||||||
- _Stencil: 0
|
|
||||||
- _StencilComp: 8
|
|
||||||
- _StencilOp: 0
|
|
||||||
- _StencilReadMask: 255
|
|
||||||
- _StencilWriteMask: 255
|
|
||||||
- _UVSec: 0
|
|
||||||
- _UseUIAlphaClip: 0
|
|
||||||
- _ZWrite: 1
|
|
||||||
m_Colors:
|
|
||||||
- _ClipRect: {r: -32767, g: -32767, b: 32767, a: 32767}
|
|
||||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
|
||||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
|
||||||
- _TintColor: {r: 1, g: 1, b: 1, a: 1}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 585 KiB |
@@ -1,121 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 294c5667b05cc4edcac3885a5899cc65
|
|
||||||
TextureImporter:
|
|
||||||
fileIDToRecycleName: {}
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 9
|
|
||||||
mipmaps:
|
|
||||||
mipMapMode: 0
|
|
||||||
enableMipMap: 1
|
|
||||||
sRGBTexture: 1
|
|
||||||
linearTexture: 0
|
|
||||||
fadeOut: 0
|
|
||||||
borderMipMap: 0
|
|
||||||
mipMapsPreserveCoverage: 0
|
|
||||||
alphaTestReferenceValue: 0.5
|
|
||||||
mipMapFadeDistanceStart: 1
|
|
||||||
mipMapFadeDistanceEnd: 3
|
|
||||||
bumpmap:
|
|
||||||
convertToNormalMap: 0
|
|
||||||
externalNormalMap: 0
|
|
||||||
heightScale: 0.25
|
|
||||||
normalMapFilter: 0
|
|
||||||
isReadable: 0
|
|
||||||
streamingMipmaps: 0
|
|
||||||
streamingMipmapsPriority: 0
|
|
||||||
grayScaleToAlpha: 0
|
|
||||||
generateCubemap: 6
|
|
||||||
cubemapConvolution: 0
|
|
||||||
seamlessCubemap: 0
|
|
||||||
textureFormat: 1
|
|
||||||
maxTextureSize: 2048
|
|
||||||
textureSettings:
|
|
||||||
serializedVersion: 2
|
|
||||||
filterMode: 2
|
|
||||||
aniso: 16
|
|
||||||
mipBias: -100
|
|
||||||
wrapU: -1
|
|
||||||
wrapV: -1
|
|
||||||
wrapW: -1
|
|
||||||
nPOTScale: 1
|
|
||||||
lightmap: 0
|
|
||||||
compressionQuality: 50
|
|
||||||
spriteMode: 0
|
|
||||||
spriteExtrude: 1
|
|
||||||
spriteMeshType: 1
|
|
||||||
alignment: 0
|
|
||||||
spritePivot: {x: 0.5, y: 0.5}
|
|
||||||
spritePixelsToUnits: 100
|
|
||||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
|
||||||
spriteGenerateFallbackPhysicsShape: 1
|
|
||||||
alphaUsage: 1
|
|
||||||
alphaIsTransparency: 0
|
|
||||||
spriteTessellationDetail: -1
|
|
||||||
textureType: 0
|
|
||||||
textureShape: 1
|
|
||||||
singleChannelComponent: 0
|
|
||||||
maxTextureSizeSet: 0
|
|
||||||
compressionQualitySet: 0
|
|
||||||
textureFormatSet: 0
|
|
||||||
platformSettings:
|
|
||||||
- serializedVersion: 2
|
|
||||||
buildTarget: DefaultTexturePlatform
|
|
||||||
maxTextureSize: 4096
|
|
||||||
resizeAlgorithm: 0
|
|
||||||
textureFormat: -1
|
|
||||||
textureCompression: 2
|
|
||||||
compressionQuality: 50
|
|
||||||
crunchedCompression: 0
|
|
||||||
allowsAlphaSplitting: 0
|
|
||||||
overridden: 0
|
|
||||||
androidETC2FallbackOverride: 0
|
|
||||||
- serializedVersion: 2
|
|
||||||
buildTarget: Standalone
|
|
||||||
maxTextureSize: 4096
|
|
||||||
resizeAlgorithm: 0
|
|
||||||
textureFormat: -1
|
|
||||||
textureCompression: 2
|
|
||||||
compressionQuality: 50
|
|
||||||
crunchedCompression: 0
|
|
||||||
allowsAlphaSplitting: 0
|
|
||||||
overridden: 0
|
|
||||||
androidETC2FallbackOverride: 0
|
|
||||||
- serializedVersion: 2
|
|
||||||
buildTarget: Android
|
|
||||||
maxTextureSize: 4096
|
|
||||||
resizeAlgorithm: 0
|
|
||||||
textureFormat: -1
|
|
||||||
textureCompression: 2
|
|
||||||
compressionQuality: 50
|
|
||||||
crunchedCompression: 0
|
|
||||||
allowsAlphaSplitting: 0
|
|
||||||
overridden: 0
|
|
||||||
androidETC2FallbackOverride: 0
|
|
||||||
- serializedVersion: 2
|
|
||||||
buildTarget: WebGL
|
|
||||||
maxTextureSize: 4096
|
|
||||||
resizeAlgorithm: 0
|
|
||||||
textureFormat: -1
|
|
||||||
textureCompression: 2
|
|
||||||
compressionQuality: 50
|
|
||||||
crunchedCompression: 0
|
|
||||||
allowsAlphaSplitting: 0
|
|
||||||
overridden: 0
|
|
||||||
androidETC2FallbackOverride: 0
|
|
||||||
spriteSheet:
|
|
||||||
serializedVersion: 2
|
|
||||||
sprites: []
|
|
||||||
outline: []
|
|
||||||
physicsShape: []
|
|
||||||
bones: []
|
|
||||||
spriteID:
|
|
||||||
vertices: []
|
|
||||||
indices:
|
|
||||||
edges: []
|
|
||||||
weights: []
|
|
||||||
spritePackingTag:
|
|
||||||
pSDRemoveMatte: 0
|
|
||||||
pSDShowRemoveMatteOption: 0
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: b7ac7640c2f1047c887aa52ff1ce9fcc
|
|
||||||
NativeFormatImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
mainObjectFileID: 2100000
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: c5a6b37697e71473cb1ecc90047622d0
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: b888c253a15224f1fa518bed74028211
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
Binary file not shown.
@@ -1,22 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 70069a8db1df148ae8b4c8108c079acf
|
|
||||||
TrueTypeFontImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 4
|
|
||||||
fontSize: 26
|
|
||||||
forceTextureCase: 0
|
|
||||||
characterSpacing: 0
|
|
||||||
characterPadding: 1
|
|
||||||
includeFontData: 1
|
|
||||||
fontName: Falstin
|
|
||||||
fontNames:
|
|
||||||
- Falstin
|
|
||||||
fallbackFontReferences: []
|
|
||||||
customCharacters:
|
|
||||||
fontRenderingMode: 1
|
|
||||||
ascentCalculationMode: 1
|
|
||||||
useLegacyBoundsCalculation: 0
|
|
||||||
shouldRoundAdvanceValue: 1
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: fa6e3b593bf274861b2eab47082d9b1e
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 784696794bc6345bc80bf49623581c2e
|
|
||||||
PrefabImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: f0b370726e57248da97c1c2f3bfd8bdf
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Coffee.NanoMonitor",
|
|
||||||
"references": [],
|
|
||||||
"optionalUnityReferences": [],
|
|
||||||
"includePlatforms": [],
|
|
||||||
"excludePlatforms": [],
|
|
||||||
"allowUnsafeCode": false,
|
|
||||||
"overrideReferences": false,
|
|
||||||
"precompiledReferences": [],
|
|
||||||
"autoReferenced": false,
|
|
||||||
"defineConstraints": []
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 3d6cc132218a845708ce317bd33e5500
|
|
||||||
AssemblyDefinitionImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,268 +0,0 @@
|
|||||||
using System;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.Serialization;
|
|
||||||
using UnityEngine.UI;
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
using UnityEditor;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Coffee.NanoMonitor
|
|
||||||
{
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
[CustomEditor(typeof(NanoMonitor))]
|
|
||||||
internal class NanoMonitorEditor : Editor
|
|
||||||
{
|
|
||||||
private UnityEditorInternal.ReorderableList m_MonitorItemList;
|
|
||||||
|
|
||||||
private void OnEnable()
|
|
||||||
{
|
|
||||||
var items = serializedObject.FindProperty("m_CustomMonitorItems");
|
|
||||||
m_MonitorItemList = new UnityEditorInternal.ReorderableList(serializedObject, items)
|
|
||||||
{
|
|
||||||
draggable = false,
|
|
||||||
drawHeaderCallback = r => { EditorGUI.LabelField(r, new GUIContent("Custom Monitor Items")); },
|
|
||||||
drawElementCallback = (r, i, _, __) =>
|
|
||||||
{
|
|
||||||
EditorGUI.LabelField(new Rect(r.x, r.y, r.width, r.height - 2), GUIContent.none, EditorStyles.textArea);
|
|
||||||
var labelWidth = EditorGUIUtility.labelWidth;
|
|
||||||
EditorGUIUtility.labelWidth = 80;
|
|
||||||
EditorGUI.PropertyField(new Rect(r.x + 2, r.y + 3, r.width - 4, r.height - 4), items.GetArrayElementAtIndex(i), true);
|
|
||||||
EditorGUIUtility.labelWidth = labelWidth;
|
|
||||||
},
|
|
||||||
elementHeightCallback = i => EditorGUI.GetPropertyHeight(items.GetArrayElementAtIndex(i)) + 6,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnInspectorGUI()
|
|
||||||
{
|
|
||||||
base.OnInspectorGUI();
|
|
||||||
|
|
||||||
m_MonitorItemList.DoLayoutList();
|
|
||||||
serializedObject.ApplyModifiedProperties();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
[DisallowMultipleComponent]
|
|
||||||
public sealed class NanoMonitor : MonoBehaviour
|
|
||||||
{
|
|
||||||
//################################
|
|
||||||
// Serialize Members.
|
|
||||||
//################################
|
|
||||||
// Settings
|
|
||||||
[Header("Settings")] [SerializeField] [Range(0.01f, 2f)]
|
|
||||||
private float m_Interval = 1f;
|
|
||||||
|
|
||||||
[SerializeField] [Range(0, 3)] private int m_Precision = 2;
|
|
||||||
[SerializeField] private Font m_Font;
|
|
||||||
|
|
||||||
// Foldout
|
|
||||||
[Header("Foldout")] [SerializeField] private bool m_Opened = false;
|
|
||||||
|
|
||||||
[FormerlySerializedAs("m_Collapse")] [SerializeField]
|
|
||||||
private GameObject m_FoldoutObject = null;
|
|
||||||
|
|
||||||
[SerializeField] private Button m_OpenButton = null;
|
|
||||||
[SerializeField] private Button m_CloseButton = null;
|
|
||||||
|
|
||||||
// View
|
|
||||||
[Header("View")] [SerializeField] private MonitorUI m_Fps = null;
|
|
||||||
[SerializeField] private MonitorUI m_Gc = null;
|
|
||||||
[SerializeField] private MonitorUI m_MonoUsage = null;
|
|
||||||
[SerializeField] private MonitorUI m_UnityUsage = null;
|
|
||||||
|
|
||||||
[HideInInspector] [SerializeField] private CustomMonitorItem[] m_CustomMonitorItems = new CustomMonitorItem[0];
|
|
||||||
|
|
||||||
|
|
||||||
//################################
|
|
||||||
// Public Members.
|
|
||||||
//################################
|
|
||||||
public void Clean()
|
|
||||||
{
|
|
||||||
Resources.UnloadUnusedAssets();
|
|
||||||
GC.Collect();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//################################
|
|
||||||
// Private Members.
|
|
||||||
//################################
|
|
||||||
private double _elapsed;
|
|
||||||
private double _fpsElapsed;
|
|
||||||
private int _frames;
|
|
||||||
|
|
||||||
private void Open()
|
|
||||||
{
|
|
||||||
_frames = 0;
|
|
||||||
_elapsed = m_Interval;
|
|
||||||
_fpsElapsed = 0;
|
|
||||||
|
|
||||||
if (m_FoldoutObject)
|
|
||||||
{
|
|
||||||
m_FoldoutObject.SetActive(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_CloseButton)
|
|
||||||
{
|
|
||||||
m_CloseButton.gameObject.SetActive(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_OpenButton)
|
|
||||||
{
|
|
||||||
m_OpenButton.gameObject.SetActive(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Close()
|
|
||||||
{
|
|
||||||
if (m_FoldoutObject)
|
|
||||||
{
|
|
||||||
m_FoldoutObject.SetActive(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_CloseButton)
|
|
||||||
{
|
|
||||||
m_CloseButton.gameObject.SetActive(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_OpenButton)
|
|
||||||
{
|
|
||||||
m_OpenButton.gameObject.SetActive(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//################################
|
|
||||||
// Unity Callbacks.
|
|
||||||
//################################
|
|
||||||
private void OnEnable()
|
|
||||||
{
|
|
||||||
if (m_OpenButton)
|
|
||||||
{
|
|
||||||
m_OpenButton.onClick.AddListener(Open);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_CloseButton)
|
|
||||||
{
|
|
||||||
m_CloseButton.onClick.AddListener(Close);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_Opened)
|
|
||||||
{
|
|
||||||
Open();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDisable()
|
|
||||||
{
|
|
||||||
if (m_OpenButton)
|
|
||||||
{
|
|
||||||
m_OpenButton.onClick.RemoveListener(Open);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_CloseButton)
|
|
||||||
{
|
|
||||||
m_CloseButton.onClick.RemoveListener(Close);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Update()
|
|
||||||
{
|
|
||||||
_frames++;
|
|
||||||
_elapsed += Time.unscaledDeltaTime;
|
|
||||||
_fpsElapsed += Time.unscaledDeltaTime;
|
|
||||||
if (_elapsed < m_Interval) return;
|
|
||||||
|
|
||||||
if (m_Fps)
|
|
||||||
{
|
|
||||||
m_Fps.SetText("FPS: {0}", (int) (_frames / _fpsElapsed));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_Gc)
|
|
||||||
{
|
|
||||||
m_Gc.SetText("GC: {0}", GC.CollectionCount(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_MonoUsage)
|
|
||||||
{
|
|
||||||
var monoUsed = (UnityEngine.Profiling.Profiler.GetMonoUsedSizeLong() >> 10) / 1024f;
|
|
||||||
var monoTotal = (UnityEngine.Profiling.Profiler.GetMonoHeapSizeLong() >> 10) / 1024f;
|
|
||||||
if (m_Precision == 3)
|
|
||||||
{
|
|
||||||
m_MonoUsage.SetText("Mono: {0:N3}/{1:N3}MB", monoUsed, monoTotal);
|
|
||||||
}
|
|
||||||
else if (m_Precision == 2)
|
|
||||||
{
|
|
||||||
m_MonoUsage.SetText("Mono: {0:N2}/{1:N2}MB", monoUsed, monoTotal);
|
|
||||||
}
|
|
||||||
else if (m_Precision == 1)
|
|
||||||
{
|
|
||||||
m_MonoUsage.SetText("Mono: {0:N1}/{1:N1}MB", monoUsed, monoTotal);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_MonoUsage.SetText("Mono: {0:N0}/{1:N0}MB", monoUsed, monoTotal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_UnityUsage)
|
|
||||||
{
|
|
||||||
var unityUsed = (UnityEngine.Profiling.Profiler.GetTotalAllocatedMemoryLong() >> 10) / 1024f;
|
|
||||||
var unityTotal = (UnityEngine.Profiling.Profiler.GetTotalReservedMemoryLong() >> 10) / 1024f;
|
|
||||||
if (m_Precision == 3)
|
|
||||||
{
|
|
||||||
m_UnityUsage.SetText("Unity: {0:N3}/{1:N3}MB", unityUsed, unityTotal);
|
|
||||||
}
|
|
||||||
else if (m_Precision == 2)
|
|
||||||
{
|
|
||||||
m_UnityUsage.SetText("Unity: {0:N2}/{1:N2}MB", unityUsed, unityTotal);
|
|
||||||
}
|
|
||||||
else if (m_Precision == 1)
|
|
||||||
{
|
|
||||||
m_UnityUsage.SetText("Unity: {0:N1}/{1:N1}MB", unityUsed, unityTotal);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_UnityUsage.SetText("Unity: {0:N0}/{1:N0}MB", unityUsed, unityTotal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var item in m_CustomMonitorItems)
|
|
||||||
{
|
|
||||||
item.UpdateText();
|
|
||||||
}
|
|
||||||
|
|
||||||
_frames = 0;
|
|
||||||
_elapsed %= m_Interval;
|
|
||||||
_fpsElapsed = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
private void OnValidate()
|
|
||||||
{
|
|
||||||
if (m_Font)
|
|
||||||
{
|
|
||||||
foreach (var ui in GetComponentsInChildren<MonitorUI>(true))
|
|
||||||
{
|
|
||||||
ui.font = m_Font;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_Opened)
|
|
||||||
{
|
|
||||||
Open();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 19e83f45e7d5648f2bd10122dc7fed14
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: affee221821a14cfb842a0b0e8514a4e
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.UI;
|
|
||||||
|
|
||||||
namespace Coffee.NanoMonitor{
|
|
||||||
public class FixedFont
|
|
||||||
{
|
|
||||||
private readonly UIVertex[] _tmpVerts = new UIVertex[4];
|
|
||||||
private static readonly Dictionary<Font, FixedFont> _fonts = new Dictionary<Font, FixedFont>();
|
|
||||||
private static readonly TextGenerator _textGenerator = new TextGenerator(100);
|
|
||||||
|
|
||||||
private static TextGenerationSettings _settings = new TextGenerationSettings
|
|
||||||
{
|
|
||||||
scaleFactor = 1,
|
|
||||||
horizontalOverflow = HorizontalWrapMode.Overflow,
|
|
||||||
verticalOverflow = VerticalWrapMode.Overflow,
|
|
||||||
alignByGeometry = true,
|
|
||||||
textAnchor = TextAnchor.MiddleCenter,
|
|
||||||
color = Color.white
|
|
||||||
};
|
|
||||||
|
|
||||||
private int _resolution = 0;
|
|
||||||
private readonly Font _font;
|
|
||||||
private UIVertex[] _verts;
|
|
||||||
private UICharInfo[] _charInfos;
|
|
||||||
|
|
||||||
private FixedFont(Font font)
|
|
||||||
{
|
|
||||||
_font = font;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int fontSize => _font.dynamic ? 32 : _font.fontSize;
|
|
||||||
|
|
||||||
public static FixedFont GetOrCreate(Font font)
|
|
||||||
{
|
|
||||||
if (font == null) return null;
|
|
||||||
if (_fonts.TryGetValue(font, out var data)) return data;
|
|
||||||
|
|
||||||
data = new FixedFont(font);
|
|
||||||
_fonts.Add(font, data);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Invalidate()
|
|
||||||
{
|
|
||||||
_resolution = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateFont()
|
|
||||||
{
|
|
||||||
if (!_font) return;
|
|
||||||
|
|
||||||
var mat = _font.material;
|
|
||||||
if (!mat) return;
|
|
||||||
|
|
||||||
var tex = mat.mainTexture;
|
|
||||||
if (!tex) return;
|
|
||||||
|
|
||||||
var currentResolution = tex.width * tex.height;
|
|
||||||
|
|
||||||
if (_resolution == currentResolution) return;
|
|
||||||
_resolution = currentResolution;
|
|
||||||
|
|
||||||
_settings.font = _font;
|
|
||||||
_textGenerator.Invalidate();
|
|
||||||
_textGenerator.Populate("_!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", _settings);
|
|
||||||
|
|
||||||
_verts = _textGenerator.GetVerticesArray();
|
|
||||||
_charInfos = _textGenerator.GetCharactersArray();
|
|
||||||
|
|
||||||
float offsetX = 0;
|
|
||||||
for (var i = 0; i < _verts.Length; i++)
|
|
||||||
{
|
|
||||||
if ((i & 3) == 0)
|
|
||||||
offsetX = _verts[i].position.x;
|
|
||||||
|
|
||||||
var v = _verts[i];
|
|
||||||
v.position -= new Vector3(offsetX, 0);
|
|
||||||
_verts[i] = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public float Layout(char c, float offset, float scale)
|
|
||||||
{
|
|
||||||
if (_charInfos == null) return offset;
|
|
||||||
if (c < 0x20 || 0x7e < c) return offset;
|
|
||||||
var ci = c - 0x20;
|
|
||||||
|
|
||||||
return offset + _charInfos[ci].charWidth * scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float Append(VertexHelper toFill, char c, float offset, float scale, Color color)
|
|
||||||
{
|
|
||||||
if (_verts == null || _charInfos == null) return offset;
|
|
||||||
if (c < 0x20 || 0x7e < c) return offset;
|
|
||||||
var ci = c - 0x20;
|
|
||||||
|
|
||||||
for (var i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
_tmpVerts[i] = _verts[ci * 4 + i];
|
|
||||||
_tmpVerts[i].position = _tmpVerts[i].position * scale + new Vector3(offset, 0);
|
|
||||||
_tmpVerts[i].color = ci == 0 ? Color.clear : color;
|
|
||||||
}
|
|
||||||
|
|
||||||
toFill.AddUIVertexQuad(_tmpVerts);
|
|
||||||
return offset + _charInfos[ci].charWidth * scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Fill(VertexHelper toFill, Color color, RectTransform tr)
|
|
||||||
{
|
|
||||||
if (_verts == null || _charInfos == null) return;
|
|
||||||
const int ci = '*' - 0x20;
|
|
||||||
var uv = (_verts[ci * 4].uv0 + _verts[ci * 4 + 2].uv0) / 2;
|
|
||||||
|
|
||||||
var rect = tr.rect;
|
|
||||||
var size = rect.size / 2;
|
|
||||||
var offset = (new Vector2(0.5f, 0.5f) - tr.pivot) * rect.size;
|
|
||||||
|
|
||||||
for (var i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
_tmpVerts[i] = new UIVertex();
|
|
||||||
_tmpVerts[i].uv0 = uv;
|
|
||||||
_tmpVerts[i].color = color;
|
|
||||||
|
|
||||||
if (i == 0)
|
|
||||||
_tmpVerts[i].position = new Vector2(-size.x, -size.y) + offset;
|
|
||||||
else if (i == 1)
|
|
||||||
_tmpVerts[i].position = new Vector2(-size.x, size.y) + offset;
|
|
||||||
else if (i == 2)
|
|
||||||
_tmpVerts[i].position = new Vector2(size.x, size.y) + offset;
|
|
||||||
else
|
|
||||||
_tmpVerts[i].position = new Vector2(size.x, -size.y) + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
toFill.AddUIVertexQuad(_tmpVerts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 9a8c5c555d4bf4361ab3435c318c0699
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences:
|
|
||||||
- m_Material: {fileID: 2100000, guid: 4da4639f724144ddead57bffca64e71f, type: 3}
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,236 +0,0 @@
|
|||||||
using System.Text;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.UI;
|
|
||||||
|
|
||||||
namespace Coffee.NanoMonitor{
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
using UnityEditor;
|
|
||||||
|
|
||||||
[CustomEditor(typeof(MonitorUI))]
|
|
||||||
public class MonitorTextEditor : Editor
|
|
||||||
{
|
|
||||||
private SerializedProperty m_Mode;
|
|
||||||
private SerializedProperty m_TextAnchor;
|
|
||||||
private SerializedProperty m_FontSize;
|
|
||||||
private SerializedProperty m_Font;
|
|
||||||
private SerializedProperty m_Text;
|
|
||||||
private SerializedProperty m_Color;
|
|
||||||
|
|
||||||
private void OnEnable()
|
|
||||||
{
|
|
||||||
m_Mode = serializedObject.FindProperty("m_Mode");
|
|
||||||
|
|
||||||
m_Text = serializedObject.FindProperty("m_Text");
|
|
||||||
m_Color = serializedObject.FindProperty("m_Color");
|
|
||||||
var fontData = serializedObject.FindProperty("m_FontData");
|
|
||||||
m_FontSize = fontData.FindPropertyRelative("m_FontSize");
|
|
||||||
m_Font = fontData.FindPropertyRelative("m_Font");
|
|
||||||
m_TextAnchor = serializedObject.FindProperty("m_TextAnchor");
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnInspectorGUI()
|
|
||||||
{
|
|
||||||
serializedObject.Update();
|
|
||||||
|
|
||||||
EditorGUILayout.PropertyField(m_Mode);
|
|
||||||
if ((MonitorUI.Mode) m_Mode.intValue == MonitorUI.Mode.Text)
|
|
||||||
{
|
|
||||||
EditorGUILayout.PropertyField(m_Text);
|
|
||||||
EditorGUILayout.PropertyField(m_FontSize);
|
|
||||||
EditorGUILayout.PropertyField(m_TextAnchor);
|
|
||||||
|
|
||||||
//EditorGUI.BeginDisabledGroup(true);
|
|
||||||
EditorGUILayout.PropertyField(m_Font);
|
|
||||||
//EditorGUI.EndDisabledGroup();
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorGUILayout.PropertyField(m_Color);
|
|
||||||
|
|
||||||
serializedObject.ApplyModifiedProperties();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public class MonitorUI : Text
|
|
||||||
{
|
|
||||||
public enum Mode
|
|
||||||
{
|
|
||||||
Text,
|
|
||||||
Fill,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TextAnchor
|
|
||||||
{
|
|
||||||
Left,
|
|
||||||
Center,
|
|
||||||
Right
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//################################
|
|
||||||
// Serialize Members.
|
|
||||||
//################################
|
|
||||||
[SerializeField] private Mode m_Mode = Mode.Text;
|
|
||||||
[SerializeField] private TextAnchor m_TextAnchor;
|
|
||||||
|
|
||||||
|
|
||||||
//################################
|
|
||||||
// Public Members.
|
|
||||||
//################################
|
|
||||||
public override string text
|
|
||||||
{
|
|
||||||
get => m_StringBuilder.ToString();
|
|
||||||
set
|
|
||||||
{
|
|
||||||
m_Text = value;
|
|
||||||
if (m_StringBuilder.IsEqual(m_Text)) return;
|
|
||||||
|
|
||||||
m_StringBuilder.Length = 0;
|
|
||||||
m_StringBuilder.Append(m_Text);
|
|
||||||
SetVerticesDirty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextAnchor textAnchor
|
|
||||||
{
|
|
||||||
get => m_TextAnchor;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (m_TextAnchor == value) return;
|
|
||||||
|
|
||||||
m_TextAnchor = value;
|
|
||||||
SetVerticesDirty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool raycastTarget
|
|
||||||
{
|
|
||||||
get => m_Mode == Mode.Fill;
|
|
||||||
set { }
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetText(string format, double arg0 = 0, double arg1 = 0, double arg2 = 0, double arg3 = 0)
|
|
||||||
{
|
|
||||||
m_StringBuilder.Length = 0;
|
|
||||||
m_StringBuilder.AppendFormatNoAlloc(format, arg0, arg1, arg2, arg3);
|
|
||||||
SetVerticesDirty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetText(StringBuilder builder)
|
|
||||||
{
|
|
||||||
m_StringBuilder.Length = 0;
|
|
||||||
m_StringBuilder.Append(builder);
|
|
||||||
SetVerticesDirty();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//################################
|
|
||||||
// Private Members.
|
|
||||||
//################################
|
|
||||||
private readonly StringBuilder m_StringBuilder = new StringBuilder(64);
|
|
||||||
|
|
||||||
private void UpdateFont()
|
|
||||||
{
|
|
||||||
//var globalFont = NNanoMonitorttings.Instance.font;
|
|
||||||
//if (globalFont)
|
|
||||||
//{
|
|
||||||
// font = globalFont;
|
|
||||||
//}
|
|
||||||
|
|
||||||
var fontData = FixedFont.GetOrCreate(font);
|
|
||||||
if (fontData != null)
|
|
||||||
{
|
|
||||||
fontData.Invalidate();
|
|
||||||
fontData.UpdateFont();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//################################
|
|
||||||
// Unity Callbacks.
|
|
||||||
//################################
|
|
||||||
protected override void OnEnable()
|
|
||||||
{
|
|
||||||
//NaNanoMonitortings.Instance.onFontChanged += UpdateFont;
|
|
||||||
RegisterDirtyMaterialCallback(UpdateFont);
|
|
||||||
|
|
||||||
base.OnEnable();
|
|
||||||
raycastTarget = false;
|
|
||||||
maskable = false;
|
|
||||||
m_StringBuilder.Length = 0;
|
|
||||||
m_StringBuilder.Append(m_Text);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnDisable()
|
|
||||||
{
|
|
||||||
//NanNanoMonitorings.Instance.onFontChanged -= UpdateFont;
|
|
||||||
UnregisterDirtyMaterialCallback(UpdateFont);
|
|
||||||
|
|
||||||
base.OnDisable();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
protected override void OnValidate()
|
|
||||||
{
|
|
||||||
base.OnValidate();
|
|
||||||
|
|
||||||
if (!m_StringBuilder.IsEqual(m_Text))
|
|
||||||
{
|
|
||||||
m_StringBuilder.Length = 0;
|
|
||||||
m_StringBuilder.Append(m_Text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
protected override void OnPopulateMesh(VertexHelper toFill)
|
|
||||||
{
|
|
||||||
toFill.Clear();
|
|
||||||
|
|
||||||
var fontData = FixedFont.GetOrCreate(font);
|
|
||||||
if (fontData == null) return;
|
|
||||||
|
|
||||||
fontData.UpdateFont();
|
|
||||||
|
|
||||||
if (m_Mode == Mode.Fill)
|
|
||||||
{
|
|
||||||
fontData.Fill(toFill, color, rectTransform);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var scale = (float) fontSize / fontData.fontSize;
|
|
||||||
float offset = 0;
|
|
||||||
switch (textAnchor)
|
|
||||||
{
|
|
||||||
case TextAnchor.Left:
|
|
||||||
offset = rectTransform.rect.xMin;
|
|
||||||
break;
|
|
||||||
case TextAnchor.Center:
|
|
||||||
for (var i = 0; i < m_StringBuilder.Length; i++)
|
|
||||||
offset = fontData.Layout(m_StringBuilder[i], offset, scale);
|
|
||||||
offset = -offset / 2;
|
|
||||||
break;
|
|
||||||
case TextAnchor.Right:
|
|
||||||
for (var i = 0; i < m_StringBuilder.Length; i++)
|
|
||||||
offset = fontData.Layout(m_StringBuilder[i], offset, scale);
|
|
||||||
offset = rectTransform.rect.xMax - offset;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < m_StringBuilder.Length; i++)
|
|
||||||
{
|
|
||||||
offset = fontData.Append(toFill, m_StringBuilder[i], offset, scale, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void UpdateMaterial()
|
|
||||||
{
|
|
||||||
base.UpdateMaterial();
|
|
||||||
|
|
||||||
var fontData = FixedFont.GetOrCreate(font);
|
|
||||||
if (fontData != null)
|
|
||||||
{
|
|
||||||
fontData.UpdateFont();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: b0e08c6080a2e4d8186f97c60518830f
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences:
|
|
||||||
- m_Material: {fileID: 2100000, guid: 4da4639f724144ddead57bffca64e71f, type: 3}
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.SceneManagement;
|
|
||||||
|
|
||||||
namespace Coffee.MiniProfiler
|
|
||||||
{
|
|
||||||
internal class MiniProfilerSettings : ScriptableSettings<MiniProfilerSettings>
|
|
||||||
{
|
|
||||||
[Header("UI")]
|
|
||||||
[SerializeField] private Font m_Font = null;
|
|
||||||
|
|
||||||
[Header("Instantiate On Boot")]
|
|
||||||
[SerializeField] private GameObject miniProfilerPrefab = null;
|
|
||||||
[SerializeField] private string[] m_SceneNames = new string[0];
|
|
||||||
|
|
||||||
public Font font => m_Font;
|
|
||||||
public event Action onFontChanged;
|
|
||||||
|
|
||||||
protected override void OnBoot()
|
|
||||||
{
|
|
||||||
SceneManager.sceneLoaded -= OnSceneLoaded;
|
|
||||||
SceneManager.sceneLoaded += OnSceneLoaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnSceneLoaded(Scene scene, LoadSceneMode __)
|
|
||||||
{
|
|
||||||
SceneManager.sceneLoaded -= OnSceneLoaded;
|
|
||||||
if (!miniProfilerPrefab || !m_SceneNames.Contains(scene.name)) return;
|
|
||||||
|
|
||||||
var go = Instantiate(miniProfilerPrefab);
|
|
||||||
if (Application.isPlaying)
|
|
||||||
DontDestroyOnLoad(go);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool bootOnPlayMode => true;
|
|
||||||
protected override bool bootOnEditorMode => false;
|
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
protected override void OnValidate()
|
|
||||||
{
|
|
||||||
onFontChanged?.Invoke();
|
|
||||||
base.OnValidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Reset()
|
|
||||||
{
|
|
||||||
m_Font = UnityEngine.Resources.GetBuiltinResource<Font>("Arial.ttf");
|
|
||||||
}
|
|
||||||
|
|
||||||
[UnityEditor.SettingsProvider]
|
|
||||||
private static UnityEditor.SettingsProvider CreateSettingsProvider() => new ScriptableSettingsProvider<MiniProfilerSettings>();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 647dad4f8226a49b9874b68b79413d64
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences:
|
|
||||||
- miniProfilerPrefab: {fileID: 7211429669315726685, guid: 784696794bc6345bc80bf49623581c2e,
|
|
||||||
type: 3}
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,280 +0,0 @@
|
|||||||
using UnityEngine;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
using UnityEditor;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Coffee.MiniProfiler
|
|
||||||
{
|
|
||||||
internal abstract class ScriptableSettings : ScriptableObject
|
|
||||||
{
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
public virtual string GetSettingPath()
|
|
||||||
{
|
|
||||||
return GetSettingPath(GetType());
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static string GetSettingPath(Type type)
|
|
||||||
{
|
|
||||||
return $"Project/{ObjectNames.NicifyVariableName(type.Name.Replace("ProjectSettings", ""))}";
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public virtual string GetDefaultAssetPath()
|
|
||||||
{
|
|
||||||
return $"Assets/ProjectSettings/{GetType().Name}.asset";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal abstract class ScriptableSettings<T> : ScriptableSettings
|
|
||||||
where T : ScriptableSettings<T>
|
|
||||||
{
|
|
||||||
//################################
|
|
||||||
// Public Members.
|
|
||||||
//################################
|
|
||||||
public static T Instance => _instance ? _instance : _instance = GetOrCreate();
|
|
||||||
|
|
||||||
private static T _instance;
|
|
||||||
|
|
||||||
protected virtual bool bootOnEditorMode => true;
|
|
||||||
protected virtual bool bootOnPlayMode => true;
|
|
||||||
|
|
||||||
protected abstract void OnBoot();
|
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
//################################
|
|
||||||
// Private Members.
|
|
||||||
//################################
|
|
||||||
private bool enabled;
|
|
||||||
|
|
||||||
private static T GetOrCreate()
|
|
||||||
{
|
|
||||||
return PlayerSettings.GetPreloadedAssets()
|
|
||||||
.OfType<T>()
|
|
||||||
.FirstOrDefault() ?? CreateInstance<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPlayModeStateChanged(PlayModeStateChange state)
|
|
||||||
{
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case PlayModeStateChange.EnteredEditMode:
|
|
||||||
enabled = true;
|
|
||||||
Boot();
|
|
||||||
break;
|
|
||||||
case PlayModeStateChange.ExitingEditMode:
|
|
||||||
case PlayModeStateChange.ExitingPlayMode:
|
|
||||||
enabled = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Boot()
|
|
||||||
{
|
|
||||||
var preloadedAssets = PlayerSettings.GetPreloadedAssets();
|
|
||||||
var assets = preloadedAssets.OfType<T>().ToArray();
|
|
||||||
var first = assets.FirstOrDefault() ?? this as T;
|
|
||||||
|
|
||||||
// If there are no preloaded assets, registry the first asset.
|
|
||||||
// If there are multiple preloaded assets, unregisters all but the first one.
|
|
||||||
if (assets.Length != 1)
|
|
||||||
{
|
|
||||||
// The first asset is not saved.
|
|
||||||
if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(first)))
|
|
||||||
{
|
|
||||||
if (!AssetDatabase.IsValidFolder("Assets/ProjectSettings"))
|
|
||||||
AssetDatabase.CreateFolder("Assets", "ProjectSettings");
|
|
||||||
|
|
||||||
var assetName = ObjectNames.NicifyVariableName(first.GetType().Name.Replace("ProjectSettings", ""));
|
|
||||||
var assetPath = AssetDatabase.GenerateUniqueAssetPath($"Assets/ProjectSettings/{assetName}.asset");
|
|
||||||
AssetDatabase.CreateAsset(first, assetPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
PlayerSettings.SetPreloadedAssets(preloadedAssets
|
|
||||||
.Where(x => x)
|
|
||||||
.Except(assets)
|
|
||||||
.Concat(new[] {first})
|
|
||||||
.ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Another asset is registered as a preload asset.
|
|
||||||
if (first != this)
|
|
||||||
{
|
|
||||||
UnityEngine.Debug.LogError($"Another asset '{first}' is registered as a preload '{typeof(T).Name}' asset." +
|
|
||||||
$"\nThis instance ('{this}') will be ignored. Check 'Project Settings > Player > Preload Assets'", this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_instance = first;
|
|
||||||
|
|
||||||
// Do nothing on editor mode.
|
|
||||||
if (!bootOnEditorMode && !EditorApplication.isPlayingOrWillChangePlaymode)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do nothing on play mode.
|
|
||||||
if (!bootOnPlayMode && EditorApplication.isPlayingOrWillChangePlaymode)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OnBoot();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//################################
|
|
||||||
// Unity Callbacks.
|
|
||||||
//################################
|
|
||||||
private void OnEnable()
|
|
||||||
{
|
|
||||||
enabled = true;
|
|
||||||
Boot();
|
|
||||||
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDisable()
|
|
||||||
{
|
|
||||||
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void OnValidate()
|
|
||||||
{
|
|
||||||
if (enabled)
|
|
||||||
Boot();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
private static T GetOrCreate()
|
|
||||||
{
|
|
||||||
return CreateInstance<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnEnable()
|
|
||||||
{
|
|
||||||
if (!bootOnPlayMode) return;
|
|
||||||
|
|
||||||
_instance = this as T;
|
|
||||||
OnBoot();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
[CustomEditor(typeof(ScriptablePreferenceSettings<>), true)]
|
|
||||||
internal class ScriptablePreferenceSettingsEditor : Editor
|
|
||||||
{
|
|
||||||
private static readonly GUIContent _button = new GUIContent("Open Project Settings");
|
|
||||||
|
|
||||||
public override void OnInspectorGUI()
|
|
||||||
{
|
|
||||||
if (GUILayout.Button(_button))
|
|
||||||
{
|
|
||||||
SettingsService.OpenProjectSettings(((ScriptableSettings) target).GetSettingPath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal abstract class ScriptablePreferenceSettings<T> : ScriptableSingleton<T>
|
|
||||||
where T : ScriptablePreferenceSettings<T>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
[CustomEditor(typeof(ScriptableSettings), true)]
|
|
||||||
internal class ScriptableSettingsEditor : Editor
|
|
||||||
{
|
|
||||||
private static readonly GUIContent _button = new GUIContent("Open Project Settings");
|
|
||||||
|
|
||||||
public override void OnInspectorGUI()
|
|
||||||
{
|
|
||||||
if (GUILayout.Button(_button))
|
|
||||||
{
|
|
||||||
SettingsService.OpenProjectSettings(((ScriptableSettings) target).GetSettingPath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class ScriptableSettingsProvider<T> : SettingsProvider where T : ScriptableSettings<T>
|
|
||||||
{
|
|
||||||
public ScriptableSettingsProvider(string path) : base(path)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public ScriptableSettingsProvider() : base(ScriptableSettings.GetSettingPath(typeof(T)))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected SerializedObject serializedObject { get; private set; }
|
|
||||||
protected ScriptableSettings<T> target { get; private set; }
|
|
||||||
|
|
||||||
public sealed override void OnGUI(string searchContext)
|
|
||||||
{
|
|
||||||
if (!target)
|
|
||||||
{
|
|
||||||
target = ScriptableSettings<T>.Instance;
|
|
||||||
serializedObject = new SerializedObject(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
OnGUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void OnGUI()
|
|
||||||
{
|
|
||||||
serializedObject.UpdateIfRequiredOrScript();
|
|
||||||
var iterator = serializedObject.GetIterator();
|
|
||||||
var enterChildren = true;
|
|
||||||
while (iterator.NextVisible(enterChildren))
|
|
||||||
{
|
|
||||||
if (iterator.propertyPath != "m_Script")
|
|
||||||
EditorGUILayout.PropertyField(iterator, true);
|
|
||||||
|
|
||||||
enterChildren = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
serializedObject.ApplyModifiedProperties();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class ScriptablePreferenceSettingsProvider<T> : SettingsProvider where T : ScriptableSettings<T>
|
|
||||||
{
|
|
||||||
public ScriptablePreferenceSettingsProvider(string path) : base(path, SettingsScope.User)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public ScriptablePreferenceSettingsProvider() : base(ScriptableSettings.GetSettingPath(typeof(T)), SettingsScope.User)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected SerializedObject serializedObject { get; private set; }
|
|
||||||
protected ScriptableSettings<T> target { get; private set; }
|
|
||||||
|
|
||||||
public sealed override void OnGUI(string searchContext)
|
|
||||||
{
|
|
||||||
if (!target)
|
|
||||||
{
|
|
||||||
target = ScriptableSettings<T>.Instance;
|
|
||||||
serializedObject = new SerializedObject(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
OnGUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void OnGUI()
|
|
||||||
{
|
|
||||||
serializedObject.UpdateIfRequiredOrScript();
|
|
||||||
var iterator = serializedObject.GetIterator();
|
|
||||||
var enterChildren = true;
|
|
||||||
while (iterator.NextVisible(enterChildren))
|
|
||||||
{
|
|
||||||
if (iterator.propertyPath != "m_Script")
|
|
||||||
EditorGUILayout.PropertyField(iterator, true);
|
|
||||||
|
|
||||||
enterChildren = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
serializedObject.ApplyModifiedProperties();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 6ea9606f69cee413e9f96f52de99fa5e
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 1051ed7e3f1474ed59ca41b33b00029b
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
using UnityEngine;
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
using UnityEditor;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Coffee.NanoMonitor
|
|
||||||
{
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
[CustomPropertyDrawer(typeof(CustomMonitorItem))]
|
|
||||||
internal sealed class CustomMonitorItemDrawer : PropertyDrawer
|
|
||||||
{
|
|
||||||
public override void OnGUI(Rect p, SerializedProperty property, GUIContent label)
|
|
||||||
{
|
|
||||||
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 0, p.width, 16), property.FindPropertyRelative("m_Text"));
|
|
||||||
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 1, p.width, 16), property.FindPropertyRelative("m_Format"));
|
|
||||||
EditorGUI.indentLevel++;
|
|
||||||
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 2, p.width, 16), property.FindPropertyRelative("m_Arg0"));
|
|
||||||
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 3, p.width, 16), property.FindPropertyRelative("m_Arg1"));
|
|
||||||
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 4, p.width, 16), property.FindPropertyRelative("m_Arg2"));
|
|
||||||
EditorGUI.indentLevel--;
|
|
||||||
|
|
||||||
property.serializedObject.ApplyModifiedProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
|
||||||
{
|
|
||||||
return (EditorGUIUtility.singleLineHeight + 2) * 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
[System.Serializable]
|
|
||||||
public class CustomMonitorItem
|
|
||||||
{
|
|
||||||
[SerializeField] private MonitorUI m_Text = null;
|
|
||||||
[SerializeField] private string m_Format = "";
|
|
||||||
[SerializeField] private NumericProperty m_Arg0 = null;
|
|
||||||
[SerializeField] private NumericProperty m_Arg1 = null;
|
|
||||||
[SerializeField] private NumericProperty m_Arg2 = null;
|
|
||||||
|
|
||||||
public void UpdateText()
|
|
||||||
{
|
|
||||||
if (m_Text)
|
|
||||||
m_Text.SetText(m_Format, m_Arg0.Get(), m_Arg1.Get(), m_Arg2.Get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 5c50c6434f4ad4488bfc5b0928dbb4c4
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,199 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.Serialization;
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
using UnityEditor;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Coffee.NanoMonitor
|
|
||||||
{
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
[CustomPropertyDrawer(typeof(NumericProperty))]
|
|
||||||
internal sealed class NumericPropertyDrawer : PropertyDrawer
|
|
||||||
{
|
|
||||||
private static Action<PropertyInfo> s_OnMenuSelected;
|
|
||||||
private static GenericMenu s_PropertyMenu;
|
|
||||||
|
|
||||||
private static readonly Dictionary<Type, string> s_SupportedTypes = new Dictionary<Type, string>
|
|
||||||
{
|
|
||||||
{typeof(bool), "bool"},
|
|
||||||
{typeof(sbyte), "sbyte"},
|
|
||||||
{typeof(short), "short"},
|
|
||||||
{typeof(int), "int"},
|
|
||||||
{typeof(long), "long"},
|
|
||||||
{typeof(byte), "byte"},
|
|
||||||
{typeof(ushort), "ushort"},
|
|
||||||
{typeof(uint), "uint"},
|
|
||||||
{typeof(ulong), "ulong"},
|
|
||||||
{typeof(float), "float"},
|
|
||||||
{typeof(double), "double"},
|
|
||||||
{typeof(decimal), "decimal"},
|
|
||||||
};
|
|
||||||
|
|
||||||
private static void Init()
|
|
||||||
{
|
|
||||||
if (s_PropertyMenu != null) return;
|
|
||||||
|
|
||||||
var properties = AppDomain.CurrentDomain.GetAssemblies()
|
|
||||||
.SelectMany(assembly => assembly.GetTypes())
|
|
||||||
.SelectMany(type => type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetProperty))
|
|
||||||
.Where(pi => pi.GetMethod != null && s_SupportedTypes.ContainsKey(pi.PropertyType))
|
|
||||||
.OrderBy(pi => ConvertToMenuItem(pi, false))
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
s_PropertyMenu = new GenericMenu();
|
|
||||||
s_PropertyMenu.AddItem(new GUIContent("No Property"), false, arg => s_OnMenuSelected?.Invoke(arg as PropertyInfo), null);
|
|
||||||
s_PropertyMenu.AddItem(new GUIContent("(Non Public Properties)/"), false, ()=>{});
|
|
||||||
s_PropertyMenu.AddSeparator("");
|
|
||||||
|
|
||||||
foreach (var pi in properties)
|
|
||||||
{
|
|
||||||
s_PropertyMenu.AddItem(new GUIContent(ConvertToMenuItem(pi, true)), false, arg => s_OnMenuSelected?.Invoke(arg as PropertyInfo), pi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ConvertToMenuItem(PropertyInfo p, bool propertyType)
|
|
||||||
{
|
|
||||||
var type = p.DeclaringType;
|
|
||||||
if (type == null) return "";
|
|
||||||
var category = p.GetMethod.IsPublic && type.IsPublic ? "" : "(Non Public Properties)/";
|
|
||||||
var typeName = type.FullName;
|
|
||||||
var asmName = type.Assembly.GetName().Name;
|
|
||||||
if (asmName == "UnityEngine.CoreModule")
|
|
||||||
asmName = "UnityEngine";
|
|
||||||
return propertyType
|
|
||||||
? $"{category}{asmName}/{typeName}/{s_SupportedTypes[p.PropertyType]} {p.Name}"
|
|
||||||
: $"{category}{asmName}/{typeName}/{p.Name}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
|
||||||
{
|
|
||||||
Init();
|
|
||||||
label = EditorGUI.BeginProperty(position, label, property);
|
|
||||||
|
|
||||||
var path = property.FindPropertyRelative("m_Path");
|
|
||||||
var split = path.stringValue.Split(';', ' ', ',');
|
|
||||||
var name = split.Length == 4 ? $"{split[0]}.{split[3]}" : "No Property";
|
|
||||||
|
|
||||||
position = EditorGUI.PrefixLabel(position, label);
|
|
||||||
if (GUI.Button(position, name, EditorStyles.popup))
|
|
||||||
{
|
|
||||||
s_OnMenuSelected = p =>
|
|
||||||
{
|
|
||||||
path.stringValue = p == null ? "" : $"{p.DeclaringType?.FullName}, {p.DeclaringType?.Assembly.GetName().Name};{p.Name}";
|
|
||||||
property.serializedObject.ApplyModifiedProperties();
|
|
||||||
};
|
|
||||||
s_PropertyMenu.DropDown(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorGUI.EndProperty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class NumericProperty : ISerializationCallbackReceiver
|
|
||||||
{
|
|
||||||
//################################
|
|
||||||
// Serialized Members.
|
|
||||||
//################################
|
|
||||||
[SerializeField] private string m_Path = "";
|
|
||||||
|
|
||||||
|
|
||||||
//################################
|
|
||||||
// Public Members.
|
|
||||||
//################################
|
|
||||||
public double Get()
|
|
||||||
{
|
|
||||||
return _get?.Invoke() ?? -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//################################
|
|
||||||
// Private Members.
|
|
||||||
//################################
|
|
||||||
private Func<double> _get = null;
|
|
||||||
|
|
||||||
private static PropertyInfo GetPropertyInfo(string path)
|
|
||||||
{
|
|
||||||
var p = path.Split(';');
|
|
||||||
if (p.Length != 2) return null;
|
|
||||||
|
|
||||||
var type = Type.GetType(p[0]);
|
|
||||||
if (type == null)
|
|
||||||
{
|
|
||||||
UnityEngine.Debug.LogException(new Exception($"Type '{p[0]}' is not found"));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var pInfo = type.GetProperty(p[1], BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Static);
|
|
||||||
if (pInfo == null)
|
|
||||||
{
|
|
||||||
UnityEngine.Debug.LogException(new Exception($"Member '{p[1]}' is not found in type '{type}'"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return pInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Func<double> CreateFunc(MethodInfo mInfo)
|
|
||||||
{
|
|
||||||
if (mInfo == null) return null;
|
|
||||||
switch (Type.GetTypeCode(mInfo.ReturnType))
|
|
||||||
{
|
|
||||||
case TypeCode.Boolean:
|
|
||||||
var f_bool = (Func<bool>) mInfo.CreateDelegate(typeof(Func<bool>));
|
|
||||||
return () => f_bool() ? 1 : 0;
|
|
||||||
case TypeCode.Byte:
|
|
||||||
var f_byte = (Func<byte>) mInfo.CreateDelegate(typeof(Func<byte>));
|
|
||||||
return () => f_byte();
|
|
||||||
case TypeCode.SByte:
|
|
||||||
var f_sbyte = (Func<sbyte>) mInfo.CreateDelegate(typeof(Func<sbyte>));
|
|
||||||
return () => f_sbyte();
|
|
||||||
case TypeCode.UInt16:
|
|
||||||
var f_ushort = (Func<ushort>) mInfo.CreateDelegate(typeof(Func<ushort>));
|
|
||||||
return () => f_ushort();
|
|
||||||
case TypeCode.UInt32:
|
|
||||||
var f_uint = (Func<uint>) mInfo.CreateDelegate(typeof(Func<uint>));
|
|
||||||
return () => f_uint();
|
|
||||||
case TypeCode.UInt64:
|
|
||||||
var f_ulong = (Func<ulong>) mInfo.CreateDelegate(typeof(Func<ulong>));
|
|
||||||
return () => f_ulong();
|
|
||||||
case TypeCode.Int16:
|
|
||||||
var f_short = (Func<short>) mInfo.CreateDelegate(typeof(Func<short>));
|
|
||||||
return () => f_short();
|
|
||||||
case TypeCode.Int32:
|
|
||||||
var f_int = (Func<int>) mInfo.CreateDelegate(typeof(Func<int>));
|
|
||||||
return () => f_int();
|
|
||||||
case TypeCode.Int64:
|
|
||||||
var f_long = (Func<long>) mInfo.CreateDelegate(typeof(Func<long>));
|
|
||||||
return () => f_long();
|
|
||||||
case TypeCode.Decimal:
|
|
||||||
var f_decimal = (Func<decimal>) mInfo.CreateDelegate(typeof(Func<decimal>));
|
|
||||||
return () => (double) f_decimal();
|
|
||||||
case TypeCode.Double:
|
|
||||||
var f_double = (Func<double>) mInfo.CreateDelegate(typeof(Func<double>));
|
|
||||||
return f_double;
|
|
||||||
case TypeCode.Single:
|
|
||||||
var f_float = (Func<float>) mInfo.CreateDelegate(typeof(Func<float>));
|
|
||||||
return () => f_float();
|
|
||||||
default:
|
|
||||||
UnityEngine.Debug.LogException(new Exception(string.Format("Method '{1}.{0}' is not supported.", mInfo.Name, mInfo.DeclaringType)));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ISerializationCallbackReceiver.OnAfterDeserialize()
|
|
||||||
{
|
|
||||||
var pInfo = GetPropertyInfo(m_Path);
|
|
||||||
_get = CreateFunc(pInfo?.GetMethod);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 87fefa9f373e8411596b00238a65f3c3
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,236 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("Coffee.NanoMonitor.Tests")]
|
|
||||||
|
|
||||||
namespace Coffee.NanoMonitor
|
|
||||||
{
|
|
||||||
internal static class StringBuilderExtensions
|
|
||||||
{
|
|
||||||
public static bool IsEqual(this StringBuilder sb, string other)
|
|
||||||
{
|
|
||||||
if (sb == null || other == null) return false;
|
|
||||||
if (sb.Length != other.Length) return false;
|
|
||||||
|
|
||||||
for (var i = 0; i < sb.Length; i++)
|
|
||||||
{
|
|
||||||
if (sb[i] != other[i]) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void AppendFormatNoAlloc(this StringBuilder sb, string format, double arg0 = 0, double arg1 = 0, double arg2 = 0, double arg3 = 0)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < format.Length; i++)
|
|
||||||
{
|
|
||||||
var c = format[i];
|
|
||||||
|
|
||||||
// Append formatted value
|
|
||||||
if (c == '{')
|
|
||||||
{
|
|
||||||
i = GetFormat(format, i, out var argIndex, out var padding, out var precision, out var alignment);
|
|
||||||
|
|
||||||
switch (argIndex)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
sb.AppendDouble(arg0, padding, precision, alignment);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
sb.AppendDouble(arg1, padding, precision, alignment);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
sb.AppendDouble(arg2, padding, precision, alignment);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
sb.AppendDouble(arg3, padding, precision, alignment);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append character
|
|
||||||
sb.Append(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void AppendInteger(this StringBuilder sb, double number, int padding, int precision, int alignment)
|
|
||||||
{
|
|
||||||
number = Math.Truncate(number);
|
|
||||||
var sign = number < 0;
|
|
||||||
number = sign ? -number : number;
|
|
||||||
|
|
||||||
var startIndex = sb.Length;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
var n = Math.Truncate(number % 10);
|
|
||||||
number /= 10;
|
|
||||||
|
|
||||||
sb.Append((char) (n + 48));
|
|
||||||
} while (1 <= number || (sb.Length - startIndex) < padding);
|
|
||||||
|
|
||||||
if (sign)
|
|
||||||
{
|
|
||||||
sb.Append('-');
|
|
||||||
}
|
|
||||||
|
|
||||||
var endIndex = sb.Length - 1;
|
|
||||||
|
|
||||||
sb.Reverse(startIndex, endIndex);
|
|
||||||
sb.Alignment(alignment, startIndex, endIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void AppendDouble(this StringBuilder sb, double number, int padding, int precision, int alignment)
|
|
||||||
{
|
|
||||||
var integer = Math.Truncate(number);
|
|
||||||
var startIndex = sb.Length;
|
|
||||||
sb.AppendInteger(integer, padding, precision, 0);
|
|
||||||
|
|
||||||
if (0 < precision)
|
|
||||||
{
|
|
||||||
sb.Append('.');
|
|
||||||
number -= integer;
|
|
||||||
number = Math.Round(number, precision);
|
|
||||||
for (var p = 0; p < precision; p++)
|
|
||||||
{
|
|
||||||
number *= 10;
|
|
||||||
integer = (long) number;
|
|
||||||
sb.Append((char) (integer + 48));
|
|
||||||
number -= integer;
|
|
||||||
number = Math.Round(number, precision);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.Alignment(alignment, startIndex, sb.Length - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void Reverse(this StringBuilder sb, int start, int end)
|
|
||||||
{
|
|
||||||
while (start < end)
|
|
||||||
{
|
|
||||||
var c = sb[start];
|
|
||||||
sb[start] = sb[end];
|
|
||||||
sb[end] = c;
|
|
||||||
|
|
||||||
start++;
|
|
||||||
end--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void Alignment(this StringBuilder sb, int alignment, int start, int end)
|
|
||||||
{
|
|
||||||
if (alignment == 0) return;
|
|
||||||
|
|
||||||
var len = end - start + 1;
|
|
||||||
if (0 < alignment && len < alignment)
|
|
||||||
{
|
|
||||||
sb.Append(' ', alignment - len);
|
|
||||||
for (var i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
var c = sb[end - i];
|
|
||||||
sb[end - i] = sb[start + alignment - i - 1];
|
|
||||||
sb[start + alignment - i - 1] = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (alignment < 0 && len < -alignment)
|
|
||||||
{
|
|
||||||
sb.Append(' ', -alignment - len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static int GetFormat(string format, int i, out int argIndex, out int padding, out int precision, out int alignment)
|
|
||||||
{
|
|
||||||
argIndex = -1;
|
|
||||||
padding = 0;
|
|
||||||
precision = 0;
|
|
||||||
alignment = 0;
|
|
||||||
|
|
||||||
var alignmentSign = false;
|
|
||||||
var readFlag = 0;
|
|
||||||
|
|
||||||
for (; i < format.Length; i++)
|
|
||||||
{
|
|
||||||
var c = format[i];
|
|
||||||
|
|
||||||
// End format
|
|
||||||
if (c == '}')
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start format
|
|
||||||
if (c == '{')
|
|
||||||
{
|
|
||||||
readFlag = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// After '{': Read argument index and format
|
|
||||||
else if (readFlag == 1)
|
|
||||||
{
|
|
||||||
if ('0' <= c && c <= '3')
|
|
||||||
{
|
|
||||||
argIndex = c - 48;
|
|
||||||
}
|
|
||||||
else if (c == ',')
|
|
||||||
{
|
|
||||||
readFlag = 2;
|
|
||||||
}
|
|
||||||
else if (c == ':')
|
|
||||||
{
|
|
||||||
readFlag = 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//After ',': Read alignment value
|
|
||||||
else if (readFlag == 2)
|
|
||||||
{
|
|
||||||
if ('0' <= c && c <= '9')
|
|
||||||
{
|
|
||||||
alignment = alignment * 10 + (alignmentSign ? 48 - c : c - 48);
|
|
||||||
}
|
|
||||||
else if (c == '-')
|
|
||||||
{
|
|
||||||
alignmentSign = true;
|
|
||||||
}
|
|
||||||
else if (c == ':')
|
|
||||||
{
|
|
||||||
readFlag = 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// After ':': Read format for integral
|
|
||||||
else if (readFlag == 3)
|
|
||||||
{
|
|
||||||
if (c == '.')
|
|
||||||
{
|
|
||||||
precision = 0;
|
|
||||||
readFlag = 4;
|
|
||||||
}
|
|
||||||
else if (c == '0')
|
|
||||||
{
|
|
||||||
padding++;
|
|
||||||
}
|
|
||||||
// Legacy mode
|
|
||||||
else if ('1' <= c && c <= '9')
|
|
||||||
{
|
|
||||||
precision = c - 48;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// After '.': Read decimal precision value
|
|
||||||
else if (readFlag == 4)
|
|
||||||
{
|
|
||||||
if (c == '0')
|
|
||||||
{
|
|
||||||
precision++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
argIndex = -1;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 23b4d6d0f5b8644b0981a065d7e47478
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences:
|
|
||||||
- m_Material: {fileID: 2100000, guid: 4da4639f724144ddead57bffca64e71f, type: 3}
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "com.coffee.nano-monitor",
|
|
||||||
"displayName": "Nano Monitor",
|
|
||||||
"description": "This package displays FPS, memory status and any static properties.\n- extremely fast\n- no allocations (on build)\n-1 set pass call only\n- open/close/refresh (GC) buttons",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"unity": "2018.3",
|
|
||||||
"license": "MIT",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/mob-sakai/MaskTweaksForUGUI.git"
|
|
||||||
},
|
|
||||||
"author": "mob-sakai <sakai861104@gmail.com> (https://github.com/mob-sakai)",
|
|
||||||
"dependencies": {},
|
|
||||||
"keywords": [
|
|
||||||
"monitor",
|
|
||||||
"utility"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: be075f23fcc314d319e4f4ebfa6eefdd
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: db256ad6e34f94a4a95dedcbce09ddf1
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Coffee.UIParticle.PerformanceDemo",
|
|
||||||
"references": [
|
|
||||||
"Coffee.UIParticle"
|
|
||||||
],
|
|
||||||
"optionalUnityReferences": [],
|
|
||||||
"includePlatforms": [],
|
|
||||||
"excludePlatforms": [],
|
|
||||||
"allowUnsafeCode": false,
|
|
||||||
"overrideReferences": false,
|
|
||||||
"precompiledReferences": [],
|
|
||||||
"autoReferenced": false,
|
|
||||||
"defineConstraints": []
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 9c1a1a5e813ba46d2b837936f34e33a7
|
|
||||||
AssemblyDefinitionImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Coffee.UIExtensions.Demo
|
|
||||||
{
|
|
||||||
public class UIParticle_PerformanceDemo : MonoBehaviour
|
|
||||||
{
|
|
||||||
public GameObject copyOrigin;
|
|
||||||
public int copyCount;
|
|
||||||
public Canvas root;
|
|
||||||
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
Application.targetFrameRate = 60;
|
|
||||||
|
|
||||||
if (copyOrigin)
|
|
||||||
{
|
|
||||||
copyOrigin.SetActive(false);
|
|
||||||
|
|
||||||
var parent = copyOrigin.transform.parent;
|
|
||||||
for (var i = 0; i < copyCount; i++)
|
|
||||||
{
|
|
||||||
var go = GameObject.Instantiate(copyOrigin, parent, false);
|
|
||||||
go.name = string.Format("{0} {1}", copyOrigin.name, i + 1);
|
|
||||||
go.hideFlags = HideFlags.DontSave;
|
|
||||||
|
|
||||||
go.SetActive(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ChangeScreenSize()
|
|
||||||
{
|
|
||||||
if (Screen.width == 400 && Screen.height == 720)
|
|
||||||
Screen.SetResolution(720, 720, false);
|
|
||||||
else if (Screen.width == 720 && Screen.height == 720)
|
|
||||||
Screen.SetResolution(720, 400, false);
|
|
||||||
else
|
|
||||||
Screen.SetResolution(400, 720, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void EnableAnimations(bool enabled)
|
|
||||||
{
|
|
||||||
foreach (var animator in FindObjectsOfType<Animator>())
|
|
||||||
{
|
|
||||||
animator.enabled = enabled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UIParticle_Enable(bool enabled)
|
|
||||||
{
|
|
||||||
|
|
||||||
foreach (var uip in root.GetComponentsInChildren<UIParticle>(true))
|
|
||||||
{
|
|
||||||
uip.enabled = enabled;
|
|
||||||
}
|
|
||||||
if (!enabled)
|
|
||||||
{
|
|
||||||
foreach (var ps in FindObjectsOfType<ParticleSystem>())
|
|
||||||
{
|
|
||||||
ps.Play(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UIParticle_MeshSharing(bool enabled)
|
|
||||||
{
|
|
||||||
foreach (var uip in root.GetComponentsInChildren<UIParticle>(true))
|
|
||||||
{
|
|
||||||
uip.meshSharing = enabled ? UIParticle.MeshSharing.Auto : UIParticle.MeshSharing.None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UIParticle_RandomGroup(bool enabled)
|
|
||||||
{
|
|
||||||
foreach (var uip in root.GetComponentsInChildren<UIParticle>(true))
|
|
||||||
{
|
|
||||||
uip.groupMaxId = enabled ? 4 : 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UIParticle_Scale(float scale)
|
|
||||||
{
|
|
||||||
foreach (var uip in FindObjectsOfType<UIParticle>())
|
|
||||||
{
|
|
||||||
uip.scale = scale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ParticleSystem_WorldSpaseSimulation(bool enabled)
|
|
||||||
{
|
|
||||||
foreach (var ps in FindObjectsOfType<ParticleSystem>())
|
|
||||||
{
|
|
||||||
var main = ps.main;
|
|
||||||
main.simulationSpace = enabled ? ParticleSystemSimulationSpace.World : ParticleSystemSimulationSpace.Local;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ParticleSystem_SetScale(float scale)
|
|
||||||
{
|
|
||||||
foreach (var ps in FindObjectsOfType<ParticleSystem>())
|
|
||||||
{
|
|
||||||
ps.transform.localScale = new Vector3(scale, scale, scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Canvas_WorldSpace(bool flag)
|
|
||||||
{
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
var canvas = FindObjectOfType<Canvas>();
|
|
||||||
canvas.renderMode = RenderMode.ScreenSpaceCamera;
|
|
||||||
canvas.renderMode = RenderMode.WorldSpace;
|
|
||||||
canvas.transform.rotation = Quaternion.Euler(new Vector3(0, 10, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Canvas_CameraSpace(bool flag)
|
|
||||||
{
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
var canvas = FindObjectOfType<Canvas>();
|
|
||||||
canvas.renderMode = RenderMode.ScreenSpaceCamera;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Canvas_Overlay(bool flag)
|
|
||||||
{
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
var canvas = FindObjectOfType<Canvas>();
|
|
||||||
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 3a595cf9cf93f4e0686f247a5e7e19ce
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: aacefbb114f024ec0bd6d3153b28bb36
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 34 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user