@aura3d/engine 4.0.0 → 4.0.3

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 (272) hide show
  1. package/README.md +286 -382
  2. package/dist/animation/AnimationController.d.ts +8 -0
  3. package/dist/animation/AnimationController.d.ts.map +1 -1
  4. package/dist/animation/AnimationController.js.map +1 -1
  5. package/dist/aura3d-cli/asset-core-types.d.ts +1 -0
  6. package/dist/aura3d-cli/asset-core-types.d.ts.map +1 -1
  7. package/dist/aura3d-cli/asset-inspection-types.d.ts +1 -0
  8. package/dist/aura3d-cli/asset-inspection-types.d.ts.map +1 -1
  9. package/dist/aura3d-cli/asset-manifest.d.ts.map +1 -1
  10. package/dist/aura3d-cli/asset-manifest.js +4 -1
  11. package/dist/aura3d-cli/asset-manifest.js.map +1 -1
  12. package/dist/aura3d-cli/index.d.ts.map +1 -1
  13. package/dist/aura3d-cli/index.js +27 -3
  14. package/dist/aura3d-cli/index.js.map +1 -1
  15. package/dist/aura3d-cli/meshy/admission.d.ts.map +1 -1
  16. package/dist/aura3d-cli/meshy/admission.js +32 -7
  17. package/dist/aura3d-cli/meshy/admission.js.map +1 -1
  18. package/dist/aura3d-cli/meshy/import.d.ts.map +1 -1
  19. package/dist/aura3d-cli/meshy/import.js +4 -0
  20. package/dist/aura3d-cli/meshy/import.js.map +1 -1
  21. package/dist/create-aura3d/index.js +1 -1
  22. package/dist/engine/agent-api/GameGenreKits.d.ts +16 -0
  23. package/dist/engine/agent-api/GameGenreKits.d.ts.map +1 -1
  24. package/dist/engine/agent-api/GameGenreKits.js +33 -4
  25. package/dist/engine/agent-api/GameGenreKits.js.map +1 -1
  26. package/dist/engine/agent-api/GameRuntime.d.ts.map +1 -1
  27. package/dist/engine/agent-api/GameRuntime.js +29 -6
  28. package/dist/engine/agent-api/GameRuntime.js.map +1 -1
  29. package/dist/engine/agent-api/TouchControlBinding.d.ts.map +1 -1
  30. package/dist/engine/agent-api/TouchControlBinding.js +14 -2
  31. package/dist/engine/agent-api/TouchControlBinding.js.map +1 -1
  32. package/dist/engine/agent-api/app/actorAnimationHandle.d.ts +44 -0
  33. package/dist/engine/agent-api/app/actorAnimationHandle.d.ts.map +1 -1
  34. package/dist/engine/agent-api/app/actorAnimationHandle.js +98 -0
  35. package/dist/engine/agent-api/app/actorAnimationHandle.js.map +1 -1
  36. package/dist/engine/agent-api/app/createAuraApp.d.ts.map +1 -1
  37. package/dist/engine/agent-api/app/createAuraApp.js +1 -1
  38. package/dist/engine/agent-api/app/createAuraApp.js.map +1 -1
  39. package/dist/engine/agent-api/app/frameLoop.d.ts +3 -1
  40. package/dist/engine/agent-api/app/frameLoop.d.ts.map +1 -1
  41. package/dist/engine/agent-api/app/frameLoop.js +19 -1
  42. package/dist/engine/agent-api/app/frameLoop.js.map +1 -1
  43. package/dist/engine/agent-api/app/runtimeNodes.d.ts.map +1 -1
  44. package/dist/engine/agent-api/app/runtimeNodes.js +1 -0
  45. package/dist/engine/agent-api/app/runtimeNodes.js.map +1 -1
  46. package/dist/engine/agent-api/compiler/animation.d.ts.map +1 -1
  47. package/dist/engine/agent-api/compiler/animation.js +8 -1
  48. package/dist/engine/agent-api/compiler/animation.js.map +1 -1
  49. package/dist/engine/agent-api/compiler/observations.d.ts.map +1 -1
  50. package/dist/engine/agent-api/compiler/observations.js +3 -1
  51. package/dist/engine/agent-api/compiler/observations.js.map +1 -1
  52. package/dist/engine/agent-api/compiler/primitives.d.ts.map +1 -1
  53. package/dist/engine/agent-api/compiler/primitives.js +10 -2
  54. package/dist/engine/agent-api/compiler/primitives.js.map +1 -1
  55. package/dist/engine/agent-api/compiler/renderInput.d.ts.map +1 -1
  56. package/dist/engine/agent-api/compiler/renderInput.js +35 -7
  57. package/dist/engine/agent-api/compiler/renderInput.js.map +1 -1
  58. package/dist/engine/agent-api/compiler/renderer.d.ts.map +1 -1
  59. package/dist/engine/agent-api/compiler/renderer.js +8 -4
  60. package/dist/engine/agent-api/compiler/renderer.js.map +1 -1
  61. package/dist/engine/agent-api/diagnostics.d.ts +5 -0
  62. package/dist/engine/agent-api/diagnostics.d.ts.map +1 -1
  63. package/dist/engine/agent-api/diagnostics.js +18 -5
  64. package/dist/engine/agent-api/diagnostics.js.map +1 -1
  65. package/dist/engine/agent-api/game-kits/arcadeKart.d.ts +118 -0
  66. package/dist/engine/agent-api/game-kits/arcadeKart.d.ts.map +1 -0
  67. package/dist/engine/agent-api/game-kits/arcadeKart.js +468 -0
  68. package/dist/engine/agent-api/game-kits/arcadeKart.js.map +1 -0
  69. package/dist/engine/agent-api/game-kits/carSoccer.d.ts +95 -0
  70. package/dist/engine/agent-api/game-kits/carSoccer.d.ts.map +1 -0
  71. package/dist/engine/agent-api/game-kits/carSoccer.js +717 -0
  72. package/dist/engine/agent-api/game-kits/carSoccer.js.map +1 -0
  73. package/dist/engine/agent-api/game-kits/index.d.ts +20 -0
  74. package/dist/engine/agent-api/game-kits/index.d.ts.map +1 -1
  75. package/dist/engine/agent-api/game-kits/index.js +10 -1
  76. package/dist/engine/agent-api/game-kits/index.js.map +1 -1
  77. package/dist/engine/agent-api/game-kits/racketSports.d.ts +64 -0
  78. package/dist/engine/agent-api/game-kits/racketSports.d.ts.map +1 -0
  79. package/dist/engine/agent-api/game-kits/racketSports.js +146 -0
  80. package/dist/engine/agent-api/game-kits/racketSports.js.map +1 -0
  81. package/dist/engine/agent-api/index.d.ts +4 -1
  82. package/dist/engine/agent-api/index.d.ts.map +1 -1
  83. package/dist/engine/agent-api/index.js +3 -0
  84. package/dist/engine/agent-api/index.js.map +1 -1
  85. package/dist/engine/agent-api/looks/generatedCodeWarnings.d.ts.map +1 -1
  86. package/dist/engine/agent-api/looks/generatedCodeWarnings.js +16 -2
  87. package/dist/engine/agent-api/looks/generatedCodeWarnings.js.map +1 -1
  88. package/dist/engine/agent-api/nodes/assets.d.ts.map +1 -1
  89. package/dist/engine/agent-api/nodes/assets.js +7 -0
  90. package/dist/engine/agent-api/nodes/assets.js.map +1 -1
  91. package/dist/engine/agent-api/nodes/game/index.d.ts +8 -0
  92. package/dist/engine/agent-api/nodes/game/index.d.ts.map +1 -1
  93. package/dist/engine/agent-api/nodes/game/index.js +8 -0
  94. package/dist/engine/agent-api/nodes/game/index.js.map +1 -1
  95. package/dist/engine/agent-api/nodes/model.d.ts.map +1 -1
  96. package/dist/engine/agent-api/nodes/model.js +2 -0
  97. package/dist/engine/agent-api/nodes/model.js.map +1 -1
  98. package/dist/engine/agent-api/nodes/shadows.d.ts.map +1 -1
  99. package/dist/engine/agent-api/nodes/shadows.js +14 -10
  100. package/dist/engine/agent-api/nodes/shadows.js.map +1 -1
  101. package/dist/engine/agent-api/nodes/types.d.ts +14 -6
  102. package/dist/engine/agent-api/nodes/types.d.ts.map +1 -1
  103. package/dist/engine/agent-api/publishedUnion.d.ts +1 -1
  104. package/dist/engine/agent-api/publishedUnion.d.ts.map +1 -1
  105. package/dist/engine/agent-api/runtimeEvidence.d.ts.map +1 -1
  106. package/dist/engine/agent-api/runtimeEvidence.js +2 -1
  107. package/dist/engine/agent-api/runtimeEvidence.js.map +1 -1
  108. package/dist/engine/agent-api/sceneMath.d.ts.map +1 -1
  109. package/dist/engine/agent-api/sceneMath.js +20 -1
  110. package/dist/engine/agent-api/sceneMath.js.map +1 -1
  111. package/dist/engine/contracts/animation.d.ts +18 -0
  112. package/dist/engine/contracts/animation.d.ts.map +1 -1
  113. package/dist/engine/contracts/animation.js +4 -1
  114. package/dist/engine/contracts/animation.js.map +1 -1
  115. package/dist/engine/lanes/prd06.d.ts.map +1 -1
  116. package/dist/engine/lanes/prd06.js +21 -2
  117. package/dist/engine/lanes/prd06.js.map +1 -1
  118. package/dist/engine/production-runtime/effects/EffectNodeLowering.js +1 -1
  119. package/dist/engine/production-runtime/effects/EffectNodeLowering.js.map +1 -1
  120. package/dist/engine/public/index.d.ts +3 -1
  121. package/dist/engine/public/index.d.ts.map +1 -1
  122. package/dist/engine/public/index.js +1 -0
  123. package/dist/engine/public/index.js.map +1 -1
  124. package/dist/engine/threejs-example-parity/index.d.ts.map +1 -1
  125. package/dist/engine/threejs-example-parity/index.js +52 -22
  126. package/dist/engine/threejs-example-parity/index.js.map +1 -1
  127. package/dist/rendering/Renderer.d.ts.map +1 -1
  128. package/dist/rendering/Renderer.js +15 -4
  129. package/dist/rendering/Renderer.js.map +1 -1
  130. package/dist/rendering/WebGL2Device.d.ts +1 -0
  131. package/dist/rendering/WebGL2Device.d.ts.map +1 -1
  132. package/dist/rendering/WebGL2Device.js +12 -0
  133. package/dist/rendering/WebGL2Device.js.map +1 -1
  134. package/dist/rendering/effects/ResidentGPUParticleRenderer.d.ts.map +1 -1
  135. package/dist/rendering/effects/ResidentGPUParticleRenderer.js +10 -5
  136. package/dist/rendering/effects/ResidentGPUParticleRenderer.js.map +1 -1
  137. package/dist/rendering/post/PostResources.d.ts.map +1 -1
  138. package/dist/rendering/post/PostResources.js +17 -12
  139. package/dist/rendering/post/PostResources.js.map +1 -1
  140. package/dist/rendering/post/v2Stages.js +2 -2
  141. package/dist/rendering/post/v2Stages.js.map +1 -1
  142. package/dist/rendering/production-runtime/passes/ContactShadowPass.d.ts.map +1 -1
  143. package/dist/rendering/production-runtime/passes/ContactShadowPass.js +14 -13
  144. package/dist/rendering/production-runtime/passes/ContactShadowPass.js.map +1 -1
  145. package/dist/rendering/reference/PostProcessPass.d.ts.map +1 -1
  146. package/dist/rendering/reference/PostProcessPass.js +4 -1
  147. package/dist/rendering/reference/PostProcessPass.js.map +1 -1
  148. package/dist/rendering/renderer/PostprocessExecution.d.ts.map +1 -1
  149. package/dist/rendering/renderer/PostprocessExecution.js +4 -0
  150. package/dist/rendering/renderer/PostprocessExecution.js.map +1 -1
  151. package/dist/rendering/resources/RenderTargetPool.d.ts.map +1 -1
  152. package/dist/rendering/resources/RenderTargetPool.js +13 -4
  153. package/dist/rendering/resources/RenderTargetPool.js.map +1 -1
  154. package/dist/rendering/webgl2/LegacyPost.d.ts.map +1 -1
  155. package/dist/rendering/webgl2/LegacyPost.js +5 -2
  156. package/dist/rendering/webgl2/LegacyPost.js.map +1 -1
  157. package/dist/rendering/webgl2/Probe.d.ts.map +1 -1
  158. package/dist/rendering/webgl2/Probe.js +27 -1
  159. package/dist/rendering/webgl2/Probe.js.map +1 -1
  160. package/package.json +30 -28
  161. package/templates/cinematic-scene/index.html +28 -2
  162. package/templates/cinematic-scene/package.json +1 -1
  163. package/templates/cinematic-scene/public/fonts/graphik/Graphik-Medium-Web.woff2 +0 -0
  164. package/templates/cinematic-scene/public/fonts/graphik/Graphik-Regular-Web.woff2 +0 -0
  165. package/templates/cinematic-scene/public/fonts/graphik/Graphik-RegularItalic-Web.woff2 +0 -0
  166. package/templates/mini-game/index.html +27 -1
  167. package/templates/mini-game/package.json +1 -1
  168. package/templates/mini-game/public/fonts/graphik/Graphik-Medium-Web.woff2 +0 -0
  169. package/templates/mini-game/public/fonts/graphik/Graphik-Regular-Web.woff2 +0 -0
  170. package/templates/mini-game/public/fonts/graphik/Graphik-RegularItalic-Web.woff2 +0 -0
  171. package/templates/mini-game/src/main.ts +1 -1
  172. package/templates/product-viewer/index.html +27 -2
  173. package/templates/product-viewer/package.json +1 -1
  174. package/templates/product-viewer/public/fonts/graphik/Graphik-Medium-Web.woff2 +0 -0
  175. package/templates/product-viewer/public/fonts/graphik/Graphik-Regular-Web.woff2 +0 -0
  176. package/templates/product-viewer/public/fonts/graphik/Graphik-RegularItalic-Web.woff2 +0 -0
  177. package/templates/production-asset-inspector/index.html +1 -1
  178. package/templates/production-asset-inspector/package.json +1 -1
  179. package/templates/production-asset-inspector/public/fonts/graphik/Graphik-Medium-Web.woff2 +0 -0
  180. package/templates/production-asset-inspector/public/fonts/graphik/Graphik-Regular-Web.woff2 +0 -0
  181. package/templates/production-asset-inspector/public/fonts/graphik/Graphik-RegularItalic-Web.woff2 +0 -0
  182. package/templates/production-material-studio/index.html +1 -1
  183. package/templates/production-material-studio/package.json +1 -1
  184. package/templates/production-material-studio/public/fonts/graphik/Graphik-Medium-Web.woff2 +0 -0
  185. package/templates/production-material-studio/public/fonts/graphik/Graphik-Regular-Web.woff2 +0 -0
  186. package/templates/production-material-studio/public/fonts/graphik/Graphik-RegularItalic-Web.woff2 +0 -0
  187. package/templates/production-product-configurator/index.html +1 -1
  188. package/templates/production-product-configurator/package.json +1 -1
  189. package/templates/production-product-configurator/public/fonts/graphik/Graphik-Medium-Web.woff2 +0 -0
  190. package/templates/production-product-configurator/public/fonts/graphik/Graphik-Regular-Web.woff2 +0 -0
  191. package/templates/production-product-configurator/public/fonts/graphik/Graphik-RegularItalic-Web.woff2 +0 -0
  192. package/templates/production-product-viewer/index.html +6 -1
  193. package/templates/production-product-viewer/package.json +1 -1
  194. package/templates/production-product-viewer/public/fonts/graphik/Graphik-Medium-Web.woff2 +0 -0
  195. package/templates/production-product-viewer/public/fonts/graphik/Graphik-Regular-Web.woff2 +0 -0
  196. package/templates/production-product-viewer/public/fonts/graphik/Graphik-RegularItalic-Web.woff2 +0 -0
  197. package/dist/animation/CrowdAnimation.d.ts +0 -13
  198. package/dist/animation/CrowdAnimation.d.ts.map +0 -1
  199. package/dist/animation/CrowdAnimation.js +0 -14
  200. package/dist/animation/CrowdAnimation.js.map +0 -1
  201. package/dist/engine/agent-api/lean-game.d.ts +0 -3
  202. package/dist/engine/agent-api/lean-game.d.ts.map +0 -1
  203. package/dist/engine/agent-api/lean-game.js +0 -3
  204. package/dist/engine/agent-api/lean-game.js.map +0 -1
  205. package/dist/engine/agent-api/lean-product.d.ts +0 -3
  206. package/dist/engine/agent-api/lean-product.d.ts.map +0 -1
  207. package/dist/engine/agent-api/lean-product.js +0 -3
  208. package/dist/engine/agent-api/lean-product.js.map +0 -1
  209. package/dist/engine/agent-api/lean.d.ts +0 -3
  210. package/dist/engine/agent-api/lean.d.ts.map +0 -1
  211. package/dist/engine/agent-api/lean.js +0 -3
  212. package/dist/engine/agent-api/lean.js.map +0 -1
  213. package/dist/engine/threejs-example-parity/FlagshipFoundation.d.ts +0 -158
  214. package/dist/engine/threejs-example-parity/FlagshipFoundation.d.ts.map +0 -1
  215. package/dist/engine/threejs-example-parity/FlagshipFoundation.js +0 -332
  216. package/dist/engine/threejs-example-parity/FlagshipFoundation.js.map +0 -1
  217. package/dist/rendering/ArchitecturalMaterialCatalog.d.ts +0 -30
  218. package/dist/rendering/ArchitecturalMaterialCatalog.d.ts.map +0 -1
  219. package/dist/rendering/ArchitecturalMaterialCatalog.js +0 -90
  220. package/dist/rendering/ArchitecturalMaterialCatalog.js.map +0 -1
  221. package/dist/rendering/LeanWebGL2Device.d.ts +0 -265
  222. package/dist/rendering/LeanWebGL2Device.d.ts.map +0 -1
  223. package/dist/rendering/LeanWebGL2Device.js +0 -4001
  224. package/dist/rendering/LeanWebGL2Device.js.map +0 -1
  225. package/dist/rendering/advanced-runtime/AdvancedRenderer.d.ts +0 -23
  226. package/dist/rendering/advanced-runtime/AdvancedRenderer.d.ts.map +0 -1
  227. package/dist/rendering/advanced-runtime/AdvancedRenderer.js +0 -45
  228. package/dist/rendering/advanced-runtime/AdvancedRenderer.js.map +0 -1
  229. package/dist/rendering/animation/AnimationMaterialStyle.d.ts +0 -19
  230. package/dist/rendering/animation/AnimationMaterialStyle.d.ts.map +0 -1
  231. package/dist/rendering/animation/AnimationMaterialStyle.js +0 -13
  232. package/dist/rendering/animation/AnimationMaterialStyle.js.map +0 -1
  233. package/dist/rendering/cinematic/CinematicMaterialPresets.d.ts +0 -16
  234. package/dist/rendering/cinematic/CinematicMaterialPresets.d.ts.map +0 -1
  235. package/dist/rendering/cinematic/CinematicMaterialPresets.js +0 -114
  236. package/dist/rendering/cinematic/CinematicMaterialPresets.js.map +0 -1
  237. package/dist/rendering/lean/LeanProductRenderer.d.ts +0 -29
  238. package/dist/rendering/lean/LeanProductRenderer.d.ts.map +0 -1
  239. package/dist/rendering/lean/LeanProductRenderer.js +0 -38
  240. package/dist/rendering/lean/LeanProductRenderer.js.map +0 -1
  241. package/dist/rendering/lean/LeanProductionRenderer.d.ts +0 -38
  242. package/dist/rendering/lean/LeanProductionRenderer.d.ts.map +0 -1
  243. package/dist/rendering/lean/LeanProductionRenderer.js +0 -88
  244. package/dist/rendering/lean/LeanProductionRenderer.js.map +0 -1
  245. package/dist/rendering/lean-core-runtime.d.ts +0 -13
  246. package/dist/rendering/lean-core-runtime.d.ts.map +0 -1
  247. package/dist/rendering/lean-core-runtime.js +0 -10
  248. package/dist/rendering/lean-core-runtime.js.map +0 -1
  249. package/dist/rendering/lean-runtime.d.ts +0 -18
  250. package/dist/rendering/lean-runtime.d.ts.map +0 -1
  251. package/dist/rendering/lean-runtime.js +0 -13
  252. package/dist/rendering/lean-runtime.js.map +0 -1
  253. package/dist/rendering/materials/TransmissionPass.d.ts +0 -16
  254. package/dist/rendering/materials/TransmissionPass.d.ts.map +0 -1
  255. package/dist/rendering/materials/TransmissionPass.js +0 -30
  256. package/dist/rendering/materials/TransmissionPass.js.map +0 -1
  257. package/dist/rendering/production-runtime/ProductionEffectsPipeline.d.ts +0 -20
  258. package/dist/rendering/production-runtime/ProductionEffectsPipeline.d.ts.map +0 -1
  259. package/dist/rendering/production-runtime/ProductionEffectsPipeline.js +0 -65
  260. package/dist/rendering/production-runtime/ProductionEffectsPipeline.js.map +0 -1
  261. package/dist/rendering/production-runtime/ProductionRuntimeRenderer.d.ts +0 -44
  262. package/dist/rendering/production-runtime/ProductionRuntimeRenderer.d.ts.map +0 -1
  263. package/dist/rendering/production-runtime/ProductionRuntimeRenderer.js +0 -179
  264. package/dist/rendering/production-runtime/ProductionRuntimeRenderer.js.map +0 -1
  265. package/dist/rendering/production-runtime/ProductionWebGL2Renderer.d.ts +0 -65
  266. package/dist/rendering/production-runtime/ProductionWebGL2Renderer.d.ts.map +0 -1
  267. package/dist/rendering/production-runtime/ProductionWebGL2Renderer.js +0 -305
  268. package/dist/rendering/production-runtime/ProductionWebGL2Renderer.js.map +0 -1
  269. package/dist/rendering/threejs-example-parity/index.d.ts +0 -57
  270. package/dist/rendering/threejs-example-parity/index.d.ts.map +0 -1
  271. package/dist/rendering/threejs-example-parity/index.js +0 -139
  272. package/dist/rendering/threejs-example-parity/index.js.map +0 -1
