@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,410 +0,0 @@
1
- import { Color4 } from '@babylonjs/core/Maths/math.color';
2
- import { Matrix, Vector3 } from '@babylonjs/core/Maths/math.vector';
3
- import { DynamicTexture } from '@babylonjs/core/Materials/Textures/dynamicTexture';
4
- import type { TransformNode } from '@babylonjs/core/Meshes/transformNode';
5
- import type { Particle } from '@babylonjs/core/Particles/particle';
6
- import { ParticleSystem } from '@babylonjs/core/Particles/particleSystem';
7
- import type { Scene } from '@babylonjs/core/scene';
8
- import type { VfxColorValue, VfxEffectPackage, VfxParamValues } from '../../types';
9
- import { configureVfxParticleSystem } from '../../rendering';
10
- import manifest from './effect.json';
11
-
12
- interface GroundTileUpgradeParams extends VfxParamValues {
13
- lifetime: number;
14
- scale: number;
15
- initialHeight: number;
16
- color: VfxColorValue;
17
- opacity: number;
18
- scaleX: number;
19
- scaleY: number;
20
- scaleZ: number;
21
- centerCount: number;
22
- outlineCount: number;
23
- strandWidth: number;
24
- riseSpeed: number;
25
- centerSpread: number;
26
- outlineThickness: number;
27
- glowOpacity: number;
28
- }
29
-
30
- const BASE_FOOTPRINT_X = 3.2;
31
- const BASE_FOOTPRINT_Z = 2.6;
32
- const BASE_CENTER_HEIGHT = 2.2;
33
- const BASE_OUTLINE_HEIGHT = 3.1;
34
- const BASE_GLOW_THICKNESS = 0.38;
35
-
36
- const DEFAULT_PARAMS: GroundTileUpgradeParams = {
37
- lifetime: 1.8,
38
- scale: 1,
39
- initialHeight: 0.02,
40
- color: { r: 1, g: 0.84, b: 0.12 },
41
- opacity: 1,
42
- scaleX: 0.82,
43
- scaleY: 0.24,
44
- scaleZ: 0.82,
45
- centerCount: 46,
46
- outlineCount: 150,
47
- strandWidth: 0.035,
48
- riseSpeed: 1.15,
49
- centerSpread: 0.92,
50
- outlineThickness: 0.18,
51
- glowOpacity: 0.62,
52
- };
53
-
54
- export const groundTileUpgradeEffectPackage: VfxEffectPackage<GroundTileUpgradeParams> = {
55
- id: 'ground-tile-upgrade',
56
- nameZh: '地块升级光效',
57
- manifest,
58
- defaultParams: DEFAULT_PARAMS,
59
- debugAnchor: 'playerRight',
60
- debugParams: [
61
- { key: 'lifetime', label: '生命周期', kind: 'lifetime', min: 0.2, max: 6, step: 0.01 },
62
- { key: 'scale', label: '整体缩放', kind: 'scale', min: 0.1, max: 6, step: 0.01 },
63
- { key: 'initialHeight', label: '初始高度', kind: 'number', min: -1, max: 3, step: 0.01 },
64
- { key: 'color', label: '光效颜色', kind: 'color' },
65
- { key: 'opacity', label: '透明度', kind: 'opacity', min: 0, max: 1, step: 0.01 },
66
- { key: 'scaleX', label: 'X 轴缩放', kind: 'number', min: 0.1, max: 6, step: 0.01 },
67
- { key: 'scaleY', label: 'Y 轴缩放', kind: 'number', min: 0.1, max: 6, step: 0.01 },
68
- { key: 'scaleZ', label: 'Z 轴缩放', kind: 'number', min: 0.1, max: 6, step: 0.01 },
69
- { key: 'centerCount', label: '中心光丝数量', kind: 'number', min: 0, max: 240, step: 1 },
70
- { key: 'outlineCount', label: '轮廓光丝数量', kind: 'number', min: 0, max: 420, step: 1 },
71
- { key: 'strandWidth', label: '光丝粗细', kind: 'number', min: 0.005, max: 0.2, step: 0.001 },
72
- { key: 'riseSpeed', label: '上升速度', kind: 'number', min: 0, max: 5, step: 0.01 },
73
- { key: 'centerSpread', label: '中心散布', kind: 'number', min: 0, max: 1.5, step: 0.01 },
74
- { key: 'outlineThickness', label: '轮廓厚度', kind: 'number', min: 0, max: 1, step: 0.01 },
75
- { key: 'glowOpacity', label: '光幕强度', kind: 'opacity', min: 0, max: 1, step: 0.01 },
76
- ],
77
- create({ scene, root, position, params }) {
78
- root.position.copyFrom(position).addInPlace(new Vector3(0, params.initialHeight, 0));
79
-
80
- const centerStrands = createStrandSystem(scene, root, params, 'center');
81
- const outlineStrands = createStrandSystem(scene, root, params, 'outline');
82
- const glow = createOutlineGlow(scene, root, params);
83
- let disposed = false;
84
- const disposeTimer = window.setTimeout(
85
- () => disposeAll(),
86
- Math.max(0.05, params.lifetime + getMaxStrandHeight(params) / Math.max(0.1, params.riseSpeed) * 0.18 + 0.45) * 1000,
87
- );
88
-
89
- centerStrands.start();
90
- outlineStrands.start();
91
- glow.start();
92
-
93
- return {
94
- root,
95
- dispose() {
96
- disposeAll();
97
- },
98
- };
99
-
100
- function disposeAll(): void {
101
- if (disposed) return;
102
- disposed = true;
103
- window.clearTimeout(disposeTimer);
104
- centerStrands.dispose(false);
105
- outlineStrands.dispose(false);
106
- glow.dispose(false);
107
- root.dispose();
108
- }
109
- },
110
- };
111
-
112
- function createStrandSystem(
113
- scene: Scene,
114
- root: TransformNode,
115
- params: GroundTileUpgradeParams,
116
- mode: 'center' | 'outline',
117
- ): ParticleSystem {
118
- const count = Math.max(0, Math.round(mode === 'center' ? params.centerCount : params.outlineCount));
119
- const system = new ParticleSystem(`ground-tile-upgrade.${mode}-strands`, Math.max(1, count), scene);
120
- const color = params.color;
121
- const brightColor = getBrightColor(color);
122
- const height = mode === 'center' ? getCenterHeight(params) : getOutlineHeight(params);
123
- const width = params.strandWidth * getHorizontalScale(params) * (mode === 'center' ? 1.35 : 0.92);
124
-
125
- configureVfxParticleSystem(system);
126
- system.particleTexture = getStrandTexture(scene);
127
- system.emitter = root as any;
128
- system.manualEmitCount = count;
129
- system.emitRate = count * 60;
130
- system.disposeOnStop = false;
131
- system.updateSpeed = 1 / 60;
132
- system.minLifeTime = Math.max(0.12, params.lifetime * (mode === 'center' ? 0.48 : 0.62));
133
- system.maxLifeTime = Math.max(system.minLifeTime + 0.01, params.lifetime * (mode === 'center' ? 0.86 : 1.08));
134
- system.minSize = Math.max(0.01, height * 0.34);
135
- system.maxSize = Math.max(system.minSize, height * (mode === 'center' ? 0.72 : 0.98));
136
- system.minScaleX = Math.max(0.02, width);
137
- system.maxScaleX = Math.max(system.minScaleX, width * 1.8);
138
- system.minScaleY = 1;
139
- system.maxScaleY = mode === 'center' ? 1.45 : 1.75;
140
- system.minEmitPower = Math.max(0.01, params.riseSpeed * getVerticalScale(params) * (mode === 'center' ? 0.5 : 0.7));
141
- system.maxEmitPower = Math.max(system.minEmitPower, params.riseSpeed * getVerticalScale(params) * (mode === 'center' ? 1.15 : 1.65));
142
- system.gravity = new Vector3(0, 0.38 * getVerticalScale(params), 0);
143
- system.blendMode = ParticleSystem.BLENDMODE_ADD;
144
- system.color1 = toColor4(color, params.opacity * (mode === 'center' ? 0.72 : 0.86));
145
- system.color2 = toColor4(brightColor, params.opacity);
146
- system.colorDead = toColor4(color, 0);
147
- system.addColorGradient(0, toColor4(color, 0));
148
- system.addColorGradient(0.12, toColor4(brightColor, params.opacity));
149
- system.addColorGradient(0.72, toColor4(color, params.opacity * 0.62));
150
- system.addColorGradient(1, toColor4(color, 0));
151
- system.addVelocityGradient(0, 1);
152
- system.addVelocityGradient(0.65, 0.55);
153
- system.addVelocityGradient(1, 0.12);
154
-
155
- let positionIndex = 0;
156
- let directionIndex = 0;
157
- system.startPositionFunction = (worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle, isLocal: boolean) => {
158
- const index = particle.id + positionIndex;
159
- positionIndex += 1;
160
- const local = mode === 'center'
161
- ? sampleCenterPosition(index, params)
162
- : sampleOutlinePosition(index, params);
163
- if (isLocal) positionToUpdate.copyFrom(local);
164
- else Vector3.TransformCoordinatesToRef(local, worldMatrix, positionToUpdate);
165
- };
166
- system.startDirectionFunction = (worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle, isLocal: boolean) => {
167
- const index = particle.id + directionIndex;
168
- directionIndex += 1;
169
- const sway = (mode === 'center' ? 0.22 : 0.12) * getHorizontalScale(params);
170
- const local = new Vector3(
171
- (sequence01(index, 4) - 0.5) * sway,
172
- 0.8 + sequence01(index, 5) * 0.65,
173
- (sequence01(index, 6) - 0.5) * sway,
174
- );
175
- if (isLocal) directionToUpdate.copyFrom(local);
176
- else Vector3.TransformNormalToRef(local, worldMatrix, directionToUpdate);
177
- };
178
-
179
- return system;
180
- }
181
-
182
- function createOutlineGlow(scene: Scene, root: TransformNode, params: GroundTileUpgradeParams): ParticleSystem {
183
- const count = Math.max(1, Math.round(params.outlineCount * 0.82));
184
- const system = new ParticleSystem('ground-tile-upgrade.outline-glow-rays', count, scene);
185
- const height = getOutlineHeight(params) * 1.06;
186
- const glowWidth = Math.max(0.04, BASE_GLOW_THICKNESS * getHorizontalScale(params));
187
- const alpha = params.glowOpacity * params.opacity;
188
- const brightColor = getBrightColor(params.color);
189
-
190
- configureVfxParticleSystem(system);
191
- system.particleTexture = getOutlineGlowTexture(scene);
192
- system.emitter = root as any;
193
- system.manualEmitCount = count;
194
- system.emitRate = count * 60;
195
- system.disposeOnStop = false;
196
- system.updateSpeed = 1 / 60;
197
- system.minLifeTime = Math.max(0.12, params.lifetime * 0.62);
198
- system.maxLifeTime = Math.max(system.minLifeTime + 0.01, params.lifetime * 1.08);
199
- system.minSize = Math.max(0.01, height * 0.42);
200
- system.maxSize = Math.max(system.minSize, height * 1.08);
201
- system.minScaleX = glowWidth * 0.42;
202
- system.maxScaleX = glowWidth * 1.18;
203
- system.minScaleY = 1.05;
204
- system.maxScaleY = 1.75;
205
- system.minEmitPower = Math.max(0.01, params.riseSpeed * getVerticalScale(params) * 0.58);
206
- system.maxEmitPower = Math.max(system.minEmitPower, params.riseSpeed * getVerticalScale(params) * 1.38);
207
- system.gravity = new Vector3(0, 0.3 * getVerticalScale(params), 0);
208
- system.blendMode = ParticleSystem.BLENDMODE_ADD;
209
- system.color1 = toColor4(params.color, alpha * 0.62);
210
- system.color2 = toColor4(brightColor, alpha * 0.86);
211
- system.colorDead = toColor4(params.color, 0);
212
- system.addColorGradient(0, toColor4(params.color, 0));
213
- system.addColorGradient(0.1, toColor4(brightColor, alpha * 0.82));
214
- system.addColorGradient(0.56, toColor4(params.color, alpha * 0.52));
215
- system.addColorGradient(1, toColor4(params.color, 0));
216
- system.addVelocityGradient(0, 1);
217
- system.addVelocityGradient(0.65, 0.52);
218
- system.addVelocityGradient(1, 0.12);
219
-
220
- let positionIndex = 0;
221
- let directionIndex = 0;
222
- system.startPositionFunction = (worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle, isLocal: boolean) => {
223
- const index = particle.id + positionIndex + 31;
224
- positionIndex += 1;
225
- const local = sampleOutlinePosition(index, params);
226
- if (isLocal) positionToUpdate.copyFrom(local);
227
- else Vector3.TransformCoordinatesToRef(local, worldMatrix, positionToUpdate);
228
- };
229
- system.startDirectionFunction = (worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle, isLocal: boolean) => {
230
- const index = particle.id + directionIndex + 31;
231
- directionIndex += 1;
232
- const sway = 0.08 * getHorizontalScale(params);
233
- const local = new Vector3(
234
- (sequence01(index, 4) - 0.5) * sway,
235
- 0.82 + sequence01(index, 5) * 0.58,
236
- (sequence01(index, 6) - 0.5) * sway,
237
- );
238
- if (isLocal) directionToUpdate.copyFrom(local);
239
- else Vector3.TransformNormalToRef(local, worldMatrix, directionToUpdate);
240
- };
241
-
242
- return system;
243
- }
244
-
245
- function sampleCenterPosition(index: number, params: GroundTileUpgradeParams): Vector3 {
246
- const angle = sequence01(index, 0) * Math.PI * 2;
247
- const radius = Math.sqrt(0.16 + sequence01(index, 1) * 0.84);
248
- const xRadius = getFootprintX(params) * 0.5 * params.centerSpread;
249
- const zRadius = getFootprintZ(params) * 0.5 * params.centerSpread;
250
- const jitterX = (sequence01(index, 7) - 0.5) * xRadius * 0.18;
251
- const jitterZ = (sequence01(index, 8) - 0.5) * zRadius * 0.18;
252
- const x = Math.cos(angle) * radius * xRadius + jitterX;
253
- const z = Math.sin(angle) * radius * zRadius + jitterZ;
254
- const y = sequence01(index, 2) * 0.12 * getVerticalScale(params);
255
- return new Vector3(x, y, z);
256
- }
257
-
258
- function sampleOutlinePosition(index: number, params: GroundTileUpgradeParams): Vector3 {
259
- const width = getFootprintX(params);
260
- const depth = getFootprintZ(params);
261
- const perimeter = Math.max(0.001, width * 2 + depth * 2);
262
- const distance = sequence01(index, 0) * perimeter;
263
- const jitter = (sequence01(index, 1) - 0.5) * params.outlineThickness * getHorizontalScale(params);
264
- const y = sequence01(index, 2) * 0.16 * getVerticalScale(params);
265
-
266
- if (distance < width) return new Vector3(-width * 0.5 + distance, y, -depth * 0.5 + jitter);
267
- if (distance < width + depth) return new Vector3(width * 0.5 + jitter, y, -depth * 0.5 + distance - width);
268
- if (distance < width * 2 + depth) return new Vector3(width * 0.5 - (distance - width - depth), y, depth * 0.5 + jitter);
269
- return new Vector3(-width * 0.5 + jitter, y, depth * 0.5 - (distance - width * 2 - depth));
270
- }
271
-
272
- function getFootprintX(params: GroundTileUpgradeParams): number {
273
- return BASE_FOOTPRINT_X * Math.max(0.05, params.scale) * Math.max(0.05, params.scaleX);
274
- }
275
-
276
- function getFootprintZ(params: GroundTileUpgradeParams): number {
277
- return BASE_FOOTPRINT_Z * Math.max(0.05, params.scale) * Math.max(0.05, params.scaleZ);
278
- }
279
-
280
- function getVerticalScale(params: GroundTileUpgradeParams): number {
281
- return Math.max(0.05, params.scale) * Math.max(0.05, params.scaleY);
282
- }
283
-
284
- function getHorizontalScale(params: GroundTileUpgradeParams): number {
285
- return Math.max(0.05, params.scale) * Math.max(0.05, (params.scaleX + params.scaleZ) * 0.5);
286
- }
287
-
288
- function getCenterHeight(params: GroundTileUpgradeParams): number {
289
- return BASE_CENTER_HEIGHT * getVerticalScale(params);
290
- }
291
-
292
- function getOutlineHeight(params: GroundTileUpgradeParams): number {
293
- return BASE_OUTLINE_HEIGHT * getVerticalScale(params);
294
- }
295
-
296
- function getMaxStrandHeight(params: GroundTileUpgradeParams): number {
297
- return Math.max(getCenterHeight(params), getOutlineHeight(params));
298
- }
299
-
300
- function getStrandTexture(scene: Scene): DynamicTexture {
301
- const key = '__vfx_ground_tile_upgrade_strand_texture';
302
- const metadata = scene.metadata && typeof scene.metadata === 'object' ? scene.metadata as Record<string, unknown> : {};
303
- scene.metadata = metadata;
304
- const existing = metadata[key] as DynamicTexture | undefined;
305
- if (existing && !isTextureDisposed(existing)) return existing;
306
-
307
- const texture = new DynamicTexture('ground_tile_upgrade_strand_texture', { width: 48, height: 192 }, scene, true);
308
- const context = texture.getContext();
309
- context.clearRect(0, 0, 48, 192);
310
- const glow = context.createLinearGradient(0, 0, 0, 192);
311
- glow.addColorStop(0, 'rgba(255, 255, 255, 0)');
312
- glow.addColorStop(0.18, 'rgba(255, 255, 255, 0.92)');
313
- glow.addColorStop(0.62, 'rgba(255, 255, 255, 0.52)');
314
- glow.addColorStop(1, 'rgba(255, 255, 255, 0)');
315
- context.fillStyle = glow;
316
- context.fillRect(19, 0, 10, 192);
317
- context.fillStyle = 'rgba(255, 255, 255, 0.95)';
318
- context.fillRect(23, 8, 2, 168);
319
- const halo = context.createRadialGradient(24, 64, 0, 24, 64, 24);
320
- halo.addColorStop(0, 'rgba(255, 255, 255, 0.5)');
321
- halo.addColorStop(1, 'rgba(255, 255, 255, 0)');
322
- context.fillStyle = halo;
323
- context.fillRect(0, 16, 48, 96);
324
- texture.hasAlpha = true;
325
- texture.update(false);
326
- metadata[key] = texture;
327
- texture.onDisposeObservable.addOnce(() => {
328
- if (metadata[key] === texture) delete metadata[key];
329
- });
330
- return texture;
331
- }
332
-
333
- function getOutlineGlowTexture(scene: Scene): DynamicTexture {
334
- const key = '__vfx_ground_tile_upgrade_outline_glow_texture';
335
- const metadata = scene.metadata && typeof scene.metadata === 'object' ? scene.metadata as Record<string, unknown> : {};
336
- scene.metadata = metadata;
337
- const existing = metadata[key] as DynamicTexture | undefined;
338
- if (existing && !isTextureDisposed(existing)) return existing;
339
-
340
- const texture = new DynamicTexture('ground_tile_upgrade_outline_glow_texture', { width: 96, height: 192 }, scene, true);
341
- const context = texture.getContext();
342
- const compositeContext = context as unknown as CanvasRenderingContext2D;
343
- context.clearRect(0, 0, 96, 192);
344
- const sideFade = context.createLinearGradient(0, 0, 96, 0);
345
- sideFade.addColorStop(0, 'rgba(255, 255, 255, 0)');
346
- sideFade.addColorStop(0.28, 'rgba(255, 255, 255, 0.36)');
347
- sideFade.addColorStop(0.5, 'rgba(255, 255, 255, 0.78)');
348
- sideFade.addColorStop(0.72, 'rgba(255, 255, 255, 0.36)');
349
- sideFade.addColorStop(1, 'rgba(255, 255, 255, 0)');
350
- const verticalFade = context.createLinearGradient(0, 0, 0, 192);
351
- verticalFade.addColorStop(0, 'rgba(255, 255, 255, 0)');
352
- verticalFade.addColorStop(0.16, 'rgba(255, 255, 255, 0.65)');
353
- verticalFade.addColorStop(0.55, 'rgba(255, 255, 255, 0.46)');
354
- verticalFade.addColorStop(1, 'rgba(255, 255, 255, 0)');
355
- context.fillStyle = sideFade;
356
- context.fillRect(0, 0, 96, 192);
357
- compositeContext.globalCompositeOperation = 'source-in';
358
- context.fillStyle = verticalFade;
359
- context.fillRect(0, 0, 96, 192);
360
- compositeContext.globalCompositeOperation = 'source-over';
361
- const core = context.createLinearGradient(0, 0, 0, 192);
362
- core.addColorStop(0, 'rgba(255, 255, 255, 0)');
363
- core.addColorStop(0.22, 'rgba(255, 255, 255, 0.64)');
364
- core.addColorStop(0.66, 'rgba(255, 255, 255, 0.28)');
365
- core.addColorStop(1, 'rgba(255, 255, 255, 0)');
366
- context.fillStyle = core;
367
- context.fillRect(44, 8, 8, 166);
368
- texture.hasAlpha = true;
369
- texture.update(false);
370
- metadata[key] = texture;
371
- texture.onDisposeObservable.addOnce(() => {
372
- if (metadata[key] === texture) delete metadata[key];
373
- });
374
- return texture;
375
- }
376
-
377
- function getBrightColor(color: VfxColorValue): VfxColorValue {
378
- return {
379
- r: lerp(color.r, 1, 0.68),
380
- g: lerp(color.g, 1, 0.68),
381
- b: lerp(color.b, 1, 0.68),
382
- };
383
- }
384
-
385
- function toColor4(color: VfxColorValue, alpha: number): Color4 {
386
- return new Color4(clamp01(color.r), clamp01(color.g), clamp01(color.b), clamp01(alpha));
387
- }
388
-
389
- function isTextureDisposed(texture: DynamicTexture): boolean {
390
- const maybeTexture = texture as DynamicTexture & { isDisposed?: () => boolean; _isDisposed?: boolean };
391
- return maybeTexture.isDisposed?.() ?? maybeTexture._isDisposed === true;
392
- }
393
-
394
- function lerp(min: number, max: number, t: number): number {
395
- return min + (max - min) * t;
396
- }
397
-
398
- function clamp01(value: number): number {
399
- return Math.min(1, Math.max(0, value));
400
- }
401
-
402
- function fract(value: number): number {
403
- return value - Math.floor(value);
404
- }
405
-
406
- function sequence01(index: number, axis: number): number {
407
- if (index === 0) return 0.5;
408
- const strides = [0.618033988749895, 0.414213562373095, 0.732050807568877, 0.324717957244746, 0.754877666246693, 0.569840290998053];
409
- return fract(0.5 + index * strides[axis % strides.length] + axis * 0.173205080756888);
410
- }
@@ -1,77 +0,0 @@
1
- // 命中蓝白爆闪(移植自 babylon-laser createHitParticles/burstHit, 特效#3)。
2
- // 一次性 ParticleSystem 爆发:程序光斑贴图,蓝白渐变到透明,BLENDMODE_ADD 全向四散。
3
- import { ParticleSystem } from '@babylonjs/core/Particles/particleSystem';
4
- import { DynamicTexture } from '@babylonjs/core/Materials/Textures/dynamicTexture';
5
- import { Color4 } from '@babylonjs/core/Maths/math.color';
6
- import { Vector3 } from '@babylonjs/core/Maths/math.vector';
7
- import type { Scene } from '@babylonjs/core/scene';
8
- import type { VfxEffectPackage, VfxParamValues } from '../../types';
9
-
10
- interface HitFlashParams extends VfxParamValues {
11
- count: number;
12
- sizeMax: number;
13
- power: number;
14
- }
15
-
16
- const DEFAULT_PARAMS: HitFlashParams = { count: 24, sizeMax: 0.5, power: 7 };
17
-
18
- function makeFlareTexture(scene: Scene, inner = '255,255,255', outer = '90,160,255'): DynamicTexture {
19
- const dt = new DynamicTexture('vfx_hit_flare', 128, scene, false);
20
- const ctx = dt.getContext();
21
- const g = ctx.createRadialGradient(64, 64, 0, 64, 64, 64);
22
- g.addColorStop(0, `rgba(${inner},1)`);
23
- g.addColorStop(0.35, `rgba(${outer},0.55)`);
24
- g.addColorStop(1, `rgba(${outer},0)`);
25
- ctx.clearRect(0, 0, 128, 128);
26
- ctx.fillStyle = g; ctx.fillRect(0, 0, 128, 128);
27
- dt.update(); dt.hasAlpha = true;
28
- return dt;
29
- }
30
-
31
- // 贴图内容恒定:按 scene 缓存共享,免每发命中重建+GPU 上传(M2)。
32
- const flareByScene = new WeakMap<Scene, DynamicTexture>();
33
- function getFlareTexture(scene: Scene): DynamicTexture {
34
- let dt = flareByScene.get(scene);
35
- if (!dt || (dt as { isDisposed?: boolean }).isDisposed) { dt = makeFlareTexture(scene); flareByScene.set(scene, dt); }
36
- return dt;
37
- }
38
-
39
- export const hitFlashEffectPackage: VfxEffectPackage<HitFlashParams> = {
40
- id: 'hit-flash',
41
- nameZh: '命中蓝白爆闪',
42
- placement: 'world',
43
- debugAnchor: 'playerRight',
44
- defaultParams: DEFAULT_PARAMS,
45
- debugParams: [
46
- { key: 'count', label: '粒子数', kind: 'number', min: 1, max: 200, step: 1 },
47
- { key: 'sizeMax', label: '最大尺寸', kind: 'scale', min: 0.1, max: 2, step: 0.01 },
48
- { key: 'power', label: '四散速度', kind: 'number', min: 0.5, max: 20, step: 0.5 },
49
- ],
50
-
51
- create({ scene, root, position, params }) {
52
- root.position.copyFrom(position);
53
- const ps = new ParticleSystem('vfx_hit_ps', 400, scene);
54
- ps.particleTexture = getFlareTexture(scene);
55
- ps.emitter = position.clone();
56
- ps.minEmitBox = new Vector3(-0.1, -0.1, -0.1); ps.maxEmitBox = new Vector3(0.1, 0.1, 0.1);
57
- ps.direction1 = new Vector3(-1, -1, -1); ps.direction2 = new Vector3(1, 1, 1);
58
- ps.color1 = new Color4(0.85, 0.95, 1, 1); ps.color2 = new Color4(0.35, 0.6, 1, 1); ps.colorDead = new Color4(0.1, 0.2, 0.6, 0);
59
- ps.minSize = 0.12; ps.maxSize = params.sizeMax;
60
- ps.minLifeTime = 0.15; ps.maxLifeTime = 0.45;
61
- ps.minEmitPower = params.power * 0.36; ps.maxEmitPower = params.power;
62
- ps.updateSpeed = 0.016;
63
- ps.blendMode = ParticleSystem.BLENDMODE_ADD;
64
- ps.emitRate = 0;
65
- ps.start();
66
- ps.manualEmitCount = Math.round(params.count); // 一次性爆发
67
-
68
- let disposed = false;
69
- const disposeTimer = window.setTimeout(() => disposeAll(), 800);
70
- function disposeAll(): void {
71
- if (disposed) return; disposed = true;
72
- window.clearTimeout(disposeTimer);
73
- ps.dispose(false); root.dispose(); // dispose(false):共享缓存纹理不随实例销毁
74
- }
75
- return { root, dispose() { disposeAll(); } };
76
- },
77
- };
@@ -1,6 +0,0 @@
1
- // 主激光束(特效#1)。共享实现见 ../laser-beam-factory;本包只定 id/中文名/默认参数(主束 width0.55/intensity1.0)。
2
- import { createLaserBeamEffectPackage } from '../laser-beam-factory';
3
-
4
- export const laserBeamEffectPackage = createLaserBeamEffectPackage('laser-beam', '激光束', {
5
- width: 0.55, intensity: 1.0, laserSpeed: 7, targetDistance: 12,
6
- });
@@ -1,146 +0,0 @@
1
- // 激光束共享工厂(移植自 babylon-laser LaserBeam,被 laser-beam(主#1)与 laser-splash-beam(副#2)复用)。
2
- // 非 effect(无 index.ts);两个特效 index.ts 经 `../laser-beam-factory` 引用,差异只在 defaultParams(width/intensity)。
3
- import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
4
- import { Mesh } from '@babylonjs/core/Meshes/mesh';
5
- import { VertexData } from '@babylonjs/core/Meshes/mesh.vertexData';
6
- import { CreatePlane } from '@babylonjs/core/Meshes/Builders/planeBuilder';
7
- import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial';
8
- import { Texture } from '@babylonjs/core/Materials/Textures/texture';
9
- import { Color3 } from '@babylonjs/core/Maths/math.color';
10
- import { Vector3 } from '@babylonjs/core/Maths/math.vector';
11
- import { Space } from '@babylonjs/core/Maths/math.axis';
12
- import { Constants } from '@babylonjs/core/Engines/constants';
13
- import type { Scene } from '@babylonjs/core/scene';
14
- import type { VfxEffectPackage, VfxParamValues } from '../types';
15
- import { makeFlareTexture, LIFETIME_DEBUG_PARAMS, LIFETIME_DEFAULTS, scheduleLifetime } from './space-shared';
16
- import arcTextureUrl from './laser-beam/assets/textures/laser_glow.webp?url';
17
- import noiseTextureUrl from './laser-beam/assets/textures/laser_noise.webp?url';
18
-
19
- export interface LaserBeamParams extends VfxParamValues {
20
- lifetimeMode: string;
21
- lifetime: number;
22
- width: number;
23
- intensity: number;
24
- laserSpeed: number;
25
- targetDistance: number;
26
- }
27
- type LaserCoreDefaults = Omit<LaserBeamParams, 'lifetimeMode' | 'lifetime'>;
28
-
29
- // 十字面片:局部 +Z 长度=1(beamRoot.scaling.z=dist 拉伸);U 沿长度 → uOffset 滚动即流动
30
- function createBeamPlaneGeo(name: string, width: number, axis: 'x' | 'y', scene: Scene): Mesh {
31
- const h = width / 2;
32
- const positions = axis === 'x'
33
- ? [-h, 0, 0, h, 0, 0, h, 0, 1, -h, 0, 1]
34
- : [0, -h, 0, 0, h, 0, 0, h, 1, 0, -h, 1];
35
- const normals = axis === 'x' ? [0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0] : [1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0];
36
- const uvs = [0, 0, 0, 1, 1, 1, 1, 0];
37
- const indices = [0, 1, 2, 0, 2, 3];
38
- const mesh = new Mesh(name, scene);
39
- const vd = new VertexData();
40
- vd.positions = positions; vd.normals = normals; vd.uvs = uvs; vd.indices = indices;
41
- vd.applyToMesh(mesh);
42
- return mesh;
43
- }
44
-
45
- export function createLaserBeamEffectPackage(id: string, nameZh: string, core: LaserCoreDefaults): VfxEffectPackage<LaserBeamParams> {
46
- const defaultParams = { ...LIFETIME_DEFAULTS, ...core } as LaserBeamParams;
47
- return {
48
- // 定向武器 = socket 起点(parent 到炮口)+ aim 终点(optionalInputs)。geometrySpace local(束几何挂 root)。
49
- // 'link' 留给真·多端点特效(本特效只有单 aim 终点,非 link)。见 #9-A。
50
- id, nameZh, defaultParams, debugAnchor: 'playerRight', placement: 'socket', geometrySpace: 'local', optionalInputs: ['aim'],
51
- debugParams: [
52
- ...LIFETIME_DEBUG_PARAMS,
53
- { key: 'width', label: '束宽', kind: 'scale', min: 0.05, max: 2, step: 0.01 },
54
- { key: 'intensity', label: '强度', kind: 'number', min: 0.1, max: 3, step: 0.05 },
55
- { key: 'laserSpeed', label: '纹理流速', kind: 'number', min: 0, max: 20, step: 0.5 },
56
- { key: 'targetDistance', label: '目标距离', kind: 'number', min: 2, max: 40, step: 0.5 },
57
- ],
58
- create({ scene, root, position, rotationY, params, inputs }) {
59
- root.position.copyFrom(position);
60
- root.rotation.y = rotationY;
61
- const { width, intensity } = params;
62
- const segLen = width * 5;
63
-
64
- const arcTex = new Texture(arcTextureUrl, scene); arcTex.wrapU = Texture.WRAP_ADDRESSMODE;
65
- const arcMat = new StandardMaterial('vfx_laser_arcMat', scene);
66
- arcMat.emissiveTexture = arcTex; arcMat.opacityTexture = arcTex;
67
- arcMat.emissiveColor = new Color3(0.45 * intensity, 0.62 * intensity, 1.35 * intensity);
68
- arcMat.disableLighting = true; arcMat.backFaceCulling = false; arcMat.alphaMode = Constants.ALPHA_ADD;
69
-
70
- const noiseTex = new Texture(noiseTextureUrl, scene); noiseTex.wrapU = Texture.WRAP_ADDRESSMODE;
71
- const noiseMat = new StandardMaterial('vfx_laser_noiseMat', scene);
72
- noiseMat.emissiveTexture = noiseTex; noiseMat.opacityTexture = noiseTex;
73
- noiseMat.opacityTexture.getAlphaFromRGB = true;
74
- noiseMat.emissiveColor = new Color3(0.2 * intensity, 0.35 * intensity, 0.9 * intensity);
75
- noiseMat.disableLighting = true; noiseMat.backFaceCulling = false; noiseMat.alphaMode = Constants.ALPHA_ADD;
76
-
77
- const beamRoot = new TransformNode('vfx_laser_beamRoot', scene);
78
- beamRoot.parent = root;
79
- const planes: Mesh[] = [];
80
- const layout: Array<['x' | 'y', StandardMaterial, number]> = [
81
- ['x', arcMat, width], ['y', arcMat, width], ['x', noiseMat, width * 1.9], ['y', noiseMat, width * 1.9],
82
- ];
83
- for (const [axis, mat, w] of layout) {
84
- const p = createBeamPlaneGeo(`vfx_laser_p${planes.length}`, w, axis, scene);
85
- p.material = mat; p.parent = beamRoot; p.isPickable = false;
86
- planes.push(p);
87
- }
88
-
89
- const flareTex = makeFlareTexture(scene, 'vfx_laser_flare');
90
- function makeFlare(name: string, size: number): Mesh {
91
- const f = CreatePlane(name, { size }, scene);
92
- f.billboardMode = Mesh.BILLBOARDMODE_ALL;
93
- const m = new StandardMaterial(name + 'Mat', scene);
94
- m.emissiveTexture = flareTex; m.opacityTexture = flareTex;
95
- m.emissiveColor = new Color3(0.7, 0.85, 1.6);
96
- m.disableLighting = true; m.alphaMode = Constants.ALPHA_ADD;
97
- f.material = m; f.isPickable = false; f.parent = root;
98
- return f;
99
- }
100
- const muzzleFlare = makeFlare('vfx_laser_muzzle', width * 3.2);
101
- const hitFlare = makeFlare('vfx_laser_hit', width * 3.2);
102
-
103
- let time = 0;
104
- const observer = scene.onBeforeRenderObservable.add(() => {
105
- const dt = Math.min(scene.getEngine().getDeltaTime() / 1000, 0.05);
106
- time += dt;
107
- // 有 inputs.aim:朝目标(束长=到目标距离);无 aim:回退正前方 targetDistance(预览)。
108
- let dist = params.targetDistance;
109
- if (inputs?.aim) {
110
- const tgt = inputs.aim();
111
- dist = Vector3.Distance(root.getAbsolutePosition(), tgt);
112
- // Space.WORLD:root 挂在挂点上(有父节点),lookAt 默认按 LOCAL 解释目标点,必须显式 WORLD。
113
- root.lookAt(tgt, 0, 0, 0, Space.WORLD);
114
- }
115
- beamRoot.scaling.z = dist;
116
- const tiles = Math.max(1, dist / segLen);
117
- (arcMat.emissiveTexture as Texture).uScale = tiles; (arcMat.opacityTexture as Texture).uScale = tiles;
118
- (arcMat.emissiveTexture as Texture).uOffset -= params.laserSpeed * dt;
119
- (arcMat.opacityTexture as Texture).uOffset = (arcMat.emissiveTexture as Texture).uOffset;
120
- (noiseMat.emissiveTexture as Texture).uScale = tiles * 0.6;
121
- (noiseMat.emissiveTexture as Texture).uOffset -= params.laserSpeed * 0.31 * dt;
122
- (noiseMat.opacityTexture as Texture).uScale = tiles * 0.6;
123
- (noiseMat.opacityTexture as Texture).uOffset = (noiseMat.emissiveTexture as Texture).uOffset;
124
- const pulse = 1 + Math.sin(time * 24) * 0.18;
125
- muzzleFlare.position.set(0, 0, 0); muzzleFlare.scaling.setAll(pulse);
126
- hitFlare.position.set(0, 0, dist); hitFlare.scaling.setAll(pulse * 1.4);
127
- });
128
-
129
- let disposed = false;
130
- let ltTimer = 0;
131
- const dispose = (): void => {
132
- if (disposed) return; disposed = true;
133
- if (ltTimer) window.clearTimeout(ltTimer);
134
- scene.onBeforeRenderObservable.remove(observer);
135
- for (const p of planes) p.dispose();
136
- muzzleFlare.material?.dispose(); muzzleFlare.dispose();
137
- hitFlare.material?.dispose(); hitFlare.dispose();
138
- beamRoot.dispose();
139
- arcMat.dispose(); arcTex.dispose(); noiseMat.dispose(); noiseTex.dispose(); flareTex.dispose();
140
- root.dispose();
141
- };
142
- ltTimer = scheduleLifetime(params, dispose); // 自定义时间模式:到时自动停;无限=循环
143
- return { root, dispose };
144
- },
145
- };
146
- }
@@ -1,6 +0,0 @@
1
- {
2
- "id": "lumber-cart-suction",
3
- "nameZh": "收集车吸入圆环",
4
- "assets": [],
5
- "source": "procedural"
6
- }