@fps-games/vfx 0.3.2 → 0.3.4

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.
Files changed (234) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +5 -5
  3. package/dist/effects/treasure-attention/index.d.ts +1 -1
  4. package/package.json +6 -5
  5. package/tooling/vfx-cli.mjs +31 -22
  6. package/tooling/vfx-package-resolution.mjs +8 -8
  7. package/docs/AUTHORING_EFFECTS.md +0 -297
  8. package/docs/INTEGRATION.md +0 -194
  9. package/docs/VFX_LIBRARY_ARCHITECTURE_chatgpt.md +0 -1580
  10. package/docs/VFX_LIBRARY_EXECUTION_PLAN.md +0 -229
  11. package/docs/VFX_LIBRARY_PLAN.md +0 -546
  12. package/docs/hit-flash-red-method.md +0 -155
  13. package/docs/treasure_attention_fx_babylonjs_guide.md +0 -901
  14. package/docs/vfx-ab/RESULTS.md +0 -35
  15. package/docs/vfx-ab/lumber-order/vehicle-exhaust-smoke/after.png +0 -0
  16. package/docs/vfx-ab/lumber-order/vehicle-exhaust-smoke/before.png +0 -0
  17. package/docs/vfx-ab/lumber-truck/vehicle-exhaust-smoke/after.png +0 -0
  18. package/docs/vfx-ab/lumber-truck/vehicle-exhaust-smoke/before.png +0 -0
  19. package/docs/vfx-integration_chatgpt.md +0 -462
  20. package/docs/vfx-placement-design.md +0 -164
  21. package/docs/weapon-trail-visualization.html +0 -241
  22. package/packages/EffectPackageService.ts +0 -346
  23. package/packages/SceneVfxService.ts +0 -96
  24. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/runtime/simpleMeshEffect.v1.js +0 -333
  25. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.frag.glsl +0 -25
  26. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.vert.glsl +0 -11
  27. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/textures/effect_jianbian.png +0 -0
  28. package/packages/build.mesh.yellow_build_upgrade_indicator/effect.json +0 -927
  29. package/packages/build.mesh.yellow_build_upgrade_indicator/media/contact-sheet.png +0 -0
  30. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.gif +0 -0
  31. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.mp4 +0 -0
  32. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.webm +0 -0
  33. package/packages/build.mesh.yellow_build_upgrade_indicator/media/thumbnail.png +0 -0
  34. package/packages/build.mesh.yellow_build_upgrade_indicator/metadata/description.json +0 -197
  35. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-effect.original.json +0 -895
  36. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-normalized-vfx-to-babylon-report.json +0 -241
  37. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-overrides.json +0 -542
  38. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-tuning-report.json +0 -69
  39. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/asset-map.json +0 -125
  40. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/lineage.json +0 -44
  41. package/packages/build.particle.golden_upgrade_starburst/assets/runtime/particleEmitter.v1.js +0 -210
  42. package/packages/build.particle.golden_upgrade_starburst/assets/textures/effect_guangdian.png +0 -0
  43. package/packages/build.particle.golden_upgrade_starburst/effect.json +0 -880
  44. package/packages/build.particle.golden_upgrade_starburst/media/contact-sheet.png +0 -0
  45. package/packages/build.particle.golden_upgrade_starburst/media/preview.gif +0 -0
  46. package/packages/build.particle.golden_upgrade_starburst/media/preview.mp4 +0 -0
  47. package/packages/build.particle.golden_upgrade_starburst/media/preview.webm +0 -0
  48. package/packages/build.particle.golden_upgrade_starburst/media/thumbnail.png +0 -0
  49. package/packages/build.particle.golden_upgrade_starburst/metadata/description.json +0 -161
  50. package/packages/build.particle.golden_upgrade_starburst/provenance/03-effect.original.json +0 -762
  51. package/packages/build.particle.golden_upgrade_starburst/provenance/03-normalized-vfx-to-babylon-report.json +0 -260
  52. package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-overrides.json +0 -436
  53. package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-tuning-report.json +0 -40
  54. package/packages/build.particle.golden_upgrade_starburst/provenance/asset-map.json +0 -115
  55. package/packages/build.particle.golden_upgrade_starburst/provenance/lineage.json +0 -40
  56. package/packages/build.particle.orange_upgrade_transform_sparks/assets/runtime/particleEmitter.v1.js +0 -210
  57. package/packages/build.particle.orange_upgrade_transform_sparks/assets/textures/b5b27ab1-e740-4398-b407-848fc2b2c897.png +0 -0
  58. package/packages/build.particle.orange_upgrade_transform_sparks/effect.json +0 -887
  59. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.gif +0 -0
  60. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.mp4 +0 -0
  61. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.webm +0 -0
  62. package/packages/build.particle.orange_upgrade_transform_sparks/media/thumbnail.png +0 -0
  63. package/packages/build.particle.orange_upgrade_transform_sparks/metadata/description.json +0 -179
  64. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-effect.original.json +0 -859
  65. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-normalized-vfx-to-babylon-report.json +0 -260
  66. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-overrides.json +0 -478
  67. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-tuning-report.json +0 -40
  68. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/asset-map.json +0 -114
  69. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/lineage.json +0 -41
  70. package/packages/build.particle.wood_chip_dust_burst/assets/runtime/particleEmitter.v1.js +0 -210
  71. package/packages/build.particle.wood_chip_dust_burst/assets/textures/effect_yanwu4.png +0 -0
  72. package/packages/build.particle.wood_chip_dust_burst/assets/textures/suipian3.png +0 -0
  73. package/packages/build.particle.wood_chip_dust_burst/effect.json +0 -1400
  74. package/packages/build.particle.wood_chip_dust_burst/media/contact-sheet.png +0 -0
  75. package/packages/build.particle.wood_chip_dust_burst/media/preview.gif +0 -0
  76. package/packages/build.particle.wood_chip_dust_burst/media/preview.mp4 +0 -0
  77. package/packages/build.particle.wood_chip_dust_burst/media/preview.webm +0 -0
  78. package/packages/build.particle.wood_chip_dust_burst/media/thumbnail.png +0 -0
  79. package/packages/build.particle.wood_chip_dust_burst/metadata/description.json +0 -173
  80. package/packages/build.particle.wood_chip_dust_burst/provenance/03-effect.original.json +0 -1277
  81. package/packages/build.particle.wood_chip_dust_burst/provenance/03-normalized-vfx-to-babylon-report.json +0 -329
  82. package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-overrides.json +0 -749
  83. package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-tuning-report.json +0 -60
  84. package/packages/build.particle.wood_chip_dust_burst/provenance/asset-map.json +0 -146
  85. package/packages/build.particle.wood_chip_dust_burst/provenance/lineage.json +0 -69
  86. package/packages/effects/building-upgrade/effect.json +0 -6
  87. package/packages/effects/building-upgrade/index.ts +0 -387
  88. package/packages/effects/character-entrance/effect.json +0 -6
  89. package/packages/effects/character-entrance/index.ts +0 -308
  90. package/packages/effects/coin-burst/index.ts +0 -48
  91. package/packages/effects/comet-trail-flame/assets/textures/trail_5x4.webp +0 -0
  92. package/packages/effects/comet-trail-flame/index.ts +0 -107
  93. package/packages/effects/conveyor-upgrade/effect.json +0 -6
  94. package/packages/effects/conveyor-upgrade/index.ts +0 -401
  95. package/packages/effects/debris-smoke/assets/models/rock_debris.glb +0 -0
  96. package/packages/effects/debris-smoke/assets/textures/smoke22.webp +0 -0
  97. package/packages/effects/debris-smoke/index.ts +0 -102
  98. package/packages/effects/door_open_gold_flakes/assets/runtime/goldFlakes.v1.js +0 -397
  99. package/packages/effects/door_open_gold_flakes/door_open_gold_flakes.json +0 -498
  100. package/packages/effects/door_open_gold_flakes/index.ts +0 -11
  101. package/packages/effects/electric-arc/assets/textures/spark_4x4.webp +0 -0
  102. package/packages/effects/electric-arc/index.ts +0 -63
  103. package/packages/effects/energy-shield/effect.json +0 -7
  104. package/packages/effects/energy-shield/index.ts +0 -432
  105. package/packages/effects/explosion/assets/textures/baozha29.webp +0 -0
  106. package/packages/effects/explosion/assets/textures/glow01.webp +0 -0
  107. package/packages/effects/explosion/assets/textures/lizi01.webp +0 -0
  108. package/packages/effects/explosion/assets/textures/xulie_lizibaozha02_5x5.webp +0 -0
  109. package/packages/effects/explosion/index.ts +0 -115
  110. package/packages/effects/ground-tile-upgrade/effect.json +0 -6
  111. package/packages/effects/ground-tile-upgrade/index.ts +0 -410
  112. package/packages/effects/hit-flash/index.ts +0 -77
  113. package/packages/effects/laser-beam/assets/textures/laser_glow.webp +0 -0
  114. package/packages/effects/laser-beam/assets/textures/laser_noise.webp +0 -0
  115. package/packages/effects/laser-beam/index.ts +0 -6
  116. package/packages/effects/laser-beam-factory.ts +0 -146
  117. package/packages/effects/lumber-cart-suction/effect.json +0 -6
  118. package/packages/effects/lumber-cart-suction/index.ts +0 -399
  119. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb +0 -0
  120. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb.versions/.active +0 -1
  121. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb.versions/1781589063890_upload.glb +0 -0
  122. package/packages/effects/lumber-debris-scatter/assets/runtime/solidParticleScatter.v1.js +0 -236
  123. package/packages/effects/lumber-debris-scatter/effect.json +0 -228
  124. package/packages/effects/lumber-debris-scatter/index.ts +0 -780
  125. package/packages/effects/lumber_vehicle_gear_spin/assets/runtime/gearSpin.v1.js +0 -202
  126. package/packages/effects/lumber_vehicle_gear_spin/index.ts +0 -11
  127. package/packages/effects/lumber_vehicle_gear_spin/lumber_vehicle_gear_spin.json +0 -338
  128. package/packages/effects/lumber_vehicle_upgrade_aura/assets/runtime/upgradeAura.v1.js +0 -353
  129. package/packages/effects/lumber_vehicle_upgrade_aura/index.ts +0 -13
  130. package/packages/effects/lumber_vehicle_upgrade_aura/lumber_vehicle_upgrade_aura.json +0 -365
  131. package/packages/effects/lumber_vehicle_wood_chips/assets/runtime/solidParticleScatter.v1.js +0 -310
  132. package/packages/effects/lumber_vehicle_wood_chips/index.ts +0 -11
  133. package/packages/effects/lumber_vehicle_wood_chips/lumber_vehicle_wood_chips.json +0 -335
  134. package/packages/effects/monster-hit/index.ts +0 -129
  135. package/packages/effects/player-upgrade/effect.json +0 -6
  136. package/packages/effects/player-upgrade/index.ts +0 -640
  137. package/packages/effects/pulse-laser-volley/assets/textures/bolt_guangshu.webp +0 -0
  138. package/packages/effects/pulse-laser-volley/index.ts +0 -215
  139. package/packages/effects/resource-collect-sparkles/effect.json +0 -6
  140. package/packages/effects/resource-collect-sparkles/index.ts +0 -254
  141. package/packages/effects/run-footstep-dust/assets/runtime/runFootstepDust.v1.js +0 -215
  142. package/packages/effects/run-footstep-dust/effect.json +0 -183
  143. package/packages/effects/run-footstep-dust/index.ts +0 -377
  144. package/packages/effects/space-shared.ts +0 -120
  145. package/packages/effects/thruster-flame/index.ts +0 -306
  146. package/packages/effects/treasure-attention/effect.json +0 -7
  147. package/packages/effects/treasure-attention/index.ts +0 -630
  148. package/packages/effects/tree-chop-dust/assets/textures/tree_chop_dust_atlas.png +0 -0
  149. package/packages/effects/tree-chop-dust/effect.json +0 -8
  150. package/packages/effects/tree-chop-dust/index.ts +0 -202
  151. package/packages/effects/tree-leaf-chop-burst/assets/runtime/particleEmitter.v1.js +0 -303
  152. package/packages/effects/tree-leaf-chop-burst/assets/textures/tree_leaf_chop_burst_leaf_atlas.png +0 -0
  153. package/packages/effects/tree-leaf-chop-burst/effect.json +0 -498
  154. package/packages/effects/tree-leaf-chop-burst/index.ts +0 -294
  155. package/packages/effects/tree_chop_dust_burst/assets/runtime/particleEmitter.v1.js +0 -318
  156. package/packages/effects/tree_chop_dust_burst/assets/textures/tree_chop_dust_burst_dust.png +0 -0
  157. package/packages/effects/tree_chop_dust_burst/index.ts +0 -13
  158. package/packages/effects/tree_chop_dust_burst/tree_chop_dust_burst.json +0 -412
  159. package/packages/effects/ufo-thread-flame/assets/textures/flame_flow.webp +0 -0
  160. package/packages/effects/ufo-thread-flame/assets/textures/flame_spike.webp +0 -0
  161. package/packages/effects/ufo-thread-flame/index.ts +0 -153
  162. package/packages/effects/vehicle-exhaust-smoke/assets/textures/vehicle_exhaust_smoke_atlas.png +0 -0
  163. package/packages/effects/vehicle-exhaust-smoke/effect.json +0 -8
  164. package/packages/effects/vehicle-exhaust-smoke/index.ts +0 -298
  165. package/packages/effects/vehicle-upgrade/effect.json +0 -6
  166. package/packages/effects/vehicle-upgrade/index.ts +0 -404
  167. package/packages/effects/weapon-trail/assets/textures/trail_wedge.png +0 -0
  168. package/packages/effects/weapon-trail/index.ts +0 -317
  169. package/packages/effects/wood-crusher-sawdust/assets/runtime/particleEmitter.v1.js +0 -312
  170. package/packages/effects/wood-crusher-sawdust/assets/textures/wood_crusher_sawdust_dust.png +0 -0
  171. package/packages/effects/wood-crusher-sawdust/assets/textures/wood_crusher_sawdust_fiber.png +0 -0
  172. package/packages/effects/wood-crusher-sawdust/index.ts +0 -43
  173. package/packages/effects/wood-crusher-sawdust/wood_crusher_sawdust.json +0 -592
  174. package/packages/effects/wood-cutter-sawdust/assets/runtime/particleEmitter.v1.js +0 -312
  175. package/packages/effects/wood-cutter-sawdust/assets/textures/wood_cutter_sawdust_chip.png +0 -0
  176. package/packages/effects/wood-cutter-sawdust/assets/textures/wood_cutter_sawdust_dust.png +0 -0
  177. package/packages/effects/wood-cutter-sawdust/index.ts +0 -43
  178. package/packages/effects/wood-cutter-sawdust/wood_cutter_sawdust.json +0 -592
  179. package/packages/effects/wood-sawdust-effect-factory.ts +0 -194
  180. package/packages/effects/wood_crusher_sawdust/assets/runtime/particleEmitter.v1.js +0 -318
  181. package/packages/effects/wood_crusher_sawdust/assets/textures/wood_crusher_sawdust_dust.png +0 -0
  182. package/packages/effects/wood_crusher_sawdust/assets/textures/wood_crusher_sawdust_fiber.png +0 -0
  183. package/packages/effects/wood_crusher_sawdust/index.ts +0 -29
  184. package/packages/effects/wood_crusher_sawdust/wood_crusher_sawdust.json +0 -592
  185. package/packages/effects/wood_cutter_sawdust/assets/runtime/particleEmitter.v1.js +0 -318
  186. package/packages/effects/wood_cutter_sawdust/assets/textures/wood_cutter_sawdust_chip.png +0 -0
  187. package/packages/effects/wood_cutter_sawdust/assets/textures/wood_cutter_sawdust_dust.png +0 -0
  188. package/packages/effects/wood_cutter_sawdust/index.ts +0 -29
  189. package/packages/effects/wood_cutter_sawdust/wood_cutter_sawdust.json +0 -592
  190. package/packages/effects/wood_peel_material_test/assets/runtime/woodPeelMaterialTest.v1.js +0 -196
  191. package/packages/effects/wood_peel_material_test/index.ts +0 -11
  192. package/packages/effects/wood_peel_material_test/wood_peel_material_test.json +0 -136
  193. package/packages/env.particle.forest_edge_fog/assets/runtime/particleEmitter.v1.js +0 -210
  194. package/packages/env.particle.forest_edge_fog/assets/textures/f12a23c4-b924-4322-a260-3d982428f1e8.png +0 -0
  195. package/packages/env.particle.forest_edge_fog/assets/textures/yuan.png +0 -0
  196. package/packages/env.particle.forest_edge_fog/effect.json +0 -854
  197. package/packages/env.particle.forest_edge_fog/media/preview.gif +0 -0
  198. package/packages/env.particle.forest_edge_fog/media/preview.mp4 +0 -0
  199. package/packages/env.particle.forest_edge_fog/media/preview.webm +0 -0
  200. package/packages/env.particle.forest_edge_fog/media/thumbnail.png +0 -0
  201. package/packages/env.particle.forest_edge_fog/metadata/description.json +0 -148
  202. package/packages/env.particle.forest_edge_fog/provenance/03-effect.original.json +0 -827
  203. package/packages/env.particle.forest_edge_fog/provenance/03-normalized-vfx-to-babylon-report.json +0 -196
  204. package/packages/env.particle.forest_edge_fog/provenance/04-preview-overrides.json +0 -432
  205. package/packages/env.particle.forest_edge_fog/provenance/04-preview-tuning-report.json +0 -28
  206. package/packages/env.particle.forest_edge_fog/provenance/asset-map.json +0 -124
  207. package/packages/env.particle.forest_edge_fog/provenance/lineage.json +0 -41
  208. package/packages/generation.ts +0 -14
  209. package/packages/index.ts +0 -14
  210. package/packages/legacy-particle-runtime.ts +0 -113
  211. package/packages/manifestRuntimePackage.ts +0 -519
  212. package/packages/registry.ts +0 -85
  213. package/packages/rendering.ts +0 -13
  214. package/packages/resource.particle.viscous_oil_suction/assets/runtime/top_disk_suction/particleEmitter.v1.js +0 -424
  215. package/packages/resource.particle.viscous_oil_suction/assets/textures/Glow ad.png +0 -0
  216. package/packages/resource.particle.viscous_oil_suction/effect.json +0 -1254
  217. package/packages/resource.particle.viscous_oil_suction/media/preview.gif +0 -0
  218. package/packages/resource.particle.viscous_oil_suction/media/preview.mp4 +0 -0
  219. package/packages/resource.particle.viscous_oil_suction/media/preview.webm +0 -0
  220. package/packages/resource.particle.viscous_oil_suction/media/thumbnail.png +0 -0
  221. package/packages/resource.particle.viscous_oil_suction/metadata/description.json +0 -122
  222. package/packages/resource.particle.viscous_oil_suction/provenance/03-effect.original.json +0 -1051
  223. package/packages/resource.particle.viscous_oil_suction/provenance/03-normalized-vfx-to-babylon-report.json +0 -200
  224. package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-overrides.json +0 -581
  225. package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-tuning-report.json +0 -28
  226. package/packages/resource.particle.viscous_oil_suction/provenance/asset-map.json +0 -111
  227. package/packages/resource.particle.viscous_oil_suction/provenance/lineage.json +0 -45
  228. package/packages/types.ts +0 -195
  229. package/tooling/check-dist-runtime.mjs +0 -166
  230. package/tooling/generate-index.mjs +0 -55
  231. package/tooling/test-guardrails.mjs +0 -157
  232. package/tooling/validate-boundary.mjs +0 -92
  233. package/tooling/validate-effects.mjs +0 -304
  234. package/tooling/validate.mjs +0 -53
