com.wallstop-studios.unity-helpers 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/format-on-demand.yml +2 -2
- package/.github/workflows/markdown-json.yml +1 -1
- package/.github/workflows/npm-publish.yml +1 -1
- package/.github/workflows/prettier-autofix.yml +4 -4
- package/.github/workflows/yaml-format-lint.yml +1 -1
- package/Docs/EFFECTS_SYSTEM.md +1316 -0
- package/{EFFECTS_SYSTEM_TUTORIAL.md → Docs/EFFECTS_SYSTEM_TUTORIAL.md} +1 -1
- package/{GETTING_STARTED.md → Docs/GETTING_STARTED.md} +10 -8
- package/{GLOSSARY.md → Docs/GLOSSARY.md} +4 -4
- package/Docs/HELPER_UTILITIES.md +885 -0
- package/Docs/HELPER_UTILITIES.md.meta +7 -0
- package/{INDEX.md → Docs/INDEX.md} +107 -62
- package/Docs/MATH_AND_EXTENSIONS.md +1039 -0
- package/{RANDOM_PERFORMANCE.md → Docs/RANDOM_PERFORMANCE.md} +15 -15
- package/{RELATIONAL_COMPONENTS.md → Docs/RELATIONAL_COMPONENTS.md} +21 -3
- package/{SPATIAL_TREES_2D_GUIDE.md → Docs/SPATIAL_TREES_2D_GUIDE.md} +2 -2
- package/{SPATIAL_TREES_3D_GUIDE.md → Docs/SPATIAL_TREES_3D_GUIDE.md} +1 -1
- package/{SPATIAL_TREE_2D_PERFORMANCE.md → Docs/SPATIAL_TREE_2D_PERFORMANCE.md} +64 -64
- package/{SPATIAL_TREE_3D_PERFORMANCE.md → Docs/SPATIAL_TREE_3D_PERFORMANCE.md} +64 -64
- package/Docs/UTILITY_COMPONENTS.md +906 -0
- package/Docs/UTILITY_COMPONENTS.md.meta +7 -0
- package/Docs/VISUAL_COMPONENTS.md +337 -0
- package/Docs/VISUAL_COMPONENTS.md.meta +7 -0
- package/Editor/Sprites/AnimationCopier.cs +3 -3
- package/README.md +69 -62
- package/Runtime/AssemblyInfo.cs +2 -0
- package/Runtime/Core/DataStructure/KDTree3D.cs +1 -1
- package/Runtime/Core/DataStructure/OctTree3D.cs +1 -1
- package/Runtime/Core/Extension/AsyncOperationExtensions.cs +122 -0
- package/Runtime/Core/Helper/Logging/UnityLogTagFormatter.cs +76 -90
- package/Runtime/Core/Serialization/ProtobufUnitySurrogates.cs +24 -29
- package/Runtime/Integrations/Reflex/AssemblyInfo.cs +7 -0
- package/Runtime/Integrations/Reflex/AssemblyInfo.cs.meta +11 -0
- package/Runtime/Integrations/Reflex/ContainerRelationalExtensions.cs +198 -0
- package/Runtime/Integrations/Reflex/ContainerRelationalExtensions.cs.meta +11 -0
- package/Runtime/Integrations/Reflex/RelationalComponentsInstaller.cs +86 -0
- package/Runtime/Integrations/Reflex/RelationalComponentsInstaller.cs.meta +11 -0
- package/Runtime/Integrations/Reflex/RelationalReflexSceneBootstrapper.cs +316 -0
- package/Runtime/Integrations/Reflex/RelationalReflexSceneBootstrapper.cs.meta +11 -0
- package/Runtime/Integrations/Reflex/RelationalSceneAssignmentOptions.cs +86 -0
- package/Runtime/Integrations/Reflex/RelationalSceneAssignmentOptions.cs.meta +11 -0
- package/Runtime/Integrations/Reflex/WallstopStudios.UnityHelpers.Integration.Reflex.asmdef +20 -0
- package/Runtime/Integrations/Reflex/WallstopStudios.UnityHelpers.Integration.Reflex.asmdef.meta +7 -0
- package/Runtime/Integrations/Reflex.meta +8 -0
- package/Runtime/Utils/ScriptableObjectSingleton.cs +1 -1
- package/Samples~/DI - Reflex/README.md +527 -0
- package/Samples~/DI - Reflex/README.md.meta +7 -0
- package/Samples~/DI - Reflex/Scripts/ReflexPaletteService.cs +36 -0
- package/Samples~/DI - Reflex/Scripts/ReflexPaletteService.cs.meta +11 -0
- package/Samples~/DI - Reflex/Scripts/ReflexRelationalConsumer.cs +79 -0
- package/Samples~/DI - Reflex/Scripts/ReflexRelationalConsumer.cs.meta +11 -0
- package/Samples~/DI - Reflex/Scripts/ReflexSampleInstaller.cs +30 -0
- package/Samples~/DI - Reflex/Scripts/ReflexSampleInstaller.cs.meta +11 -0
- package/Samples~/DI - Reflex/Scripts/ReflexSpawner.cs +79 -0
- package/Samples~/DI - Reflex/Scripts/ReflexSpawner.cs.meta +11 -0
- package/Samples~/DI - Reflex/Scripts/Samples.UnityHelpers.DI.Reflex.asmdef +26 -0
- package/Samples~/DI - Reflex/Scripts/Samples.UnityHelpers.DI.Reflex.asmdef.meta +9 -0
- package/Samples~/DI - Reflex/Scripts.meta +8 -0
- package/Samples~/DI - Reflex.meta +8 -0
- package/Samples~/DI - VContainer/README.md +6 -5
- package/Samples~/DI - Zenject/README.md +6 -5
- package/Tests/Editor/Core/Attributes/RelationalComponentAssignerTests.cs +29 -31
- package/Tests/Editor/Integrations/Reflex/ReflexIntegrationCompilationTests.cs +41 -0
- package/Tests/Editor/Integrations/Reflex/ReflexIntegrationCompilationTests.cs.meta +11 -0
- package/Tests/Editor/Integrations/Reflex/WallstopStudios.UnityHelpers.Tests.Editor.Reflex.asmdef +27 -0
- package/Tests/Editor/Integrations/Reflex/WallstopStudios.UnityHelpers.Tests.Editor.Reflex.asmdef.meta +7 -0
- package/Tests/Editor/Integrations/Reflex.meta +8 -0
- package/Tests/Editor/Integrations/VContainer/VContainerRelationalEntryPointTests.cs +15 -16
- package/Tests/Editor/Integrations/VContainer/VContainerRelationalHelpersTests.cs +7 -13
- package/Tests/Editor/Integrations/Zenject/ZenjectRelationalHelpersTests.cs +7 -11
- package/Tests/Editor/Integrations/Zenject/ZenjectRelationalInitializerTests.cs +19 -21
- package/Tests/Editor/PersistentDirectorySettingsTests.cs +0 -1
- package/Tests/Editor/Sprites/AnimationCopierFilterTests.cs +0 -1
- package/Tests/Editor/Sprites/AnimationViewerWindowTests.cs +2 -2
- package/Tests/Editor/Tools/ImageBlurToolTests.cs +1 -1
- package/Tests/Editor/Utils/CommonTestBase.cs +17 -0
- package/Tests/Editor/Utils/ScriptableObjectSingletonCreatorTests.cs +1 -1
- package/Tests/Runtime/Extensions/AsyncOperationExtensionsTests.cs +179 -0
- package/Tests/Runtime/Extensions/RandomExtensionTests.cs +55 -0
- package/Tests/Runtime/Extensions/UnityLogTagFormatterEdgeTests.cs +84 -0
- package/Tests/Runtime/Integrations/Reflex/RelationalComponentsReflexTests.cs +445 -0
- package/Tests/Runtime/Integrations/Reflex/RelationalComponentsReflexTests.cs.meta +11 -0
- package/Tests/Runtime/Integrations/Reflex/WallstopStudios.UnityHelpers.Tests.Runtime.Reflex.asmdef +28 -0
- package/Tests/Runtime/Integrations/Reflex/WallstopStudios.UnityHelpers.Tests.Runtime.Reflex.asmdef.meta +7 -0
- package/Tests/Runtime/Integrations/Reflex.meta +8 -0
- package/Tests/Runtime/Integrations/VContainer/RelationalComponentsVContainerTests.cs +24 -29
- package/Tests/Runtime/Integrations/VContainer/RelationalObjectPoolsVContainerTests.cs +8 -3
- package/Tests/Runtime/Integrations/Zenject/RelationalComponentsZenjectTests.cs +10 -20
- package/Tests/Runtime/Performance/RandomPerformanceTests.cs +1 -1
- package/Tests/Runtime/Performance/SpatialTree2DPerformanceTests.cs +1 -1
- package/Tests/Runtime/Performance/SpatialTree3DPerformanceTests.cs +1 -1
- package/Tests/Runtime/Serialization/JsonRoundtripComprehensiveTests.cs +4 -9
- package/Tests/Runtime/Serialization/ProtoRoundtripComprehensiveTests.cs +13 -13
- package/Tests/Runtime/TestUtils/CommonTestBase.cs +11 -0
- package/Tests/Runtime/TestUtils/ReflexTestSupport.cs +111 -0
- package/Tests/Runtime/TestUtils/ReflexTestSupport.cs.meta +12 -0
- package/Tests/Runtime/Utils/MatchColliderToSpriteTests.cs +4 -4
- package/Tests/TestUtils.meta +8 -0
- package/package.json +6 -1
- package/EFFECTS_SYSTEM.md +0 -242
- package/MATH_AND_EXTENSIONS.md +0 -316
- /package/{CHANGELOG.md → Docs/CHANGELOG.md} +0 -0
- /package/{CHANGELOG.md.meta → Docs/CHANGELOG.md.meta} +0 -0
- /package/{CONTRIBUTING.md → Docs/CONTRIBUTING.md} +0 -0
- /package/{CONTRIBUTING.md.meta → Docs/CONTRIBUTING.md.meta} +0 -0
- /package/{DATA_STRUCTURES.md → Docs/DATA_STRUCTURES.md} +0 -0
- /package/{DATA_STRUCTURES.md.meta → Docs/DATA_STRUCTURES.md.meta} +0 -0
- /package/{EDITOR_TOOLS_GUIDE.md → Docs/EDITOR_TOOLS_GUIDE.md} +0 -0
- /package/{EDITOR_TOOLS_GUIDE.md.meta → Docs/EDITOR_TOOLS_GUIDE.md.meta} +0 -0
- /package/{EFFECTS_SYSTEM.md.meta → Docs/EFFECTS_SYSTEM.md.meta} +0 -0
- /package/{EFFECTS_SYSTEM_TUTORIAL.md.meta → Docs/EFFECTS_SYSTEM_TUTORIAL.md.meta} +0 -0
- /package/{GETTING_STARTED.md.meta → Docs/GETTING_STARTED.md.meta} +0 -0
- /package/{GLOSSARY.md.meta → Docs/GLOSSARY.md.meta} +0 -0
- /package/{HULLS.md → Docs/HULLS.md} +0 -0
- /package/{HULLS.md.meta → Docs/HULLS.md.meta} +0 -0
- /package/{INDEX.md.meta → Docs/INDEX.md.meta} +0 -0
- /package/{LICENSE.md → Docs/LICENSE.md} +0 -0
- /package/{LICENSE.md.meta → Docs/LICENSE.md.meta} +0 -0
- /package/{MATH_AND_EXTENSIONS.md.meta → Docs/MATH_AND_EXTENSIONS.md.meta} +0 -0
- /package/{RANDOM_PERFORMANCE.md.meta → Docs/RANDOM_PERFORMANCE.md.meta} +0 -0
- /package/{REFLECTION_HELPERS.md → Docs/REFLECTION_HELPERS.md} +0 -0
- /package/{REFLECTION_HELPERS.md.meta → Docs/REFLECTION_HELPERS.md.meta} +0 -0
- /package/{RELATIONAL_COMPONENTS.md.meta → Docs/RELATIONAL_COMPONENTS.md.meta} +0 -0
- /package/{SERIALIZATION.md → Docs/SERIALIZATION.md} +0 -0
- /package/{SERIALIZATION.md.meta → Docs/SERIALIZATION.md.meta} +0 -0
- /package/{SINGLETONS.md → Docs/SINGLETONS.md} +0 -0
- /package/{SINGLETONS.md.meta → Docs/SINGLETONS.md.meta} +0 -0
- /package/{SPATIAL_TREES_2D_GUIDE.md.meta → Docs/SPATIAL_TREES_2D_GUIDE.md.meta} +0 -0
- /package/{SPATIAL_TREES_3D_GUIDE.md.meta → Docs/SPATIAL_TREES_3D_GUIDE.md.meta} +0 -0
- /package/{SPATIAL_TREE_2D_PERFORMANCE.md.meta → Docs/SPATIAL_TREE_2D_PERFORMANCE.md.meta} +0 -0
- /package/{SPATIAL_TREE_3D_PERFORMANCE.md.meta → Docs/SPATIAL_TREE_3D_PERFORMANCE.md.meta} +0 -0
- /package/{SPATIAL_TREE_SEMANTICS.md → Docs/SPATIAL_TREE_SEMANTICS.md} +0 -0
- /package/{SPATIAL_TREE_SEMANTICS.md.meta → Docs/SPATIAL_TREE_SEMANTICS.md.meta} +0 -0
- /package/{THIRD_PARTY_NOTICES.md → Docs/THIRD_PARTY_NOTICES.md} +0 -0
- /package/{THIRD_PARTY_NOTICES.md.meta → Docs/THIRD_PARTY_NOTICES.md.meta} +0 -0
package/EFFECTS_SYSTEM.md
DELETED
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
# Effects, Attributes, and Tags — Deep Dive
|
|
2
|
-
|
|
3
|
-
## TL;DR — What Problem This Solves
|
|
4
|
-
|
|
5
|
-
- **⭐ Build buff/debuff systems without writing custom code for every effect.**
|
|
6
|
-
- Data‑driven ScriptableObjects: designers create 100s of effects, programmers build system once.
|
|
7
|
-
- **Time saved: Weeks of boilerplate eliminated + designers empowered to iterate freely.**
|
|
8
|
-
|
|
9
|
-
### ⭐ The Designer Empowerment Killer Feature
|
|
10
|
-
|
|
11
|
-
**The Problem - Hardcoded Effects:**
|
|
12
|
-
|
|
13
|
-
```csharp
|
|
14
|
-
// Every buff needs its own custom MonoBehaviour:
|
|
15
|
-
|
|
16
|
-
public class HasteEffect : MonoBehaviour
|
|
17
|
-
{
|
|
18
|
-
private float duration = 5f;
|
|
19
|
-
private float originalSpeed;
|
|
20
|
-
private PlayerStats player;
|
|
21
|
-
|
|
22
|
-
void Start()
|
|
23
|
-
{
|
|
24
|
-
player = GetComponent<PlayerStats>();
|
|
25
|
-
originalSpeed = player.speed;
|
|
26
|
-
player.speed *= 1.5f; // Apply speed boost
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
void Update()
|
|
30
|
-
{
|
|
31
|
-
duration -= Time.deltaTime;
|
|
32
|
-
if (duration <= 0)
|
|
33
|
-
{
|
|
34
|
-
player.speed = originalSpeed; // Restore
|
|
35
|
-
Destroy(this);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// 20 effects × 50 lines each = 1000 lines of repetitive code
|
|
41
|
-
// Designers can't create effects without programmer
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
**The Solution - Data-Driven:**
|
|
45
|
-
|
|
46
|
-
```csharp
|
|
47
|
-
// Programmers build system once (Unity Helpers provides this):
|
|
48
|
-
// - AttributesComponent base class
|
|
49
|
-
// - EffectHandler manages application/removal
|
|
50
|
-
// - ScriptableObject authoring
|
|
51
|
-
|
|
52
|
-
// Designers create effects in Editor (NO CODE):
|
|
53
|
-
// 1. Right-click → Create → Attribute Effect
|
|
54
|
-
// 2. Name: "Haste"
|
|
55
|
-
// 3. Add modification: Speed × 1.5
|
|
56
|
-
// 4. Duration: 5 seconds
|
|
57
|
-
// 5. Done!
|
|
58
|
-
|
|
59
|
-
// Apply at runtime (one line):
|
|
60
|
-
target.ApplyEffect(hasteEffect);
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
**Designer Workflow:**
|
|
64
|
-
|
|
65
|
-
1. Create effect asset in 30 seconds (no code)
|
|
66
|
-
2. Test in-game immediately
|
|
67
|
-
3. Tweak values and iterate freely
|
|
68
|
-
4. Create variations (Haste II, Haste III) by duplicating assets
|
|
69
|
-
|
|
70
|
-
**Impact:**
|
|
71
|
-
|
|
72
|
-
- **Programmer time saved**: Weeks of boilerplate → system built once
|
|
73
|
-
- **Designer empowerment**: Block creating 100s of effects instantly
|
|
74
|
-
- **Iteration speed**: Change values without code changes/recompiles
|
|
75
|
-
- **Maintainability**: All effects in one system vs scattered scripts
|
|
76
|
-
|
|
77
|
-
Data‑driven gameplay effects that modify stats, apply tags, and drive cosmetic presentation.
|
|
78
|
-
|
|
79
|
-
This guide explains the concepts, how they work together, authoring patterns, recipes, best practices, and FAQs.
|
|
80
|
-
|
|
81
|
-
Visuals
|
|
82
|
-
|
|
83
|
-