@@ -0,0 +1,717 @@
1
+ import { material } from "../nodes/material.js";
2
+ import { primitives } from "../nodes/primitives.js";
3
+ function clamp(value, min, max) {
4
+ return Math.max(min, Math.min(max, value));
5
+ }
6
+ function wrapAngle(angle) {
7
+ return Math.atan2(Math.sin(angle), Math.cos(angle));
8
+ }
9
+ export function buildCarSoccerPitchNodes(options = {}) {
10
+ const pitchHalfX = options.pitchHalfX ?? 18.5;
11
+ const pitchHalfZ = options.pitchHalfZ ?? 27.0;
12
+ const goalHalfWidth = options.goalHalfWidth ?? 5.6;
13
+ const goalHeight = options.goalHeight ?? 3.9;
14
+ const goalDepth = options.goalDepth ?? 3.6;
15
+ const turfDarkMat = material.pbr({
16
+ color: "#14532d",
17
+ roughness: 0.86,
18
+ metallic: 0.04
19
+ });
20
+ const turfLightMat = material.pbr({
21
+ color: "#166534",
22
+ roughness: 0.84,
23
+ metallic: 0.04
24
+ });
25
+ const lineWhiteMat = material.emissive({
26
+ color: "#f8fafc",
27
+ emissive: "#e2e8f0",
28
+ emissiveIntensity: 0.45,
29
+ roughness: 0.35
30
+ });
31
+ const dasherWallMat = material.pbr({
32
+ color: "#0f172a",
33
+ roughness: 0.42,
34
+ metallic: 0.55
35
+ });
36
+ const blueGoalFrameMat = material.emissive({
37
+ color: "#38bdf8",
38
+ emissive: "#0ea5e9",
39
+ emissiveIntensity: 0.85,
40
+ roughness: 0.25,
41
+ metallic: 0.6
42
+ });
43
+ const blueGoalNetMat = material.pbr({
44
+ color: "#0284c7",
45
+ roughness: 0.65,
46
+ metallic: 0.15,
47
+ opacity: 0.42
48
+ });
49
+ const orangeGoalFrameMat = material.emissive({
50
+ color: "#f97316",
51
+ emissive: "#ea580c",
52
+ emissiveIntensity: 0.85,
53
+ roughness: 0.25,
54
+ metallic: 0.6
55
+ });
56
+ const orangeGoalNetMat = material.pbr({
57
+ color: "#ea580c",
58
+ roughness: 0.65,
59
+ metallic: 0.15,
60
+ opacity: 0.42
61
+ });
62
+ const nodes = [
63
+ primitives
64
+ .box({
65
+ name: "stadium-pitch-apron",
66
+ size: [pitchHalfX * 2 + 18, 0.2, pitchHalfZ * 2 + 22],
67
+ material: dasherWallMat,
68
+ receiveShadow: true
69
+ })
70
+ .position(0, -0.14, 0)
71
+ ];
72
+ const stripeCount = 12;
73
+ const stripeDepth = (pitchHalfZ * 2) / stripeCount;
74
+ for (let i = 0; i < stripeCount; i += 1) {
75
+ const zCenter = -pitchHalfZ + stripeDepth * (i + 0.5);
76
+ nodes.push(primitives
77
+ .box({
78
+ name: `pitch-turf-stripe-${i}`,
79
+ size: [pitchHalfX * 2, 0.08, stripeDepth + 0.02],
80
+ material: i % 2 === 0 ? turfDarkMat : turfLightMat,
81
+ receiveShadow: true
82
+ })
83
+ .position(0, -0.04, zCenter));
84
+ }
85
+ const lineThickness = 0.22;
86
+ const lineY = 0.008;
87
+ const sideSpanAfterGoal = (pitchHalfX - goalHalfWidth) * 0.5 + goalHalfWidth;
88
+ const sideWidthAfterGoal = pitchHalfX - goalHalfWidth;
89
+ nodes.push(primitives
90
+ .box({ name: "pitch-line-west", size: [lineThickness, 0.015, pitchHalfZ * 2], material: lineWhiteMat })
91
+ .position(-pitchHalfX, lineY, 0), primitives
92
+ .box({ name: "pitch-line-east", size: [lineThickness, 0.015, pitchHalfZ * 2], material: lineWhiteMat })
93
+ .position(pitchHalfX, lineY, 0), primitives
94
+ .box({ name: "pitch-line-center", size: [pitchHalfX * 2, 0.015, lineThickness], material: lineWhiteMat })
95
+ .position(0, lineY, 0), primitives
96
+ .torus({
97
+ name: "pitch-center-circle",
98
+ size: [9.6, 0.22, 9.6],
99
+ material: lineWhiteMat
100
+ })
101
+ .position(0, lineY + 0.01, 0)
102
+ .rotate(Math.PI / 2, 0, 0), primitives
103
+ .box({ name: "pitch-line-north-west", size: [sideWidthAfterGoal, 0.015, lineThickness], material: lineWhiteMat })
104
+ .position(-sideSpanAfterGoal, lineY, -pitchHalfZ), primitives
105
+ .box({ name: "pitch-line-north-east", size: [sideWidthAfterGoal, 0.015, lineThickness], material: lineWhiteMat })
106
+ .position(sideSpanAfterGoal, lineY, -pitchHalfZ), primitives
107
+ .box({ name: "pitch-line-south-west", size: [sideWidthAfterGoal, 0.015, lineThickness], material: lineWhiteMat })
108
+ .position(-sideSpanAfterGoal, lineY, pitchHalfZ), primitives
109
+ .box({ name: "pitch-line-south-east", size: [sideWidthAfterGoal, 0.015, lineThickness], material: lineWhiteMat })
110
+ .position(sideSpanAfterGoal, lineY, pitchHalfZ), primitives
111
+ .box({ name: "pitch-box-north-front", size: [goalHalfWidth * 2 + 5.6, 0.015, lineThickness], material: lineWhiteMat })
112
+ .position(0, lineY, -pitchHalfZ + 6.8), primitives
113
+ .box({ name: "pitch-box-north-left", size: [lineThickness, 0.015, 6.8], material: lineWhiteMat })
114
+ .position(-(goalHalfWidth + 2.8), lineY, -pitchHalfZ + 3.4), primitives
115
+ .box({ name: "pitch-box-north-right", size: [lineThickness, 0.015, 6.8], material: lineWhiteMat })
116
+ .position(goalHalfWidth + 2.8, lineY, -pitchHalfZ + 3.4), primitives
117
+ .box({ name: "pitch-box-south-front", size: [goalHalfWidth * 2 + 5.6, 0.015, lineThickness], material: lineWhiteMat })
118
+ .position(0, lineY, pitchHalfZ - 6.8), primitives
119
+ .box({ name: "pitch-box-south-left", size: [lineThickness, 0.015, 6.8], material: lineWhiteMat })
120
+ .position(-(goalHalfWidth + 2.8), lineY, pitchHalfZ - 3.4), primitives
121
+ .box({ name: "pitch-box-south-right", size: [lineThickness, 0.015, 6.8], material: lineWhiteMat })
122
+ .position(goalHalfWidth + 2.8, lineY, pitchHalfZ - 3.4));
123
+ const wallHeight = 1.05;
124
+ const wallY = wallHeight * 0.5;
125
+ nodes.push(primitives
126
+ .box({ name: "arena-wall-west", size: [0.45, wallHeight, pitchHalfZ * 2 + 0.8], material: dasherWallMat })
127
+ .position(-(pitchHalfX + 0.25), wallY, 0), primitives
128
+ .box({ name: "arena-wall-east", size: [0.45, wallHeight, pitchHalfZ * 2 + 0.8], material: dasherWallMat })
129
+ .position(pitchHalfX + 0.25, wallY, 0), primitives
130
+ .box({ name: "arena-wall-nw", size: [sideWidthAfterGoal, wallHeight, 0.45], material: dasherWallMat })
131
+ .position(-sideSpanAfterGoal, wallY, -(pitchHalfZ + 0.25)), primitives
132
+ .box({ name: "arena-wall-ne", size: [sideWidthAfterGoal, wallHeight, 0.45], material: dasherWallMat })
133
+ .position(sideSpanAfterGoal, wallY, -(pitchHalfZ + 0.25)), primitives
134
+ .box({ name: "arena-wall-sw", size: [sideWidthAfterGoal, wallHeight, 0.45], material: dasherWallMat })
135
+ .position(-sideSpanAfterGoal, wallY, pitchHalfZ + 0.25), primitives
136
+ .box({ name: "arena-wall-se", size: [sideWidthAfterGoal, wallHeight, 0.45], material: dasherWallMat })
137
+ .position(sideSpanAfterGoal, wallY, pitchHalfZ + 0.25));
138
+ const postThickness = 0.34;
139
+ const goalWidth = goalHalfWidth * 2;
140
+ nodes.push(primitives
141
+ .box({ name: "blue-goal-post-left", size: [postThickness, goalHeight, postThickness], material: blueGoalFrameMat })
142
+ .position(-goalHalfWidth, goalHeight * 0.5, -pitchHalfZ), primitives
143
+ .box({ name: "blue-goal-post-right", size: [postThickness, goalHeight, postThickness], material: blueGoalFrameMat })
144
+ .position(goalHalfWidth, goalHeight * 0.5, -pitchHalfZ), primitives
145
+ .box({ name: "blue-goal-crossbar", size: [goalWidth + postThickness, postThickness, postThickness], material: blueGoalFrameMat })
146
+ .position(0, goalHeight, -pitchHalfZ), primitives
147
+ .box({ name: "blue-goal-back-top", size: [goalWidth + postThickness, 0.24, 0.24], material: blueGoalFrameMat })
148
+ .position(0, goalHeight, -(pitchHalfZ + goalDepth)), primitives
149
+ .box({ name: "blue-goal-net-back", size: [goalWidth, goalHeight, 0.12], material: blueGoalNetMat })
150
+ .position(0, goalHeight * 0.5, -(pitchHalfZ + goalDepth)), primitives
151
+ .box({ name: "blue-goal-net-left", size: [0.12, goalHeight, goalDepth], material: blueGoalNetMat })
152
+ .position(-goalHalfWidth, goalHeight * 0.5, -(pitchHalfZ + goalDepth * 0.5)), primitives
153
+ .box({ name: "blue-goal-net-right", size: [0.12, goalHeight, goalDepth], material: blueGoalNetMat })
154
+ .position(goalHalfWidth, goalHeight * 0.5, -(pitchHalfZ + goalDepth * 0.5)), primitives
155
+ .box({ name: "blue-goal-line", size: [goalWidth, 0.02, 0.26], material: blueGoalFrameMat })
156
+ .position(0, 0.012, -pitchHalfZ), primitives
157
+ .box({ name: "orange-goal-post-left", size: [postThickness, goalHeight, postThickness], material: orangeGoalFrameMat })
158
+ .position(-goalHalfWidth, goalHeight * 0.5, pitchHalfZ), primitives
159
+ .box({ name: "orange-goal-post-right", size: [postThickness, goalHeight, postThickness], material: orangeGoalFrameMat })
160
+ .position(goalHalfWidth, goalHeight * 0.5, pitchHalfZ), primitives
161
+ .box({ name: "orange-goal-crossbar", size: [goalWidth + postThickness, postThickness, postThickness], material: orangeGoalFrameMat })
162
+ .position(0, goalHeight, pitchHalfZ), primitives
163
+ .box({ name: "orange-goal-back-top", size: [goalWidth + postThickness, 0.24, 0.24], material: orangeGoalFrameMat })
164
+ .position(0, goalHeight, pitchHalfZ + goalDepth), primitives
165
+ .box({ name: "orange-goal-net-back", size: [goalWidth, goalHeight, 0.12], material: orangeGoalNetMat })
166
+ .position(0, goalHeight * 0.5, pitchHalfZ + goalDepth), primitives
167
+ .box({ name: "orange-goal-net-left", size: [0.12, goalHeight, goalDepth], material: orangeGoalNetMat })
168
+ .position(-goalHalfWidth, goalHeight * 0.5, pitchHalfZ + goalDepth * 0.5), primitives
169
+ .box({ name: "orange-goal-net-right", size: [0.12, goalHeight, goalDepth], material: orangeGoalNetMat })
170
+ .position(goalHalfWidth, goalHeight * 0.5, pitchHalfZ + goalDepth * 0.5), primitives
171
+ .box({ name: "orange-goal-line", size: [goalWidth, 0.02, 0.26], material: orangeGoalFrameMat })
172
+ .position(0, 0.012, pitchHalfZ));
173
+ return nodes;
174
+ }
175
+ export function createCarSoccerGameKit(options = {}) {
176
+ const pitchHalfX = options.pitchHalfX ?? 18.5;
177
+ const pitchHalfZ = options.pitchHalfZ ?? 27.0;
178
+ const goalHalfWidth = options.goalHalfWidth ?? 5.6;
179
+ const goalHeight = options.goalHeight ?? 3.9;
180
+ const goalDepth = options.goalDepth ?? 3.6;
181
+ const ballRadius = options.ballRadius ?? 1.2;
182
+ const carCollisionRadius = options.carCollisionRadius ?? 1.85;
183
+ const carHalfHeight = options.carHalfHeight ?? 0.72;
184
+ const hero = {
185
+ id: "hero",
186
+ team: "orange",
187
+ x: 0,
188
+ y: 0,
189
+ z: 11.2,
190
+ vx: 0,
191
+ vy: 0,
192
+ vz: 0,
193
+ speed: 0,
194
+ heading: 0,
195
+ pitch: 0,
196
+ roll: 0,
197
+ boost: 100,
198
+ hopTimer: 0,
199
+ touchCooldown: 0
200
+ };
201
+ const green = {
202
+ id: "green",
203
+ team: "orange",
204
+ x: -7.5,
205
+ y: 0,
206
+ z: 16.5,
207
+ vx: 0,
208
+ vy: 0,
209
+ vz: 0,
210
+ speed: 0,
211
+ heading: 0.14,
212
+ pitch: 0,
213
+ roll: 0,
214
+ boost: 90,
215
+ hopTimer: 0,
216
+ touchCooldown: 0
217
+ };
218
+ const rival = {
219
+ id: "rival",
220
+ team: "blue",
221
+ x: 5.5,
222
+ y: 0,
223
+ z: -13.8,
224
+ vx: 0,
225
+ vy: 0,
226
+ vz: 0,
227
+ speed: 0,
228
+ heading: Math.PI - 0.16,
229
+ pitch: 0,
230
+ roll: 0,
231
+ boost: 90,
232
+ hopTimer: 0,
233
+ touchCooldown: 0
234
+ };
235
+ const purple = {
236
+ id: "purple",
237
+ team: "blue",
238
+ x: 0,
239
+ y: 0,
240
+ z: -23.2,
241
+ vx: 0,
242
+ vy: 0,
243
+ vz: 0,
244
+ speed: 0,
245
+ heading: Math.PI,
246
+ pitch: 0,
247
+ roll: 0,
248
+ boost: 100,
249
+ hopTimer: 0,
250
+ touchCooldown: 0
251
+ };
252
+ const ball = {
253
+ x: 0,
254
+ y: 0,
255
+ z: 0,
256
+ vx: 0,
257
+ vy: 0,
258
+ vz: 0,
259
+ wx: 0,
260
+ wy: 0,
261
+ wz: 0,
262
+ rx: 0,
263
+ ry: 0,
264
+ rz: 0,
265
+ lastTouchTeam: null,
266
+ lastTouchActor: null
267
+ };
268
+ function clampCarToPitch(car) {
269
+ const maxX = pitchHalfX - 1.45;
270
+ const maxZ = pitchHalfZ - 1.35;
271
+ const inGoalX = Math.abs(car.x) < goalHalfWidth - 1.1;
272
+ const limitZ = inGoalX ? pitchHalfZ + goalDepth - 1.2 : maxZ;
273
+ if (car.x < -maxX) {
274
+ car.x = -maxX;
275
+ if (car.vx < 0)
276
+ car.vx *= -0.35;
277
+ car.speed *= 0.88;
278
+ }
279
+ else if (car.x > maxX) {
280
+ car.x = maxX;
281
+ if (car.vx > 0)
282
+ car.vx *= -0.35;
283
+ car.speed *= 0.88;
284
+ }
285
+ if (car.z < -limitZ) {
286
+ car.z = -limitZ;
287
+ if (car.vz < 0)
288
+ car.vz *= -0.35;
289
+ car.speed *= 0.88;
290
+ }
291
+ else if (car.z > limitZ) {
292
+ car.z = limitZ;
293
+ if (car.vz > 0)
294
+ car.vz *= -0.35;
295
+ car.speed *= 0.88;
296
+ }
297
+ }
298
+ function stepAiMotion(car, dt, targetX, targetZ, targetSpeed, turnRate) {
299
+ if (car.touchCooldown > 0) {
300
+ car.touchCooldown = Math.max(0, car.touchCooldown - dt);
301
+ }
302
+ const dx = targetX - car.x;
303
+ const dz = targetZ - car.z;
304
+ const dist = Math.hypot(dx, dz);
305
+ const desiredHeading = Math.atan2(dx, -dz);
306
+ const deltaAngle = wrapAngle(desiredHeading - car.heading);
307
+ const turnStep = clamp(deltaAngle, -turnRate * dt, turnRate * dt);
308
+ car.heading = wrapAngle(car.heading + turnStep);
309
+ const alignment = Math.max(0.25, Math.cos(deltaAngle));
310
+ const desiredVel = dist < 0.75 ? 0 : targetSpeed * alignment;
311
+ car.speed += (desiredVel - car.speed) * Math.min(1, dt * 4.2);
312
+ const fx = Math.sin(car.heading);
313
+ const fz = -Math.cos(car.heading);
314
+ car.vx = fx * car.speed;
315
+ car.vz = fz * car.speed;
316
+ car.x += car.vx * dt;
317
+ car.z += car.vz * dt;
318
+ if (car.y > 0 || car.vy !== 0) {
319
+ car.vy -= 21 * dt;
320
+ car.y += car.vy * dt;
321
+ if (car.y <= 0) {
322
+ car.y = 0;
323
+ car.vy = 0;
324
+ }
325
+ }
326
+ car.roll = clamp(-deltaAngle * 0.12, -0.1, 0.1);
327
+ car.pitch = 0;
328
+ clampCarToPitch(car);
329
+ }
330
+ return {
331
+ kind: "aura-car-soccer-kit",
332
+ pitchHalfX,
333
+ pitchHalfZ,
334
+ goalHalfWidth,
335
+ goalHeight,
336
+ goalDepth,
337
+ ballRadius,
338
+ carCollisionRadius,
339
+ hero,
340
+ green,
341
+ rival,
342
+ purple,
343
+ ball,
344
+ resetKickoff() {
345
+ Object.assign(hero, {
346
+ x: 0,
347
+ y: 0,
348
+ z: 11.2,
349
+ vx: 0,
350
+ vy: 0,
351
+ vz: 0,
352
+ speed: 0,
353
+ heading: 0,
354
+ pitch: 0,
355
+ roll: 0,
356
+ hopTimer: 0,
357
+ touchCooldown: 0
358
+ });
359
+ Object.assign(green, {
360
+ x: -7.5,
361
+ y: 0,
362
+ z: 16.5,
363
+ vx: 0,
364
+ vy: 0,
365
+ vz: 0,
366
+ speed: 0,
367
+ heading: 0.14,
368
+ pitch: 0,
369
+ roll: 0,
370
+ boost: 90,
371
+ hopTimer: 0,
372
+ touchCooldown: 0
373
+ });
374
+ Object.assign(rival, {
375
+ x: 5.5,
376
+ y: 0,
377
+ z: -13.8,
378
+ vx: 0,
379
+ vy: 0,
380
+ vz: 0,
381
+ speed: 0,
382
+ heading: Math.PI - 0.16,
383
+ pitch: 0,
384
+ roll: 0,
385
+ boost: 90,
386
+ hopTimer: 0,
387
+ touchCooldown: 0
388
+ });
389
+ Object.assign(purple, {
390
+ x: 0,
391
+ y: 0,
392
+ z: -23.2,
393
+ vx: 0,
394
+ vy: 0,
395
+ vz: 0,
396
+ speed: 0,
397
+ heading: Math.PI,
398
+ pitch: 0,
399
+ roll: 0,
400
+ boost: 100,
401
+ hopTimer: 0,
402
+ touchCooldown: 0
403
+ });
404
+ Object.assign(ball, {
405
+ x: 0,
406
+ y: 0,
407
+ z: 0,
408
+ vx: 0,
409
+ vy: 0,
410
+ vz: 0,
411
+ wx: 0,
412
+ wy: 0,
413
+ wz: 0,
414
+ rx: 0,
415
+ ry: 0,
416
+ rz: 0,
417
+ lastTouchTeam: null,
418
+ lastTouchActor: null
419
+ });
420
+ },
421
+ stepHeroCar(dt, controls) {
422
+ if (hero.touchCooldown > 0) {
423
+ hero.touchCooldown = Math.max(0, hero.touchCooldown - dt);
424
+ }
425
+ const forwardInput = (controls.throttle ? 1 : 0) - (controls.brake ? 1 : 0);
426
+ const canBoost = controls.boost && hero.boost > 0.5;
427
+ const maxSpeed = canBoost ? 35 : 24;
428
+ const accel = canBoost ? 46 : 31;
429
+ const reverseAccel = 24;
430
+ if (forwardInput > 0) {
431
+ hero.speed = Math.min(maxSpeed, hero.speed + accel * dt);
432
+ }
433
+ else if (forwardInput < 0) {
434
+ hero.speed = Math.max(-15, hero.speed - reverseAccel * dt);
435
+ }
436
+ else {
437
+ hero.speed *= Math.exp(-2.8 * dt);
438
+ if (Math.abs(hero.speed) < 0.04)
439
+ hero.speed = 0;
440
+ }
441
+ if (canBoost) {
442
+ hero.boost = Math.max(0, hero.boost - 26 * dt);
443
+ if (hero.speed < 20) {
444
+ hero.speed = Math.min(maxSpeed, hero.speed + 18 * dt);
445
+ }
446
+ }
447
+ else {
448
+ hero.boost = Math.min(100, hero.boost + 3.2 * dt);
449
+ }
450
+ const steerDir = hero.speed >= -0.2 ? 1 : -1;
451
+ const speedTurnFactor = Math.min(1, Math.max(0.42, Math.abs(hero.speed) / 7.5));
452
+ const steerRate = 2.45;
453
+ if (Math.abs(controls.steer) > 1e-3) {
454
+ hero.heading = wrapAngle(hero.heading + controls.steer * steerRate * speedTurnFactor * steerDir * dt);
455
+ }
456
+ let hopped = false;
457
+ if (controls.hop && hero.hopTimer <= 0 && hero.y <= 0.05) {
458
+ hero.hopTimer = 0.52;
459
+ hero.vy = 6.8;
460
+ hero.speed = Math.min(36, Math.max(hero.speed + 5.5, 16));
461
+ hopped = true;
462
+ }
463
+ if (hero.hopTimer > 0) {
464
+ hero.hopTimer = Math.max(0, hero.hopTimer - dt);
465
+ }
466
+ if (hero.y > 0 || hero.vy !== 0) {
467
+ hero.vy -= 21.5 * dt;
468
+ hero.y += hero.vy * dt;
469
+ if (hero.y <= 0) {
470
+ hero.y = 0;
471
+ hero.vy = 0;
472
+ }
473
+ }
474
+ const fx = Math.sin(hero.heading);
475
+ const fz = -Math.cos(hero.heading);
476
+ hero.vx = fx * hero.speed;
477
+ hero.vz = fz * hero.speed;
478
+ hero.x += hero.vx * dt;
479
+ hero.z += hero.vz * dt;
480
+ hero.roll = -controls.steer * Math.min(1, Math.abs(hero.speed) / 18) * 0.09;
481
+ hero.pitch = hero.y > 0.05 ? clamp(hero.vy * 0.035, -0.22, 0.22) : 0;
482
+ clampCarToPitch(hero);
483
+ return { hopped };
484
+ },
485
+ stepTeammateAi(dt, car = green) {
486
+ const heroDistToBall = Math.hypot(ball.x - hero.x, ball.z - hero.z);
487
+ let targetX;
488
+ let targetZ;
489
+ let desiredSpeed;
490
+ if (heroDistToBall < 8.5) {
491
+ const supportSide = hero.x >= 0 ? -7.5 : 7.5;
492
+ targetX = clamp(ball.x * 0.45 + supportSide, -13.5, 13.5);
493
+ targetZ = clamp(ball.z + 8.5, -10, 19);
494
+ desiredSpeed = 14.5;
495
+ }
496
+ else {
497
+ targetX = ball.x * 0.85;
498
+ targetZ = ball.z + 1.8;
499
+ desiredSpeed = 17.5;
500
+ }
501
+ stepAiMotion(car, dt, targetX, targetZ, desiredSpeed, 2.5);
502
+ },
503
+ stepStrikerAi(dt, car = rival) {
504
+ const behindBallZ = ball.z - 2.1;
505
+ const isBehindBall = car.z <= ball.z + 0.6;
506
+ let targetX = ball.x;
507
+ let targetZ = behindBallZ;
508
+ if (!isBehindBall) {
509
+ const sideOffset = car.x >= ball.x ? 4.8 : -4.8;
510
+ targetX = clamp(ball.x + sideOffset, -14.5, 14.5);
511
+ targetZ = clamp(ball.z - 4.2, -23.5, 20.0);
512
+ }
513
+ stepAiMotion(car, dt, targetX, targetZ, 17.2, 2.6);
514
+ },
515
+ stepKeeperAi(dt, car = purple) {
516
+ const dangerZone = ball.z < -10.5 && ball.vz < 4;
517
+ const targetX = clamp(ball.x * 0.78, -(goalHalfWidth - 0.9), goalHalfWidth - 0.9);
518
+ const targetZ = dangerZone ? clamp(ball.z - 0.9, -23.8, -15.5) : -23.0;
519
+ stepAiMotion(car, dt, targetX, targetZ, dangerZone ? 17.5 : 13.5, 3.0);
520
+ },
521
+ resolveCarToCarBump(a, b) {
522
+ const dx = b.x - a.x;
523
+ const dz = b.z - a.z;
524
+ const dist = Math.hypot(dx, dz);
525
+ const minDist = carCollisionRadius * 1.72;
526
+ if (dist >= minDist || dist < 1e-4)
527
+ return false;
528
+ const nx = dx / dist;
529
+ const nz = dz / dist;
530
+ const overlap = minDist - dist;
531
+ a.x -= nx * overlap * 0.52;
532
+ a.z -= nz * overlap * 0.52;
533
+ b.x += nx * overlap * 0.52;
534
+ b.z += nz * overlap * 0.52;
535
+ const rvx = b.vx - a.vx;
536
+ const rvz = b.vz - a.vz;
537
+ const normalVel = rvx * nx + rvz * nz;
538
+ if (normalVel < 0) {
539
+ const impulse = -(1 + 0.45) * normalVel * 0.5;
540
+ a.vx -= impulse * nx;
541
+ a.vz -= impulse * nz;
542
+ b.vx += impulse * nx;
543
+ b.vz += impulse * nz;
544
+ a.speed *= 0.88;
545
+ b.speed *= 0.88;
546
+ }
547
+ clampCarToPitch(a);
548
+ clampCarToPitch(b);
549
+ return true;
550
+ },
551
+ stepBallPhysics(dt, cars = [hero, green, rival, purple]) {
552
+ const touchedBy = [];
553
+ let wallBounced = false;
554
+ let goalScored = null;
555
+ const substeps = 3;
556
+ const subDt = dt / substeps;
557
+ const hitRadius = carCollisionRadius + ballRadius;
558
+ for (let step = 0; step < substeps; step += 1) {
559
+ if (ball.y > 0 || ball.vy !== 0) {
560
+ ball.vy -= 17.5 * subDt;
561
+ }
562
+ const airFactor = ball.y > 0.15 ? 1.0 : 0.35;
563
+ ball.vx += ball.wy * ball.vz * 0.04 * airFactor * subDt;
564
+ ball.vz -= ball.wy * ball.vx * 0.04 * airFactor * subDt;
565
+ ball.x += ball.vx * subDt;
566
+ ball.y += ball.vy * subDt;
567
+ ball.z += ball.vz * subDt;
568
+ if (ball.y <= 0) {
569
+ ball.y = 0;
570
+ if (ball.vy < -1.35) {
571
+ ball.vy = -ball.vy * 0.76;
572
+ ball.vx *= 0.96;
573
+ ball.vz *= 0.96;
574
+ }
575
+ else {
576
+ ball.vy = 0;
577
+ }
578
+ const groundDrag = Math.exp(-0.72 * subDt);
579
+ ball.vx *= groundDrag;
580
+ ball.vz *= groundDrag;
581
+ ball.wx = ball.vz / ballRadius;
582
+ ball.wz = -ball.vx / ballRadius;
583
+ ball.wy *= Math.exp(-1.5 * subDt);
584
+ }
585
+ else {
586
+ const airDrag = Math.exp(-0.18 * subDt);
587
+ ball.vx *= airDrag;
588
+ ball.vz *= airDrag;
589
+ }
590
+ for (const car of cars) {
591
+ const carCenterY = car.y + carHalfHeight;
592
+ const ballCenterY = ball.y + ballRadius;
593
+ const dx = ball.x - car.x;
594
+ const dy = ballCenterY - carCenterY;
595
+ const dz = ball.z - car.z;
596
+ const distSq = dx * dx + dy * dy + dz * dz;
597
+ if (distSq < hitRadius * hitRadius && distSq > 1e-6) {
598
+ const dist = Math.sqrt(distSq);
599
+ const nx = dx / dist;
600
+ const ny = dy / dist;
601
+ const nz = dz / dist;
602
+ const overlap = hitRadius - dist;
603
+ ball.x += nx * overlap * 1.04;
604
+ ball.z += nz * overlap * 1.04;
605
+ if (ny > 0.15) {
606
+ ball.y = Math.max(0, ball.y + ny * overlap * 0.65);
607
+ }
608
+ const rvx = ball.vx - car.vx;
609
+ const rvy = ball.vy - car.vy;
610
+ const rvz = ball.vz - car.vz;
611
+ const relNormalVel = rvx * nx + rvy * ny + rvz * nz;
612
+ if (relNormalVel < 2.5) {
613
+ const carSpeed = Math.hypot(car.vx, car.vz);
614
+ const hopBonus = car.hopTimer > 0 ? 1.38 : 1.0;
615
+ const strikeSpeed = Math.max(12.5, carSpeed * 1.42 * hopBonus);
616
+ const carFx = Math.sin(car.heading);
617
+ const carFz = -Math.cos(car.heading);
618
+ const dirX = nx * 0.68 + carFx * 0.32;
619
+ const dirZ = nz * 0.68 + carFz * 0.32;
620
+ const dirLen = Math.hypot(dirX, dirZ) || 1;
621
+ ball.vx = (dirX / dirLen) * strikeSpeed + car.vx * 0.28;
622
+ ball.vz = (dirZ / dirLen) * strikeSpeed + car.vz * 0.28;
623
+ const loft = car.hopTimer > 0
624
+ ? 7.2
625
+ : clamp(3.6 + carSpeed * 0.22, 3.6, 9.4);
626
+ ball.vy = Math.max(ball.vy, loft);
627
+ const crossSpin = (car.vx * nz - car.vz * nx) * 0.35;
628
+ ball.wy = clamp(crossSpin, -9, 9);
629
+ ball.wx = ball.vz / ballRadius;
630
+ ball.wz = -ball.vx / ballRadius;
631
+ ball.lastTouchTeam = car.team;
632
+ ball.lastTouchActor = car.id;
633
+ if (car.touchCooldown <= 0) {
634
+ car.touchCooldown = 0.28;
635
+ const isShotOnBlueGoal = car.team === "orange" &&
636
+ ball.vz < -7.5 &&
637
+ Math.abs(ball.x) < goalHalfWidth + 4.0;
638
+ const isSaveAtBlueGoal = car.id === "purple" &&
639
+ ball.z < -17.5 &&
640
+ ball.vz > -2.0;
641
+ touchedBy.push({
642
+ actorId: car.id,
643
+ team: car.team,
644
+ isShotOnBlueGoal,
645
+ isSaveAtBlueGoal
646
+ });
647
+ }
648
+ }
649
+ }
650
+ }
651
+ const wallX = pitchHalfX - ballRadius;
652
+ const wallZ = pitchHalfZ - ballRadius;
653
+ const inGoalMouthX = Math.abs(ball.x) < goalHalfWidth - ballRadius * 0.45;
654
+ const underCrossbar = ball.y + ballRadius * 0.65 < goalHeight;
655
+ if (ball.x < -wallX) {
656
+ ball.x = -wallX;
657
+ ball.vx = Math.abs(ball.vx) * 0.82;
658
+ wallBounced = true;
659
+ }
660
+ else if (ball.x > wallX) {
661
+ ball.x = wallX;
662
+ ball.vx = -Math.abs(ball.vx) * 0.82;
663
+ wallBounced = true;
664
+ }
665
+ if (inGoalMouthX && underCrossbar) {
666
+ if (ball.z <= -(pitchHalfZ + ballRadius * 0.25)) {
667
+ goalScored = "orange";
668
+ break;
669
+ }
670
+ if (ball.z >= pitchHalfZ + ballRadius * 0.25) {
671
+ goalScored = "blue";
672
+ break;
673
+ }
674
+ }
675
+ else {
676
+ if (ball.z < -wallZ) {
677
+ ball.z = -wallZ;
678
+ ball.vz = Math.abs(ball.vz) * 0.82;
679
+ wallBounced = true;
680
+ }
681
+ else if (ball.z > wallZ) {
682
+ ball.z = wallZ;
683
+ ball.vz = -Math.abs(ball.vz) * 0.82;
684
+ wallBounced = true;
685
+ }
686
+ }
687
+ if (ball.y > 14.5) {
688
+ ball.y = 14.5;
689
+ if (ball.vy > 0)
690
+ ball.vy = -ball.vy * 0.65;
691
+ }
692
+ ball.rx = wrapAngle(ball.rx + ball.wx * subDt);
693
+ ball.ry = wrapAngle(ball.ry + ball.wy * subDt);
694
+ ball.rz = wrapAngle(ball.rz + ball.wz * subDt);
695
+ }
696
+ return {
697
+ touchedBy,
698
+ wallBounced,
699
+ goalScored
700
+ };
701
+ },
702
+ buildPitchAndGoalsNodes(pitchOptions = {}) {
703
+ return buildCarSoccerPitchNodes({
704
+ pitchHalfX: pitchOptions.pitchHalfX ?? pitchHalfX,
705
+ pitchHalfZ: pitchOptions.pitchHalfZ ?? pitchHalfZ,
706
+ goalHalfWidth: pitchOptions.goalHalfWidth ?? goalHalfWidth,
707
+ goalHeight: pitchOptions.goalHeight ?? goalHeight,
708
+ goalDepth: pitchOptions.goalDepth ?? goalDepth
709
+ });
710
+ }
711
+ };
712
+ }
713
+ export const carSoccer = {
714
+ create: createCarSoccerGameKit,
715
+ pitchNodes: buildCarSoccerPitchNodes
716
+ };
717
+ //# sourceMappingURL=carSoccer.js.map