@@ -1,640 +0,0 @@
1
- import { Color3, Color4 } from '@babylonjs/core/Maths/math.color';
2
- import { Vector3 } from '@babylonjs/core/Maths/math.vector';
3
- import { Constants } from '@babylonjs/core/Engines/constants';
4
- import { DynamicTexture } from '@babylonjs/core/Materials/Textures/dynamicTexture';
5
- import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial';
6
- import { CreateCylinder } from '@babylonjs/core/Meshes/Builders/cylinderBuilder';
7
- import { CreateDisc } from '@babylonjs/core/Meshes/Builders/discBuilder';
8
- import { CreatePlane } from '@babylonjs/core/Meshes/Builders/planeBuilder';
9
- import { CreateTorus } from '@babylonjs/core/Meshes/Builders/torusBuilder';
10
- import type { Mesh } from '@babylonjs/core/Meshes/mesh';
11
- import { ParticleSystem } from '@babylonjs/core/Particles/particleSystem';
12
- import type { Scene } from '@babylonjs/core/scene';
13
- import type { VfxColorValue, VfxEffectPackage, VfxParamValues } from '../../types';
14
- import { configureVfxParticleSystem, VFX_RENDERING_GROUP_ID } from '../../rendering';
15
- import manifest from './effect.json';
16
-
17
- interface PlayerUpgradeParams extends VfxParamValues {
18
- lifetime: number;
19
- scale: number;
20
- initialHeight: number;
21
- color: VfxColorValue;
22
- opacity: number;
23
- strandCount: number;
24
- strandLength: number;
25
- strandHeight: number;
26
- strandRadius: number;
27
- strandWidth: number;
28
- riseSpeed: number;
29
- ringCount: number;
30
- ringMaxRadius: number;
31
- ringThickness: number;
32
- ringInterval: number;
33
- ringOpacity: number;
34
- glowIntensity: number;
35
- glowHeight: number;
36
- glowWidth: number;
37
- }
38
-
39
- interface RingState {
40
- mesh: Mesh;
41
- material: StandardMaterial;
42
- startDelay: number;
43
- duration: number;
44
- }
45
-
46
- interface StrandMeshState {
47
- mesh: Mesh;
48
- material: StandardMaterial;
49
- height: number;
50
- startDelay: number;
51
- duration: number;
52
- }
53
-
54
- const strandTextureByScene = new WeakMap<Scene, DynamicTexture>();
55
- const glowTextureByScene = new WeakMap<Scene, DynamicTexture>();
56
- const haloTextureByScene = new WeakMap<Scene, DynamicTexture>();
57
-
58
- const DEFAULT_PARAMS: PlayerUpgradeParams = {
59
- lifetime: 2.4,
60
- scale: 1,
61
- initialHeight: 0.02,
62
- color: { r: 1, g: 0.78, b: 0.08 },
63
- opacity: 1,
64
- strandCount: 120,
65
- strandLength: 0.72,
66
- strandHeight: 1.55,
67
- strandRadius: 0.58,
68
- strandWidth: 0.075,
69
- riseSpeed: 1.45,
70
- ringCount: 4,
71
- ringMaxRadius: 2.15,
72
- ringThickness: 0.09,
73
- ringInterval: 0.28,
74
- ringOpacity: 1,
75
- glowIntensity: 1.85,
76
- glowHeight: 2.15,
77
- glowWidth: 1.08,
78
- };
79
-
80
- export const playerUpgradeEffectPackage: VfxEffectPackage<PlayerUpgradeParams> = {
81
- id: 'player-upgrade',
82
- nameZh: '人物&NPC升级',
83
- placement: 'socket',
84
- manifest,
85
- defaultParams: DEFAULT_PARAMS,
86
- // initialHeight 走 service 存活的 Y 偏移通道(不写 root.position,避免被 applySpawnToRoot 覆盖)(G6/M13)。
87
- spawnParams: { offsetY: 'initialHeight' },
88
- debugAnchor: 'player',
89
- debugParams: [
90
- { key: 'lifetime', label: '生命周期', kind: 'lifetime', min: 0.2, max: 6, step: 0.01 },
91
- { key: 'scale', label: '整体缩放', kind: 'scale', min: 0.1, max: 5, step: 0.01 },
92
- { key: 'initialHeight', label: '初始高度', kind: 'number', min: -1, max: 3, step: 0.01 },
93
- { key: 'color', label: '金光颜色', kind: 'color' },
94
- { key: 'opacity', label: '金丝透明度', kind: 'opacity', min: 0, max: 1, step: 0.01 },
95
- { key: 'strandCount', label: '金丝数量', kind: 'number', min: 0, max: 240, step: 1 },
96
- { key: 'strandLength', label: '金丝长度', kind: 'number', min: 0.05, max: 3, step: 0.01 },
97
- { key: 'strandHeight', label: '金丝上升高度', kind: 'number', min: 0.2, max: 5, step: 0.01 },
98
- { key: 'strandRadius', label: '金丝包围半径', kind: 'number', min: 0.05, max: 2, step: 0.01 },
99
- { key: 'strandWidth', label: '金丝粗细', kind: 'number', min: 0.005, max: 0.2, step: 0.001 },
100
- { key: 'riseSpeed', label: '金丝上升速度', kind: 'number', min: 0.05, max: 6, step: 0.01 },
101
- { key: 'ringCount', label: '亮环次数', kind: 'number', min: 0, max: 10, step: 1 },
102
- { key: 'ringMaxRadius', label: '亮环最大半径', kind: 'number', min: 0.1, max: 5, step: 0.01 },
103
- { key: 'ringThickness', label: '亮环粗细', kind: 'number', min: 0.005, max: 0.3, step: 0.001 },
104
- { key: 'ringInterval', label: '亮环间隔', kind: 'number', min: 0.02, max: 1.2, step: 0.01 },
105
- { key: 'ringOpacity', label: '亮环透明度', kind: 'opacity', min: 0, max: 1, step: 0.01 },
106
- { key: 'glowIntensity', label: '光芒强度', kind: 'number', min: 0, max: 3, step: 0.01 },
107
- { key: 'glowHeight', label: '光柱高度', kind: 'number', min: 0.2, max: 5, step: 0.01 },
108
- { key: 'glowWidth', label: '光柱宽度', kind: 'number', min: 0.1, max: 4, step: 0.01 },
109
- ],
110
- create({ scene, root, position, params }) {
111
- markVfxRoot(root);
112
- root.position.copyFrom(position); // 高度偏移由 service 经 spawnParams.offsetY 施加(存活)
113
- const strands = createStrandSystem(scene, root, params);
114
- const strandMeshes = createStrandMeshes(scene, root, params);
115
- const rings = createExpandingRings(scene, root, params);
116
- const glowAura = createGlowAura(scene, root, params);
117
- let disposed = false;
118
- const disposeTimer = window.setTimeout(() => disposeAll(), getDisposeDelaySeconds(params) * 1000);
119
-
120
- strands.start();
121
-
122
- return {
123
- root,
124
- dispose() {
125
- disposeAll();
126
- },
127
- };
128
-
129
- function disposeAll(): void {
130
- if (disposed) return;
131
- disposed = true;
132
- window.clearTimeout(disposeTimer);
133
- strands.stop();
134
- // dispose(false):金丝粒子贴图是按 scene 缓存的共享 DynamicTexture(strandTextureByScene),
135
- // ParticleSystem.dispose() 默认 disposeTexture=true 会销毁它,WeakMap 却仍持失效引用 →
136
- // 二次升级金丝空白。纹理生命周期绑 scene、跨播放复用,故不随实例销毁。
137
- strands.dispose(false);
138
- strandMeshes.dispose();
139
- rings.dispose();
140
- glowAura.dispose();
141
- cleanupPlanarShadowArtifacts(scene);
142
- root.dispose();
143
- }
144
- },
145
- };
146
-
147
- function markVfxRoot(root: unknown): void {
148
- const target = root as { metadata?: Record<string, unknown> | null };
149
- target.metadata = {
150
- ...(target.metadata ?? {}),
151
- disablePlanarShadow: true,
152
- disablePostOutlineDepth: true,
153
- };
154
- }
155
-
156
- function prepareVfxMesh(mesh: Mesh): void {
157
- mesh.isPickable = false;
158
- mesh.checkCollisions = false;
159
- mesh.receiveShadows = false;
160
- mesh.metadata = {
161
- ...((mesh.metadata as Record<string, unknown> | null) ?? {}),
162
- disablePlanarShadow: true,
163
- disablePostOutlineDepth: true,
164
- };
165
- }
166
-
167
- function cleanupPlanarShadowArtifacts(scene: Scene): void {
168
- for (const mesh of [...scene.meshes]) {
169
- if (mesh.name.startsWith('player-upgrade.') && mesh.name.includes('_planarShadow')) {
170
- mesh.dispose();
171
- }
172
- }
173
-
174
- for (const node of [...scene.transformNodes]) {
175
- if (node.name.startsWith('player-upgrade.') && node.name.includes('_shadow_root')) {
176
- node.dispose();
177
- }
178
- }
179
- }
180
-
181
- function createGlowAura(scene: Scene, root: { getAbsolutePosition(): Vector3 }, params: PlayerUpgradeParams): { dispose(): void } {
182
- const effectScale = Math.max(0.05, params.scale);
183
- const color = params.color;
184
- const glowHeight = Math.max(0.1, params.glowHeight) * effectScale;
185
- const glowWidth = Math.max(0.05, params.glowWidth) * effectScale;
186
- const glowIntensity = Math.max(0, params.glowIntensity);
187
- const meshes: Mesh[] = [];
188
- const materials: StandardMaterial[] = [];
189
-
190
- for (let index = 0; index < 3; index += 1) {
191
- const mesh = CreatePlane(`player-upgrade.soft-glow-column.${index}`, { size: 1 }, scene);
192
- prepareVfxMesh(mesh);
193
- mesh.parent = root as any;
194
- mesh.position.y = glowHeight * 0.48;
195
- mesh.rotation.y = (index * Math.PI) / 3;
196
- mesh.scaling.set(glowWidth, glowHeight, 1);
197
- mesh.renderingGroupId = VFX_RENDERING_GROUP_ID;
198
-
199
- const material = new StandardMaterial(`player-upgrade.soft-glow-column-material.${index}`, scene);
200
- configureTexturedGlowMaterial(material, color, getGlowTexture(scene), 2.8);
201
- material.alpha = 0;
202
- mesh.material = material;
203
-
204
- meshes.push(mesh);
205
- materials.push(material);
206
- }
207
-
208
- const halo = CreateDisc('player-upgrade.ground-halo', { radius: 1, tessellation: 96 }, scene);
209
- prepareVfxMesh(halo);
210
- halo.parent = root as any;
211
- halo.position.y = 0.025 * effectScale;
212
- halo.rotation.x = Math.PI / 2;
213
- halo.scaling.set(glowWidth * 1.12, glowWidth * 1.12, 1);
214
- halo.renderingGroupId = VFX_RENDERING_GROUP_ID;
215
-
216
- const haloMaterial = new StandardMaterial('player-upgrade.ground-halo-material', scene);
217
- configureTexturedGlowMaterial(haloMaterial, color, getHaloTexture(scene), 2.4);
218
- haloMaterial.alpha = 0;
219
- halo.material = haloMaterial;
220
- meshes.push(halo);
221
- materials.push(haloMaterial);
222
-
223
- let age = 0;
224
- let disposed = false;
225
- const observer = scene.onBeforeRenderObservable.add(() => {
226
- if (disposed) return;
227
- const deltaSeconds = Math.min(0.05, scene.getEngine().getDeltaTime() / 1000);
228
- age += deltaSeconds;
229
- const lifetime = Math.max(0.2, params.lifetime);
230
- const t = Math.min(1, age / lifetime);
231
- const fadeIn = Math.min(1, t / 0.12);
232
- const fadeOut = Math.max(0, 1 - Math.max(0, t - 0.72) / 0.28);
233
- const pulse = 0.86 + Math.sin(age * 13) * 0.1 + Math.sin(age * 23) * 0.04;
234
- const columnAlpha = Math.min(1, glowIntensity * params.opacity * 0.56 * fadeIn * fadeOut * pulse);
235
- const haloAlpha = Math.min(1, glowIntensity * params.ringOpacity * 0.68 * fadeIn * fadeOut);
236
-
237
- for (let index = 0; index < materials.length; index += 1) {
238
- materials[index].alpha = index === materials.length - 1 ? haloAlpha : columnAlpha;
239
- }
240
-
241
- const haloRadius = glowWidth * 1.12 * (1 + easeOutCubic(t) * 0.34);
242
- halo.scaling.set(haloRadius, haloRadius, 1);
243
-
244
- if (age >= lifetime + 0.35) dispose();
245
- });
246
-
247
- function dispose(): void {
248
- if (disposed) return;
249
- disposed = true;
250
- scene.onBeforeRenderObservable.remove(observer);
251
- for (const mesh of meshes) mesh.dispose();
252
- for (const material of materials) material.dispose();
253
- }
254
-
255
- return { dispose };
256
- }
257
-
258
- function createStrandSystem(scene: Scene, root: { getAbsolutePosition(): Vector3 }, params: PlayerUpgradeParams): ParticleSystem {
259
- const effectScale = Math.max(0.05, params.scale);
260
- const count = Math.max(0, Math.round(params.strandCount));
261
- const color = params.color;
262
- const bright = brighten(color, 0.72);
263
- const strandLength = Math.max(0.05, params.strandLength) * effectScale;
264
- const strandRadius = Math.max(0, params.strandRadius) * effectScale;
265
- const strandWidth = Math.max(0.001, params.strandWidth) * effectScale;
266
-
267
- const system = new ParticleSystem('player-upgrade.gold-strands', Math.max(1, count), scene);
268
- configureVfxParticleSystem(system);
269
- system.particleTexture = getStrandTexture(scene);
270
- system.particleTexture.hasAlpha = true;
271
- system.emitter = root as any;
272
- system.manualEmitCount = count;
273
- system.emitRate = count * 60;
274
- system.targetStopDuration = 0.05;
275
- system.disposeOnStop = false;
276
- system.blendMode = ParticleSystem.BLENDMODE_ADD;
277
- system.minLifeTime = Math.max(0.12, params.lifetime * 0.52);
278
- system.maxLifeTime = Math.max(system.minLifeTime + 0.01, params.lifetime * 0.95);
279
- system.minSize = Math.max(0.04, strandLength * 0.42);
280
- system.maxSize = Math.max(system.minSize, strandLength * 0.9);
281
- system.minScaleX = strandWidth;
282
- system.maxScaleX = strandWidth * 1.8;
283
- system.minScaleY = 1;
284
- system.maxScaleY = 1.6;
285
- system.minEmitPower = Math.max(0.01, params.riseSpeed * effectScale * 0.55);
286
- system.maxEmitPower = Math.max(system.minEmitPower, params.riseSpeed * effectScale * 1.28);
287
- system.gravity = new Vector3(0, 0.34 * effectScale, 0);
288
- system.updateSpeed = 1 / 60;
289
- system.color1 = toColor4(color, params.opacity * 0.72);
290
- system.color2 = toColor4(bright, params.opacity);
291
- system.colorDead = toColor4(color, 0);
292
- system.addColorGradient(0, toColor4(color, 0));
293
- system.addColorGradient(0.13, toColor4(bright, params.opacity));
294
- system.addColorGradient(0.72, toColor4(color, params.opacity * 0.58));
295
- system.addColorGradient(1, toColor4(color, 0));
296
- system.addVelocityGradient(0, 1);
297
- system.addVelocityGradient(0.66, 0.62);
298
- system.addVelocityGradient(1, 0.16);
299
-
300
- let positionIndex = 0;
301
- let directionIndex = 0;
302
- system.startPositionFunction = (worldMatrix, positionToUpdate, particle, isLocal) => {
303
- const index = particle.id + positionIndex;
304
- positionIndex += 1;
305
- const angle = sequence01(index, 0) * Math.PI * 2;
306
- const radius = Math.sqrt(sequence01(index, 1)) * strandRadius;
307
- const local = new Vector3(
308
- Math.cos(angle) * radius,
309
- sequence01(index, 2) * 0.08 * effectScale,
310
- Math.sin(angle) * radius,
311
- );
312
- if (isLocal) positionToUpdate.copyFrom(local);
313
- else Vector3.TransformCoordinatesToRef(local, worldMatrix, positionToUpdate);
314
- };
315
- system.startDirectionFunction = (worldMatrix, directionToUpdate, particle, isLocal) => {
316
- const index = particle.id + directionIndex;
317
- directionIndex += 1;
318
- const sway = strandRadius * 0.16;
319
- const local = new Vector3(
320
- (sequence01(index, 3) - 0.5) * sway,
321
- 0.86 + sequence01(index, 4) * 0.52,
322
- (sequence01(index, 5) - 0.5) * sway,
323
- );
324
- if (isLocal) directionToUpdate.copyFrom(local);
325
- else Vector3.TransformNormalToRef(local, worldMatrix, directionToUpdate);
326
- };
327
-
328
- return system;
329
- }
330
-
331
- function createStrandMeshes(scene: Scene, root: { getAbsolutePosition(): Vector3 }, params: PlayerUpgradeParams): { dispose(): void } {
332
- const effectScale = Math.max(0.05, params.scale);
333
- const count = Math.min(90, Math.max(0, Math.round(params.strandCount * 0.62)));
334
- const color = params.color;
335
- const radius = Math.max(0.04, params.strandRadius * effectScale);
336
- const strandLength = Math.max(0.05, params.strandLength * effectScale);
337
- const riseHeight = Math.max(0.1, params.strandHeight * effectScale);
338
- const width = Math.max(0.005, params.strandWidth * effectScale * 1.25);
339
- const speedScale = Math.max(0.2, params.riseSpeed / DEFAULT_PARAMS.riseSpeed);
340
- const duration = Math.max(0.22, params.lifetime * 0.72 / speedScale);
341
- const states: StrandMeshState[] = [];
342
-
343
- for (let index = 0; index < count; index += 1) {
344
- const angle = sequence01(index, 0) * Math.PI * 2;
345
- const localRadius = radius * lerp(0.42, 1.08, sequence01(index, 1));
346
- const mesh = CreateCylinder(
347
- `player-upgrade.gold-strand-mesh.${index}`,
348
- { height: 1, diameter: width, tessellation: 6 },
349
- scene,
350
- );
351
- prepareVfxMesh(mesh);
352
- mesh.parent = root as any;
353
- mesh.position.x = Math.cos(angle) * localRadius;
354
- mesh.position.z = Math.sin(angle) * localRadius;
355
- mesh.position.y = 0;
356
- mesh.renderingGroupId = VFX_RENDERING_GROUP_ID;
357
- mesh.isVisible = false;
358
-
359
- const material = new StandardMaterial(`player-upgrade.gold-strand-mesh-material.${index}`, scene);
360
- configureGlowMaterial(material, color, 2.8);
361
- material.alpha = 0;
362
- mesh.material = material;
363
-
364
- states.push({
365
- mesh,
366
- material,
367
- height: strandLength * lerp(0.68, 1.18, sequence01(index, 2)),
368
- startDelay: sequence01(index, 3) * Math.min(0.34, params.lifetime * 0.18),
369
- duration: duration * lerp(0.78, 1.12, sequence01(index, 4)),
370
- });
371
- }
372
-
373
- let age = 0;
374
- let disposed = false;
375
- const observer = scene.onBeforeRenderObservable.add(() => {
376
- if (disposed) return;
377
- const deltaSeconds = Math.min(0.05, scene.getEngine().getDeltaTime() / 1000);
378
- age += deltaSeconds;
379
- for (const state of states) {
380
- const localAge = age - state.startDelay;
381
- if (localAge < 0 || localAge > state.duration) {
382
- state.mesh.isVisible = false;
383
- state.material.alpha = 0;
384
- continue;
385
- }
386
- const t = Math.min(1, localAge / state.duration);
387
- const grow = Math.min(1, t / 0.32);
388
- const fadeOut = Math.max(0, 1 - Math.max(0, t - 0.66) / 0.34);
389
- const alpha = params.opacity * fadeOut * Math.min(1, t / 0.12);
390
- const currentHeight = state.height * grow;
391
- state.mesh.isVisible = alpha > 0.01;
392
- state.mesh.scaling.set(1, currentHeight, 1);
393
- state.mesh.position.y = currentHeight * 0.5 + riseHeight * easeOutCubic(t);
394
- state.material.alpha = Math.min(1, alpha * 1.35);
395
- }
396
- if (age >= params.lifetime + 0.45) dispose();
397
- });
398
-
399
- function dispose(): void {
400
- if (disposed) return;
401
- disposed = true;
402
- scene.onBeforeRenderObservable.remove(observer);
403
- for (const state of states) {
404
- state.mesh.dispose();
405
- state.material.dispose();
406
- }
407
- }
408
-
409
- return { dispose };
410
- }
411
-
412
- function createExpandingRings(scene: Scene, root: { getAbsolutePosition(): Vector3 }, params: PlayerUpgradeParams): { dispose(): void } {
413
- const effectScale = Math.max(0.05, params.scale);
414
- const ringCount = Math.max(0, Math.round(params.ringCount));
415
- const ringDuration = Math.max(0.18, Math.min(0.9, params.lifetime * 0.38));
416
- const minRadius = 0.14 * effectScale;
417
- const maxRadius = Math.max(minRadius + 0.01, params.ringMaxRadius * effectScale);
418
- const thickness = Math.max(0.002, params.ringThickness * effectScale);
419
- const color = params.color;
420
- const states: RingState[] = [];
421
-
422
- for (let index = 0; index < ringCount; index += 1) {
423
- const mesh = CreateTorus(
424
- `player-upgrade.expanding-ring.${index}`,
425
- { diameter: 1, thickness, tessellation: 96 },
426
- scene,
427
- );
428
- prepareVfxMesh(mesh);
429
- mesh.parent = root as any;
430
- mesh.position.y = 0.03 * effectScale + index * 0.012 * effectScale;
431
- mesh.renderingGroupId = VFX_RENDERING_GROUP_ID;
432
- mesh.isVisible = false;
433
-
434
- const material = new StandardMaterial(`player-upgrade.ring-material.${index}`, scene);
435
- configureGlowMaterial(material, color, 2.4);
436
- material.alpha = 0;
437
- mesh.material = material;
438
-
439
- states.push({
440
- mesh,
441
- material,
442
- startDelay: index * Math.max(0.02, params.ringInterval),
443
- duration: ringDuration,
444
- });
445
- }
446
-
447
- let age = 0;
448
- let disposed = false;
449
- const observer = scene.onBeforeRenderObservable.add(() => {
450
- if (disposed) return;
451
- const deltaSeconds = Math.min(0.05, scene.getEngine().getDeltaTime() / 1000);
452
- age += deltaSeconds;
453
- for (const state of states) {
454
- const localAge = age - state.startDelay;
455
- if (localAge < 0 || localAge > state.duration) {
456
- state.mesh.isVisible = false;
457
- state.material.alpha = 0;
458
- continue;
459
- }
460
- const t = Math.min(1, localAge / state.duration);
461
- const eased = easeOutCubic(t);
462
- const radius = lerp(minRadius, maxRadius, eased);
463
- const alpha = params.ringOpacity * (1 - t) * Math.min(1, t / 0.12);
464
- state.mesh.isVisible = alpha > 0.01;
465
- state.mesh.scaling.set(radius, radius, radius);
466
- const ringColor = brighten(color, 0.1 + 0.08 * (1 - t));
467
- state.material.diffuseColor = toColor3(ringColor);
468
- state.material.emissiveColor = toGlowColor3(ringColor, 3.4);
469
- state.material.alpha = Math.min(1, alpha * 1.45);
470
- }
471
- if (age >= getLastRingEndTime(params, ringDuration) + 0.1) dispose();
472
- });
473
-
474
- function dispose(): void {
475
- if (disposed) return;
476
- disposed = true;
477
- scene.onBeforeRenderObservable.remove(observer);
478
- for (const state of states) {
479
- state.mesh.dispose();
480
- state.material.dispose();
481
- }
482
- }
483
-
484
- return { dispose };
485
- }
486
-
487
- function getStrandTexture(scene: Scene): DynamicTexture {
488
- const existing = strandTextureByScene.get(scene);
489
- if (existing) return existing;
490
- const texture = new DynamicTexture('player_upgrade_gold_strand_texture', { width: 48, height: 192 }, scene, true);
491
- const context = texture.getContext();
492
- context.clearRect(0, 0, 48, 192);
493
- const glow = context.createLinearGradient(0, 0, 0, 192);
494
- glow.addColorStop(0, 'rgba(255,255,255,0)');
495
- glow.addColorStop(0.18, 'rgba(255,255,255,0.9)');
496
- glow.addColorStop(0.62, 'rgba(255,255,255,0.5)');
497
- glow.addColorStop(1, 'rgba(255,255,255,0)');
498
- context.fillStyle = glow;
499
- context.fillRect(19, 0, 10, 192);
500
- context.fillStyle = 'rgba(255,255,255,0.95)';
501
- context.fillRect(23, 8, 2, 168);
502
- texture.hasAlpha = true;
503
- texture.update(false);
504
- strandTextureByScene.set(scene, texture);
505
- return texture;
506
- }
507
-
508
- function getGlowTexture(scene: Scene): DynamicTexture {
509
- const existing = glowTextureByScene.get(scene);
510
- if (existing) return existing;
511
-
512
- const texture = new DynamicTexture('player_upgrade_soft_glow_texture', { width: 256, height: 512 }, scene, true);
513
- const context = texture.getContext();
514
- context.clearRect(0, 0, 256, 512);
515
-
516
- const vertical = context.createLinearGradient(0, 0, 0, 512);
517
- vertical.addColorStop(0, 'rgba(255,255,255,0)');
518
- vertical.addColorStop(0.16, 'rgba(255,255,255,0.28)');
519
- vertical.addColorStop(0.46, 'rgba(255,255,255,0.72)');
520
- vertical.addColorStop(0.78, 'rgba(255,255,255,0.22)');
521
- vertical.addColorStop(1, 'rgba(255,255,255,0)');
522
- context.fillStyle = vertical;
523
- context.fillRect(0, 0, 256, 512);
524
-
525
- const radial = context.createRadialGradient(128, 262, 6, 128, 262, 120);
526
- radial.addColorStop(0, 'rgba(255,255,255,1)');
527
- radial.addColorStop(0.18, 'rgba(255,255,255,0.76)');
528
- radial.addColorStop(0.48, 'rgba(255,255,255,0.22)');
529
- radial.addColorStop(1, 'rgba(255,255,255,0)');
530
- const compositeContext = context as unknown as CanvasRenderingContext2D;
531
- compositeContext.globalCompositeOperation = 'destination-in';
532
- context.fillStyle = radial;
533
- context.fillRect(0, 0, 256, 512);
534
- compositeContext.globalCompositeOperation = 'source-over';
535
-
536
- texture.hasAlpha = true;
537
- texture.update(false);
538
- glowTextureByScene.set(scene, texture);
539
- return texture;
540
- }
541
-
542
- function getHaloTexture(scene: Scene): DynamicTexture {
543
- const existing = haloTextureByScene.get(scene);
544
- if (existing) return existing;
545
-
546
- const texture = new DynamicTexture('player_upgrade_ground_halo_texture', { width: 256, height: 256 }, scene, true);
547
- const context = texture.getContext();
548
- context.clearRect(0, 0, 256, 256);
549
-
550
- const halo = context.createRadialGradient(128, 128, 18, 128, 128, 128);
551
- halo.addColorStop(0, 'rgba(255,255,255,0.74)');
552
- halo.addColorStop(0.34, 'rgba(255,255,255,0.42)');
553
- halo.addColorStop(0.58, 'rgba(255,255,255,0.16)');
554
- halo.addColorStop(0.76, 'rgba(255,255,255,0.04)');
555
- halo.addColorStop(1, 'rgba(255,255,255,0)');
556
- context.fillStyle = halo;
557
- context.fillRect(0, 0, 256, 256);
558
-
559
- texture.hasAlpha = true;
560
- texture.update(false);
561
- haloTextureByScene.set(scene, texture);
562
- return texture;
563
- }
564
-
565
- function getDisposeDelaySeconds(params: PlayerUpgradeParams): number {
566
- const ringDuration = Math.max(0.18, Math.min(0.9, params.lifetime * 0.38));
567
- return Math.max(0.2, params.lifetime) + getLastRingEndTime(params, ringDuration) + 0.35;
568
- }
569
-
570
- function getLastRingEndTime(params: PlayerUpgradeParams, ringDuration: number): number {
571
- return Math.max(0, Math.round(params.ringCount) - 1) * Math.max(0.02, params.ringInterval) + ringDuration;
572
- }
573
-
574
- function toColor4(color: VfxColorValue, alpha: number): Color4 {
575
- return new Color4(clamp01(color.r), clamp01(color.g), clamp01(color.b), clamp01(alpha));
576
- }
577
-
578
- function toColor3(color: VfxColorValue): Color3 {
579
- return new Color3(clamp01(color.r), clamp01(color.g), clamp01(color.b));
580
- }
581
-
582
- function toGlowColor3(color: VfxColorValue, intensity: number): Color3 {
583
- return new Color3(
584
- Math.max(0, color.r * intensity),
585
- Math.max(0, color.g * intensity),
586
- Math.max(0, color.b * intensity),
587
- );
588
- }
589
-
590
- function configureGlowMaterial(material: StandardMaterial, color: VfxColorValue, intensity: number): void {
591
- material.disableLighting = true;
592
- material.backFaceCulling = false;
593
- material.diffuseColor = toColor3(color);
594
- material.emissiveColor = toGlowColor3(color, intensity);
595
- material.specularColor = Color3.Black();
596
- material.alphaMode = Constants.ALPHA_ADD;
597
- material.transparencyMode = StandardMaterial.MATERIAL_ALPHABLEND;
598
- }
599
-
600
- function configureTexturedGlowMaterial(
601
- material: StandardMaterial,
602
- color: VfxColorValue,
603
- texture: DynamicTexture,
604
- intensity: number,
605
- ): void {
606
- configureGlowMaterial(material, color, intensity);
607
- material.diffuseTexture = texture;
608
- material.opacityTexture = texture;
609
- material.useAlphaFromDiffuseTexture = true;
610
- }
611
-
612
- function brighten(color: VfxColorValue, amount: number): VfxColorValue {
613
- return {
614
- r: lerp(color.r, 1, amount),
615
- g: lerp(color.g, 1, amount),
616
- b: lerp(color.b, 1, amount),
617
- };
618
- }
619
-
620
- function easeOutCubic(t: number): number {
621
- return 1 - (1 - t) ** 3;
622
- }
623
-
624
- function lerp(min: number, max: number, t: number): number {
625
- return min + (max - min) * t;
626
- }
627
-
628
- function clamp01(value: number): number {
629
- return Math.min(1, Math.max(0, value));
630
- }
631
-
632
- function fract(value: number): number {
633
- return value - Math.floor(value);
634
- }
635
-
636
- function sequence01(index: number, axis: number): number {
637
- if (index === 0) return 0.5;
638
- const strides = [0.618033988749895, 0.414213562373095, 0.732050807568877, 0.324717957244746, 0.754877666246693, 0.569840290998053];
639
- return fract(0.5 + index * strides[axis % strides.length] + axis * 0.173205080756888);
640
- }