|
|
84
|
-
|
|
85
|
-

|
|
86
|
-
|
|
87
|
-
## Concepts
|
|
88
|
-
|
|
89
|
-
- `Attribute` — A dynamic numeric value with a base and a calculated current value. Current value applies all active modifications.
|
|
90
|
-
- `AttributeModification` — Declarative change to an `Attribute`. Actions: Addition, Multiplication, Override. Applied in that order.
|
|
91
|
-
- `AttributeEffect` — ScriptableObject asset bundling modifications, tags, cosmetic data, and duration policy.
|
|
92
|
-
- `EffectHandle` — Opaque identifier for a specific application instance (for Duration/Infinite effects). Used to remove one stack.
|
|
93
|
-
- `AttributesComponent` — Base MonoBehaviour exposing modifiable `Attribute` fields (e.g., Health, Speed) on your character.
|
|
94
|
-
- `EffectHandler` — Component that applies/removes effects, tracks durations, forwards modifications to `AttributesComponent`, applies tags and cosmetics.
|
|
95
|
-
- `TagHandler` — Counts and queries string tags for gating gameplay (e.g., "Stunned"). Removes tags only when all sources are gone.
|
|
96
|
-
- `CosmeticEffectData` — Prefab‑like container with `CosmeticEffectComponent` behaviours; reused or instanced per effect application.
|
|
97
|
-
|
|
98
|
-
## How It Works
|
|
99
|
-
|
|
100
|
-
1. You author an `AttributeEffect` with modifications, tags, cosmetics, and duration.
|
|
101
|
-
2. You apply it to a GameObject: `EffectHandle? handle = target.ApplyEffect(effect);`
|
|
102
|
-
3. `EffectHandler` will:
|
|
103
|
-
- Create an `EffectHandle` (for Duration/Infinite) and track expiration
|
|
104
|
-
- Apply tags via `TagHandler` (counted; multiple sources safe)
|
|
105
|
-
- Apply cosmetic behaviours (`CosmeticEffectData`)
|
|
106
|
-
- Forward `AttributeModification`s to all `AttributesComponent`s on the GameObject
|
|
107
|
-
4. On removal (manual or expiration), all of the above are cleanly reversed.
|
|
108
|
-
|
|
109
|
-
Instant effects modify base values permanently and return `null` instead of a handle.
|
|
110
|
-
|
|
111
|
-
## Authoring Guide
|
|
112
|
-
|
|
113
|
-
1. Define stats:
|
|
114
|
-
|
|
115
|
-
```csharp
|
|
116
|
-
public class CharacterStats : AttributesComponent
|
|
117
|
-
{
|
|
118
|
-
public Attribute Health = 100f;
|
|
119
|
-
public Attribute Speed = 5f;
|
|
120
|
-
public Attribute Defense = 10f;
|
|
121
|
-
}
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
1. Create an `AttributeEffect` asset (Project view → Create → Wallstop Studios → Unity Helpers → Attribute Effect):
|
|
125
|
-
|
|
126
|
-
- modifications: e.g., `{ attribute: "Speed", action: Multiplication, value: 1.5f }`
|
|
127
|
-
- durationType: `Duration` with `duration = 5`
|
|
128
|
-
- resetDurationOnReapplication: true to refresh timer on reapply
|
|
129
|
-
- effectTags: e.g., `[ "Haste" ]`
|
|
130
|
-
- cosmeticEffects: prefab with `CosmeticEffectData` + `CosmeticEffectComponent` scripts
|
|
131
|
-
|
|
132
|
-
1. Apply/remove at runtime:
|
|
133
|
-
|
|
134
|
-
```csharp
|
|
135
|
-
GameObject player = ...;
|
|
136
|
-
AttributeEffect haste = ...; // ScriptableObject reference
|
|
137
|
-
EffectHandle? handle = player.ApplyEffect(haste);
|
|
138
|
-
// ... later ...
|
|
139
|
-
if (handle.HasValue)
|
|
140
|
-
{
|
|
141
|
-
player.RemoveEffect(handle.Value);
|
|
142
|
-
}
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
1. Query tags anywhere:
|
|
146
|
-
|
|
147
|
-
```csharp
|
|
148
|
-
if (player.HasTag("Stunned"))
|
|
149
|
-
{
|
|
150
|
-
// Disable input, play animation, etc.
|
|
151
|
-
}
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
## Recipes
|
|
155
|
-
|
|
156
|
-
### 1) Buff with % Speed for 5s (refreshable)
|
|
157
|
-
|
|
158
|
-
- Effect: Multiplication `Speed *= 1.5f`, `Duration=5`, `resetDurationOnReapplication=true`, tag `Haste`.
|
|
159
|
-
- Apply to extend: reapply before expiry to reset the timer.
|
|
160
|
-
|
|
161
|
-
### 2) Poison: −5 Health instantly and "Poisoned" tag for 10s
|
|
162
|
-
|
|
163
|
-
- modifications: Addition `{ attribute: "Health", value: -5f }`
|
|
164
|
-
- durationType: Duration `10s`
|
|
165
|
-
- effectTags: `[ "Poisoned" ]`
|
|
166
|
-
- cosmetics: particles + UI icon
|
|
167
|
-
|
|
168
|
-
### 3) Equipment Aura: +10 Defense while equipped
|
|
169
|
-
|
|
170
|
-
- durationType: Infinite
|
|
171
|
-
- modifications: Addition `{ attribute: "Defense", value: 10f }`
|
|
172
|
-
- Apply on equip, store handle, remove on unequip.
|
|
173
|
-
|
|
174
|
-
### 4) One‑off Permanent Bonus
|
|
175
|
-
|
|
176
|
-
- durationType: Instant (returns null)
|
|
177
|
-
- modifications: Addition or Override on base value (no handle; cannot be removed).
|
|
178
|
-
|
|
179
|
-
### 5) Stacking Multiple Instances
|
|
180
|
-
|
|
181
|
-
- Apply the same effect multiple times → multiple `EffectHandle`s; remove one handle to remove one stack.
|
|
182
|
-
- Use tags to gate behaviour regardless of which instance applied it.
|
|
183
|
-
|
|
184
|
-
### 6) Shared vs Instanced Cosmetics
|
|
185
|
-
|
|
186
|
-
- In `CosmeticEffectData`, set a component’s `RequiresInstance = true` for per‑application instances (e.g., particles).
|
|
187
|
-
- Keep `RequiresInstance = false` for shared presenters (e.g., status icon overlay).
|
|
188
|
-
|
|
189
|
-
## Best Practices
|
|
190
|
-
|
|
191
|
-
- Use Addition for flat changes; Multiplication for percentage changes; Override sparingly (wins last).
|
|
192
|
-
- Use the Attribute Metadata Cache generator to power editor dropdowns for `attribute` names and avoid typos.
|
|
193
|
-
- Centralize tag strings as constants to prevent mistakes and improve refactor safety.
|
|
194
|
-
- Prefer shared cosmetics where feasible; instantiate only when state must be isolated per application.
|
|
195
|
-
- If reapplication should refresh timers, set `resetDurationOnReapplication = true` on the effect.
|
|
196
|
-
|
|
197
|
-
## FAQ
|
|
198
|
-
|
|
199
|
-
Q: Why didn’t I get an `EffectHandle`?
|
|
200
|
-
|
|
201
|
-
- Instant effects modify the base value permanently and do not return a handle (`null`). Duration/Infinite do.
|
|
202
|
-
|
|
203
|
-
Q: Do modifications stack across multiple effects?
|
|
204
|
-
|
|
205
|
-
- Yes. Each `Attribute` applies all active modifications ordered by action: Addition → Multiplication → Override.
|
|
206
|
-
|
|
207
|
-
Q: How do I remove just one instance of an effect?
|
|
208
|
-
|
|
209
|
-
- Keep the `EffectHandle` returned from `ApplyEffect` and pass it to `RemoveEffect(handle)`.
|
|
210
|
-
|
|
211
|
-
Q: Two systems apply the same tag. Who owns removal?
|
|
212
|
-
|
|
213
|
-
- The tag is reference‑counted. Each application increments the count; removal decrements it. The tag is removed when the count reaches 0.
|
|
214
|
-
|
|
215
|
-
Q: When should I use tags vs checking stats?
|
|
216
|
-
|
|
217
|
-
- Use tags to represent categorical states (e.g., Stunned/Poisoned/Invulnerable) independent from numeric values. Check stats for numeric thresholds or calculations.
|
|
218
|
-
|
|
219
|
-
## Troubleshooting
|
|
220
|
-
|
|
221
|
-
- Attribute name doesn’t apply
|
|
222
|
-
- Ensure the `attribute` field matches a public/private `Attribute` field name on an `AttributesComponent` subclass.
|
|
223
|
-
- Regenerate the Attribute Metadata Cache to update editor dropdowns.
|
|
224
|
-
|
|
225
|
-
- Effect didn’t clean up cosmetics
|
|
226
|
-
- Confirm `RequiresInstance` is set correctly and components either clean up themselves (`CleansUpSelf`) or are destroyed by `EffectHandler`.
|
|
227
|
-
|
|
228
|
-
- Duration didn’t refresh on reapply
|
|
229
|
-
- Set `resetDurationOnReapplication = true` on the `AttributeEffect`.
|
|
230
|
-
|
|
231
|
-
## Performance Notes
|
|
232
|
-
|
|
233
|
-
- Attribute field discovery is cached (and can be precomputed by the Attribute Metadata Cache generator).
|
|
234
|
-
- Tag queries provide overloads for lists to minimize allocations; prefer `IReadOnlyList<string>` overloads in hot paths.
|
|
235
|
-
- Cosmetics can be a significant cost; prefer shared presenters when possible.
|
|
236
|
-
|
|
237
|
-
---
|
|
238
|
-
|
|
239
|
-
Related:
|
|
240
|
-
|
|
241
|
-
- README section: “Effects, Attributes, and Tags”
|
|
242
|
-
- Attribute Metadata Cache (Editor Tools) for dropdowns and performance
|
package/MATH_AND_EXTENSIONS.md
DELETED
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
# Core Math & Extensions
|
|
2
|
-
|
|
3
|
-
## TL;DR — Why Use These
|
|
4
|
-
|
|
5
|
-
- Small helpers that fix everyday math and Unity annoyances: safe modulo, wrapped indices, robust equality, fast bounds math, color utilities, and more.
|
|
6
|
-
- Copy/paste examples and diagrams show intent; use as building blocks in hot paths.
|
|
7
|
-
|
|
8
|
-
This guide summarizes the math primitives and extension helpers in this package and shows how to apply them effectively, with examples, performance notes, and practical scenarios.
|
|
9
|
-
|
|
10
|
-
Contents
|
|
11
|
-
|
|
12
|
-
- [Numeric helpers](#numeric-helpers) — Positive modulo, wrapped arithmetic, approximate equality, clamping
|
|
13
|
-
- [Geometry](#geometry) — Lines, ranges, parabolas, point-in-polygon, polyline simplification
|
|
14
|
-
- [Unity extensions](#unity-extensions) — Rect/Bounds conversions, RectTransform bounds, camera bounds, bounds aggregation
|
|
15
|
-
- [Color utilities](#color-utilities) — Averaging (LAB/HSV/Weighted/Dominant), hex conversion
|
|
16
|
-
- [Collections](#collections) — IEnumerable helpers, buffering, infinite sequences
|
|
17
|
-
- [Strings](#strings) — Casing, encoding/decoding, distance
|
|
18
|
-
- [Direction helpers](#directions) — Enum conversions and operations
|
|
19
|
-
- [Best Practices](#best-practices)
|
|
20
|
-
|
|
21
|
-
<a id="numeric-helpers"></a>
|
|
22
|
-
|
|
23
|
-
## Numeric Helpers
|
|
24
|
-
|
|
25
|
-
- Positive modulo and wrap-around arithmetic
|
|
26
|
-
- Use `PositiveMod` to ensure non-negative modulo results for indices and cyclic counters.
|
|
27
|
-
- Use `WrappedAdd`/`WrappedIncrement` for ring buffer indexes and cursor navigation.
|
|
28
|
-
|
|
29
|
-
Example:
|
|
30
|
-
|
|
31
|
-
```csharp
|
|
32
|
-
using WallstopStudios.UnityHelpers.Core.Helper;
|
|
33
|
-
|
|
34
|
-
int i = -1;
|
|
35
|
-
i = i.PositiveMod(5); // 4
|
|
36
|
-
i = i.WrappedAdd(2, 5); // 1
|
|
37
|
-
|
|
38
|
-
float angle = -30f;
|
|
39
|
-
float normalized = angle.PositiveMod(360f); // 330f
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Diagram (wrap-around on a ring of size 5):
|
|
43
|
-
|
|
44
|
-
```text
|
|
45
|
-
Index: 0 1 2 3 4
|
|
46
|
-
↖ ↙
|
|
47
|
-
\ +2 from 4 => 1
|
|
48
|
-
|
|
49
|
-
Start at 4, add 2 → 6 → 6 % 5 = 1
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
- Approximate equality
|
|
53
|
-
- `float.Approximately(rhs, tolerance)` and `double.Approximately` add a magnitude-scaled fudge factor.
|
|
54
|
-
|
|
55
|
-
Example:
|
|
56
|
-
|
|
57
|
-
```csharp
|
|
58
|
-
bool close = 0.1f.Approximately(0.10001f, 0.0001f); // true
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
- Generic `Clamp`
|
|
62
|
-
- `Clamp<T>(min, max)` works for any `IComparable<T>`.
|
|
63
|
-
|
|
64
|
-
<a id="geometry"></a>
|
|
65
|
-
|
|
66
|
-
## Geometry
|
|
67
|
-
|
|
68
|
-
- `Line2D`/`Line3D` operations
|
|
69
|
-
- Length, direction, contains, intersections and closest point calculations.
|
|
70
|
-
|
|
71
|
-
Example:
|
|
72
|
-
|
|
73
|
-
```csharp
|
|
74
|
-
using WallstopStudios.UnityHelpers.Core.Math;
|
|
75
|
-
var a = new Line2D(new Vector2(0,0), new Vector2(2,0));
|
|
76
|
-
var b = new Line2D(new Vector2(1,-1), new Vector2(1,1));
|
|
77
|
-
bool hit = a.Intersects(b); // true
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Diagram (segment intersection):
|
|
81
|
-
|
|
82
|
-
```text
|
|
83
|
-
y↑ b.to (1,1)
|
|
84
|
-
| │
|
|
85
|
-
| │ b
|
|
86
|
-
| a ────────┼────────▶ x
|
|
87
|
-
| (1,0)× ← intersection
|
|
88
|
-
| │
|
|
89
|
-
| │
|
|
90
|
-
+─────────────┼────────
|
|
91
|
-
b.from (1,-1)
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
- `Range<T>` inclusive/exclusive ranges
|
|
95
|
-
- `Contains`, `Overlaps`, and factory methods for inclusive/exclusive endpoints.
|
|
96
|
-
|
|
97
|
-
Example:
|
|
98
|
-
|
|
99
|
-
```csharp
|
|
100
|
-
using WallstopStudios.UnityHelpers.Core.Math;
|
|
101
|
-
var r = Range<int>.Inclusive(0, 10);
|
|
102
|
-
bool inside = r.Contains(10); // true
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
- `Parabola`
|
|
106
|
-
- Construct by height/length or coefficients; evaluate by x or normalized position.
|
|
107
|
-
|
|
108
|
-
Example:
|
|
109
|
-
|
|
110
|
-
```csharp
|
|
111
|
-
var p = new Parabola(maxHeight: 5f, length: 10f);
|
|
112
|
-
if (p.TryGetValueAtNormalized(0.5f, out float y)) { /* y == 5 */ }
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
Diagram (normalized parabola):
|
|
116
|
-
|
|
117
|
-
```text
|
|
118
|
-
y↑ * vertex (0.5, 5)
|
|
119
|
-
| *
|
|
120
|
-
| *
|
|
121
|
-
| *
|
|
122
|
-
| *
|
|
123
|
-
|* *
|
|
124
|
-
+────────*────────▶ x (t from 0..1)
|
|
125
|
-
0 0.5 1
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
- Point-in-polygon
|
|
129
|
-
- 2D and 3D (projected) tests; remarks on precision and assumptions.
|
|
130
|
-
|
|
131
|
-
- Polyline simplification (Douglas–Peucker)
|
|
132
|
-
- `Simplify` (float epsilon) and `SimplifyPrecise` (double tolerance) reduce vertex count while preserving shape.
|
|
133
|
-
|
|
134
|
-
Example:
|
|
135
|
-
|
|
136
|
-
```csharp
|
|
137
|
-
using WallstopStudios.UnityHelpers.Core.Helper;
|
|
138
|
-
List<Vector2> simplified = LineHelper.Simplify(points, epsilon: 0.1f);
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
Diagram (original vs simplified):
|
|
142
|
-
|
|
143
|
-
```text
|
|
144
|
-
Original: *----*--*---*--*-----*
|
|
145
|
-
Simplified: *-----------*--------*
|
|
146
|
-
|
|
147
|
-
Fewer vertices within epsilon of the original polyline.
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
Visual:
|
|
151
|
-

|
|
152
|
-
|
|
153
|
-
Convex hull (monotone chain / Jarvis examples used by helpers):
|
|
154
|
-
|
|
155
|
-
```text
|
|
156
|
-
Points: · · ·
|
|
157
|
-
· · ·
|
|
158
|
-
· ·
|
|
159
|
-
|
|
160
|
-
Hull: ┌───────────┐
|
|
161
|
-
│ │
|
|
162
|
-
└───────┬───┘
|
|
163
|
-
└─┐
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
Visual:
|
|
167
|
-

|
|
168
|
-
|
|
169
|
-
Edge Cases Gallery
|
|
170
|
-
|
|
171
|
-

|
|
172
|
-
|
|
173
|
-
<a id="unity-extensions"></a>
|
|
174
|
-
|
|
175
|
-
## Unity Extensions
|
|
176
|
-
|
|
177
|
-
- Rect/Bounds conversions, RectTransform world bounds
|
|
178
|
-
- Camera `OrthographicBounds`
|
|
179
|
-
- Bounds aggregation from collections
|
|
180
|
-
|
|
181
|
-
Example:
|
|
182
|
-
|
|
183
|
-
```csharp
|
|
184
|
-
Rect r = rectTransform.GetWorldRect();
|
|
185
|
-
Bounds view = Camera.main.OrthographicBounds();
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
Diagrams:
|
|
189
|
-
|
|
190
|
-
- RectTransform world rect (axis-aligned bounds of rotated UI):
|
|
191
|
-
|
|
192
|
-
```text
|
|
193
|
-
• corner ┌───────────────┐
|
|
194
|
-
╲ │ AABB (r) │
|
|
195
|
-
╲ rotated │ ┌──────┐ │
|
|
196
|
-
╲ rectangle │ ╱│ UI ╱│ │
|
|
197
|
-
• │ ╱ └────╱─┘ │
|
|
198
|
-
└───────────────┘
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
- Orthographic camera bounds (centered on camera):
|
|
202
|
-
|
|
203
|
-
```text
|
|
204
|
-
┌──────── view (Bounds) ────────┐
|
|
205
|
-
│ height=2*size │
|
|
206
|
-
│ ┌────────────────┐ │
|
|
207
|
-
near ───▶│ │ camera FOV │ │◀── far
|
|
208
|
-
│ └────────────────┘ │
|
|
209
|
-
└────────────────────────────────┘
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
<a id="color-utilities"></a>
|
|
213
|
-
|
|
214
|
-
## Color Utilities
|
|
215
|
-
|
|
216
|
-
- Averaging methods:
|
|
217
|
-
- LAB: perceptually accurate
|
|
218
|
-
- HSV: preserves vibrancy
|
|
219
|
-
- Weighted: luminance-aware
|
|
220
|
-
- Dominant: bucket-based mode
|
|
221
|
-
|
|
222
|
-
Example:
|
|
223
|
-
|
|
224
|
-
```csharp
|
|
225
|
-
using WallstopStudios.UnityHelpers.Core.Extension;
|
|
226
|
-
Color avg = sprite.GetAverageColor(ColorAveragingMethod.LAB);
|
|
227
|
-
string html = avg.ToHex();
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
Dominant color example (bucket-based):
|
|
231
|
-
|
|
232
|
-
```csharp
|
|
233
|
-
// Emphasize palette extraction (posterized sprites, UI swatches)
|
|
234
|
-
var dominant = pixels.GetAverageColor(ColorAveragingMethod.Dominant, alphaCutoff: 0.05f);
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
Diagram (dominant buckets):
|
|
238
|
-
|
|
239
|
-
```text
|
|
240
|
-
RGB space buckets → counts
|
|
241
|
-
[R][G][B] … [R+Δ][G][B] … [R][G+Δ][B] …
|
|
242
|
-
↑ pick max bucket centroid as dominant
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
<a id="collections"></a>
|
|
246
|
-
|
|
247
|
-
## Collections
|
|
248
|
-
|
|
249
|
-
- Readable helpers: `AsList`, `ToLinkedList`, `OrderBy(Func)`
|
|
250
|
-
- Utilities: `Infinite`, min-bounds from points, bounds aggregation
|
|
251
|
-
|
|
252
|
-
Example:
|
|
253
|
-
|
|
254
|
-
```csharp
|
|
255
|
-
using WallstopStudios.UnityHelpers.Core.Extension;
|
|
256
|
-
foreach (var v in someList.Infinite()) { /* cycles forever */ }
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
Bounds from points example:
|
|
260
|
-
|
|
261
|
-
```csharp
|
|
262
|
-
// Compute BoundsInt for occupied grid cells
|
|
263
|
-
BoundsInt? area = positions.GetBounds(inclusive: false);
|
|
264
|
-
if (area is BoundsInt b) { /* use b */ }
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
Bounds aggregation example:
|
|
268
|
-
|
|
269
|
-
```csharp
|
|
270
|
-
// Merge many Bounds (e.g., from Renderers)
|
|
271
|
-
Bounds? merged = renderers.Select(r => r.bounds).GetBounds();
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
<a id="strings"></a>
|
|
275
|
-
|
|
276
|
-
## Strings
|
|
277
|
-
|
|
278
|
-
- Casing conversions (Pascal, Camel, Snake, Kebab, Title)
|
|
279
|
-
- Encoding helpers: `GetBytes`, `GetString`
|
|
280
|
-
- Similarity: `LevenshteinDistance`
|
|
281
|
-
|
|
282
|
-
Example:
|
|
283
|
-
|
|
284
|
-
```csharp
|
|
285
|
-
using WallstopStudios.UnityHelpers.Core.Extension;
|
|
286
|
-
string s = "hello_world";
|
|
287
|
-
int distance = s.LevenshteinDistance("hello-world");
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
<a id="directions"></a>
|
|
291
|
-
|
|
292
|
-
## Directions
|
|
293
|
-
|
|
294
|
-
- Conversions between enum and vectors; splitting flag sets; combining
|
|
295
|
-
|
|
296
|
-
Example:
|
|
297
|
-
|
|
298
|
-
```csharp
|
|
299
|
-
using WallstopStudios.UnityHelpers.Core.Extension;
|
|
300
|
-
Vector2Int v = Direction.NorthWest.AsVector2Int(); // (-1, 1)
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
## Best Practices
|
|
304
|
-
|
|
305
|
-
- Use `PositiveMod` instead of `%` for indices and angles when negatives are possible.
|
|
306
|
-
- Prefer `SimplifyPrecise` for offline tooling; use `Simplify` during gameplay for speed.
|
|
307
|
-
- Choose color averaging method per goal: LAB for perceptual palette, Weighted for speed, Dominant for swatches.
|
|
308
|
-
- Favor IReadOnlyList/HashSet specializations to minimize allocations; pooled buffers are used where applicable.
|
|
309
|
-
- Run Unity-dependent extensions (e.g., `RectTransform`, `Camera`, `Grid`) on the main thread.
|
|
310
|
-
|
|
311
|
-
## Related Docs
|
|
312
|
-
|
|
313
|
-
- Random performance details — [Random Performance](RANDOM_PERFORMANCE.md)
|
|
314
|
-
- Serialization formats — [Serialization Guide](SERIALIZATION.md)
|
|
315
|
-
- Effects system — [Effects System](EFFECTS_SYSTEM.md)
|
|
316
|
-
- Relational Components — [Relational Components](RELATIONAL_COMPONENTS.md)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|