rn-gamekit 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -0
- package/README.md +95 -14
- package/lib/module/assets/defineAssets.js +28 -3
- package/lib/module/assets/defineAssets.js.map +1 -1
- package/lib/module/assets.js +11 -0
- package/lib/module/assets.js.map +1 -0
- package/lib/module/audio/createGameAudio.js +784 -0
- package/lib/module/audio/createGameAudio.js.map +1 -0
- package/lib/module/audio/errors.js +12 -0
- package/lib/module/audio/errors.js.map +1 -0
- package/lib/module/audio/index.js +5 -0
- package/lib/module/audio/index.js.map +1 -0
- package/lib/module/audio/resolver.js +37 -0
- package/lib/module/audio/resolver.js.map +1 -0
- package/lib/module/audio/types.js +4 -0
- package/lib/module/audio/types.js.map +1 -0
- package/lib/module/audio.js +9 -0
- package/lib/module/audio.js.map +1 -0
- package/lib/module/camera2d/bounds.js +59 -0
- package/lib/module/camera2d/bounds.js.map +1 -0
- package/lib/module/camera2d/extents.js +25 -0
- package/lib/module/camera2d/extents.js.map +1 -0
- package/lib/module/camera2d/follow.js +138 -0
- package/lib/module/camera2d/follow.js.map +1 -0
- package/lib/module/camera2d/index.js +20 -0
- package/lib/module/camera2d/index.js.map +1 -0
- package/lib/module/camera2d/interpolation.js +98 -0
- package/lib/module/camera2d/interpolation.js.map +1 -0
- package/lib/module/camera2d/shake.js +85 -0
- package/lib/module/camera2d/shake.js.map +1 -0
- package/lib/module/camera2d/transform.js +151 -0
- package/lib/module/camera2d/transform.js.map +1 -0
- package/lib/module/camera2d/types.js +4 -0
- package/lib/module/camera2d/types.js.map +1 -0
- package/lib/module/camera2d/validation.js +98 -0
- package/lib/module/camera2d/validation.js.map +1 -0
- package/lib/module/camera2d/visibility.js +138 -0
- package/lib/module/camera2d/visibility.js.map +1 -0
- package/lib/module/camera2d.js +9 -0
- package/lib/module/camera2d.js.map +1 -0
- package/lib/module/collision2d/colliders.js +266 -0
- package/lib/module/collision2d/colliders.js.map +1 -0
- package/lib/module/collision2d/debug.js +105 -0
- package/lib/module/collision2d/debug.js.map +1 -0
- package/lib/module/collision2d/filters.js +40 -0
- package/lib/module/collision2d/filters.js.map +1 -0
- package/lib/module/collision2d/index.js +12 -0
- package/lib/module/collision2d/index.js.map +1 -0
- package/lib/module/collision2d/intersections.js +67 -0
- package/lib/module/collision2d/intersections.js.map +1 -0
- package/lib/module/collision2d/manifolds.js +218 -0
- package/lib/module/collision2d/manifolds.js.map +1 -0
- package/lib/module/collision2d/segments.js +187 -0
- package/lib/module/collision2d/segments.js.map +1 -0
- package/lib/module/collision2d/spatialHash.js +167 -0
- package/lib/module/collision2d/spatialHash.js.map +1 -0
- package/lib/module/collision2d/sweeps.js +255 -0
- package/lib/module/collision2d/sweeps.js.map +1 -0
- package/lib/module/collision2d.js +9 -0
- package/lib/module/collision2d.js.map +1 -0
- package/lib/module/core/input/buttonPad.js +214 -0
- package/lib/module/core/input/buttonPad.js.map +1 -0
- package/lib/module/core/input/createInputBuffer.js +66 -14
- package/lib/module/core/input/createInputBuffer.js.map +1 -1
- package/lib/module/core/session/createGameSession.js +454 -50
- package/lib/module/core/session/createGameSession.js.map +1 -1
- package/lib/module/core/session/deepFreeze.js +92 -2
- package/lib/module/core/session/deepFreeze.js.map +1 -1
- package/lib/module/core/session/types.js +12 -0
- package/lib/module/core/session/types.js.map +1 -1
- package/lib/module/definition/defineGame.js +23 -0
- package/lib/module/definition/defineGame.js.map +1 -1
- package/lib/module/events/defineGameEvents.js +46 -0
- package/lib/module/events/defineGameEvents.js.map +1 -0
- package/lib/module/events/errors.js +16 -0
- package/lib/module/events/errors.js.map +1 -0
- package/lib/module/events/index.js +7 -0
- package/lib/module/events/index.js.map +1 -0
- package/lib/module/events/payload.js +219 -0
- package/lib/module/events/payload.js.map +1 -0
- package/lib/module/events/seed.js +33 -0
- package/lib/module/events/seed.js.map +1 -0
- package/lib/module/events/types.js +4 -0
- package/lib/module/events/types.js.map +1 -0
- package/lib/module/events.js +13 -0
- package/lib/module/events.js.map +1 -0
- package/lib/module/geometry/helpers.js +140 -0
- package/lib/module/geometry/helpers.js.map +1 -0
- package/lib/module/geometry/index.js +5 -0
- package/lib/module/geometry/index.js.map +1 -0
- package/lib/module/geometry/validation.js +104 -0
- package/lib/module/geometry/validation.js.map +1 -0
- package/lib/module/geometry.js +9 -0
- package/lib/module/geometry.js.map +1 -0
- package/lib/module/haptics/createGameHaptics.js +214 -0
- package/lib/module/haptics/createGameHaptics.js.map +1 -0
- package/lib/module/haptics/errors.js +12 -0
- package/lib/module/haptics/errors.js.map +1 -0
- package/lib/module/haptics/index.js +5 -0
- package/lib/module/haptics/index.js.map +1 -0
- package/lib/module/haptics/resolver.js +37 -0
- package/lib/module/haptics/resolver.js.map +1 -0
- package/lib/module/haptics/types.js +4 -0
- package/lib/module/haptics/types.js.map +1 -0
- package/lib/module/haptics.js +9 -0
- package/lib/module/haptics.js.map +1 -0
- package/lib/module/index.js +8 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/particles/createParticleSystem.js +481 -0
- package/lib/module/particles/createParticleSystem.js.map +1 -0
- package/lib/module/particles/defineParticleEffect.js +178 -0
- package/lib/module/particles/defineParticleEffect.js.map +1 -0
- package/lib/module/particles/errors.js +9 -0
- package/lib/module/particles/errors.js.map +1 -0
- package/lib/module/particles/index.js +8 -0
- package/lib/module/particles/index.js.map +1 -0
- package/lib/module/particles/sampling.js +121 -0
- package/lib/module/particles/sampling.js.map +1 -0
- package/lib/module/particles/types.js +4 -0
- package/lib/module/particles/types.js.map +1 -0
- package/lib/module/particles.js +4 -0
- package/lib/module/particles.js.map +1 -0
- package/lib/module/react/GameButtonPad.js +344 -0
- package/lib/module/react/GameButtonPad.js.map +1 -0
- package/lib/module/react/GamePointerInput.js +74 -16
- package/lib/module/react/GamePointerInput.js.map +1 -1
- package/lib/module/react/GameView.js +139 -60
- package/lib/module/react/GameView.js.map +1 -1
- package/lib/module/react/assets/createGameAssetStore.js +145 -95
- package/lib/module/react/assets/createGameAssetStore.js.map +1 -1
- package/lib/module/react/assets/useGameAssets.js +60 -35
- package/lib/module/react/assets/useGameAssets.js.map +1 -1
- package/lib/module/react/bindAppLifecycle.js +46 -17
- package/lib/module/react/bindAppLifecycle.js.map +1 -1
- package/lib/module/react/bindGameSession.js +13 -2
- package/lib/module/react/bindGameSession.js.map +1 -1
- package/lib/module/react/camera2d/GameLayer2D.js +50 -0
- package/lib/module/react/camera2d/GameLayer2D.js.map +1 -0
- package/lib/module/react/camera2d/defineGameCamera2D.js +30 -0
- package/lib/module/react/camera2d/defineGameCamera2D.js.map +1 -0
- package/lib/module/react/camera2d/usePresentedCameraBinding.js +177 -0
- package/lib/module/react/camera2d/usePresentedCameraBinding.js.map +1 -0
- package/lib/module/react/cleanupList.js +38 -0
- package/lib/module/react/cleanupList.js.map +1 -0
- package/lib/module/react/lifecycleSource.js +49 -0
- package/lib/module/react/lifecycleSource.js.map +1 -0
- package/lib/module/react/particles/ParticleView.js +308 -0
- package/lib/module/react/particles/ParticleView.js.map +1 -0
- package/lib/module/react/particles/culling.js +115 -0
- package/lib/module/react/particles/culling.js.map +1 -0
- package/lib/module/react/particles/index.js +7 -0
- package/lib/module/react/particles/index.js.map +1 -0
- package/lib/module/react/particles/spriteXForm.js +45 -0
- package/lib/module/react/particles/spriteXForm.js.map +1 -0
- package/lib/module/react/particles/useParticlePresentation.js +204 -0
- package/lib/module/react/particles/useParticlePresentation.js.map +1 -0
- package/lib/module/react/pointerBinding.js +55 -17
- package/lib/module/react/pointerBinding.js.map +1 -1
- package/lib/module/react/pointerCamera.js +28 -0
- package/lib/module/react/pointerCamera.js.map +1 -0
- package/lib/module/react/pointerCoalescer.js +16 -9
- package/lib/module/react/pointerCoalescer.js.map +1 -1
- package/lib/module/react/sprites/GameSprite.js +5 -17
- package/lib/module/react/sprites/GameSprite.js.map +1 -1
- package/lib/module/react/sprites/GameWorld2D.js +112 -9
- package/lib/module/react/sprites/GameWorld2D.js.map +1 -1
- package/lib/module/react/sprites/Sprite.js +48 -63
- package/lib/module/react/sprites/Sprite.js.map +1 -1
- package/lib/module/react/sprites/SpriteBatch.js +53 -28
- package/lib/module/react/sprites/SpriteBatch.js.map +1 -1
- package/lib/module/react/sprites/batchVisibility.js +58 -0
- package/lib/module/react/sprites/batchVisibility.js.map +1 -0
- package/lib/module/react/sprites/spriteSelection.js +103 -0
- package/lib/module/react/sprites/spriteSelection.js.map +1 -0
- package/lib/module/react/sprites/spriteTransform.js +46 -25
- package/lib/module/react/sprites/spriteTransform.js.map +1 -1
- package/lib/module/react/tilemap/TileMapLayer2D.js +217 -0
- package/lib/module/react/tilemap/TileMapLayer2D.js.map +1 -0
- package/lib/module/react/tilemap/tilePresentation.js +374 -0
- package/lib/module/react/tilemap/tilePresentation.js.map +1 -0
- package/lib/module/react/useGameSession.js +70 -0
- package/lib/module/react/useGameSession.js.map +1 -0
- package/lib/module/react/useGameSessionStatus.js +46 -0
- package/lib/module/react/useGameSessionStatus.js.map +1 -0
- package/lib/module/react/viewportBinding.js +5 -1
- package/lib/module/react/viewportBinding.js.map +1 -1
- package/lib/module/react.js +12 -1
- package/lib/module/react.js.map +1 -1
- package/lib/module/scene/defineScene.js +17 -0
- package/lib/module/scene/defineScene.js.map +1 -1
- package/lib/module/sprites/sampleSpriteClip.js +66 -6
- package/lib/module/sprites/sampleSpriteClip.js.map +1 -1
- package/lib/module/sprites/spriteAnimationState.js +10 -20
- package/lib/module/sprites/spriteAnimationState.js.map +1 -1
- package/lib/module/sprites.js +11 -0
- package/lib/module/sprites.js.map +1 -0
- package/lib/module/storage/adapters/asyncStorage.js +57 -0
- package/lib/module/storage/adapters/asyncStorage.js.map +1 -0
- package/lib/module/storage/adapters/memory.js +50 -0
- package/lib/module/storage/adapters/memory.js.map +1 -0
- package/lib/module/storage/errors.js +34 -0
- package/lib/module/storage/errors.js.map +1 -0
- package/lib/module/storage/index.js +11 -0
- package/lib/module/storage/index.js.map +1 -0
- package/lib/module/storage/schema.js +151 -0
- package/lib/module/storage/schema.js.map +1 -0
- package/lib/module/storage/serialization.js +249 -0
- package/lib/module/storage/serialization.js.map +1 -0
- package/lib/module/storage/store.js +387 -0
- package/lib/module/storage/store.js.map +1 -0
- package/lib/module/storage/types.js +16 -0
- package/lib/module/storage/types.js.map +1 -0
- package/lib/module/storage/validation.js +111 -0
- package/lib/module/storage/validation.js.map +1 -0
- package/lib/module/storage.js +4 -0
- package/lib/module/storage.js.map +1 -0
- package/lib/module/testing.js +4 -0
- package/lib/module/testing.js.map +1 -1
- package/lib/module/tilemap/chunkStats.js +27 -0
- package/lib/module/tilemap/chunkStats.js.map +1 -0
- package/lib/module/tilemap/definitions.js +308 -0
- package/lib/module/tilemap/definitions.js.map +1 -0
- package/lib/module/tilemap/errors.js +13 -0
- package/lib/module/tilemap/errors.js.map +1 -0
- package/lib/module/tilemap/index.js +10 -0
- package/lib/module/tilemap/index.js.map +1 -0
- package/lib/module/tilemap/movement.js +379 -0
- package/lib/module/tilemap/movement.js.map +1 -0
- package/lib/module/tilemap/queries.js +114 -0
- package/lib/module/tilemap/queries.js.map +1 -0
- package/lib/module/tilemap/tiledAdapter.js +141 -0
- package/lib/module/tilemap/tiledAdapter.js.map +1 -0
- package/lib/module/tilemap/types.js +4 -0
- package/lib/module/tilemap/types.js.map +1 -0
- package/lib/module/tilemap.js +4 -0
- package/lib/module/tilemap.js.map +1 -0
- package/lib/typescript/src/assets/defineAssets.d.ts +1 -1
- package/lib/typescript/src/assets/defineAssets.d.ts.map +1 -1
- package/lib/typescript/src/assets.d.ts +11 -0
- package/lib/typescript/src/assets.d.ts.map +1 -0
- package/lib/typescript/src/audio/createGameAudio.d.ts +5 -0
- package/lib/typescript/src/audio/createGameAudio.d.ts.map +1 -0
- package/lib/typescript/src/audio/errors.d.ts +6 -0
- package/lib/typescript/src/audio/errors.d.ts.map +1 -0
- package/lib/typescript/src/audio/index.d.ts +4 -0
- package/lib/typescript/src/audio/index.d.ts.map +1 -0
- package/lib/typescript/src/audio/resolver.d.ts +44 -0
- package/lib/typescript/src/audio/resolver.d.ts.map +1 -0
- package/lib/typescript/src/audio/types.d.ts +42 -0
- package/lib/typescript/src/audio/types.d.ts.map +1 -0
- package/lib/typescript/src/audio.d.ts +8 -0
- package/lib/typescript/src/audio.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/bounds.d.ts +25 -0
- package/lib/typescript/src/camera2d/bounds.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/extents.d.ts +17 -0
- package/lib/typescript/src/camera2d/extents.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/follow.d.ts +24 -0
- package/lib/typescript/src/camera2d/follow.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/index.d.ts +19 -0
- package/lib/typescript/src/camera2d/index.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/interpolation.d.ts +17 -0
- package/lib/typescript/src/camera2d/interpolation.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/shake.d.ts +20 -0
- package/lib/typescript/src/camera2d/shake.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/transform.d.ts +44 -0
- package/lib/typescript/src/camera2d/transform.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/types.d.ts +74 -0
- package/lib/typescript/src/camera2d/types.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/validation.d.ts +30 -0
- package/lib/typescript/src/camera2d/validation.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/visibility.d.ts +47 -0
- package/lib/typescript/src/camera2d/visibility.d.ts.map +1 -0
- package/lib/typescript/src/camera2d.d.ts +7 -0
- package/lib/typescript/src/camera2d.d.ts.map +1 -0
- package/lib/typescript/src/collision2d/colliders.d.ts +120 -0
- package/lib/typescript/src/collision2d/colliders.d.ts.map +1 -0
- package/lib/typescript/src/collision2d/debug.d.ts +67 -0
- package/lib/typescript/src/collision2d/debug.d.ts.map +1 -0
- package/lib/typescript/src/collision2d/filters.d.ts +28 -0
- package/lib/typescript/src/collision2d/filters.d.ts.map +1 -0
- package/lib/typescript/src/collision2d/index.d.ts +17 -0
- package/lib/typescript/src/collision2d/index.d.ts.map +1 -0
- package/lib/typescript/src/collision2d/intersections.d.ts +24 -0
- package/lib/typescript/src/collision2d/intersections.d.ts.map +1 -0
- package/lib/typescript/src/collision2d/manifolds.d.ts +39 -0
- package/lib/typescript/src/collision2d/manifolds.d.ts.map +1 -0
- package/lib/typescript/src/collision2d/segments.d.ts +24 -0
- package/lib/typescript/src/collision2d/segments.d.ts.map +1 -0
- package/lib/typescript/src/collision2d/spatialHash.d.ts +50 -0
- package/lib/typescript/src/collision2d/spatialHash.d.ts.map +1 -0
- package/lib/typescript/src/collision2d/sweeps.d.ts +60 -0
- package/lib/typescript/src/collision2d/sweeps.d.ts.map +1 -0
- package/lib/typescript/src/collision2d.d.ts +7 -0
- package/lib/typescript/src/collision2d.d.ts.map +1 -0
- package/lib/typescript/src/core/input/buttonPad.d.ts +59 -0
- package/lib/typescript/src/core/input/buttonPad.d.ts.map +1 -0
- package/lib/typescript/src/core/input/createInputBuffer.d.ts +1 -1
- package/lib/typescript/src/core/input/createInputBuffer.d.ts.map +1 -1
- package/lib/typescript/src/core/input/types.d.ts +7 -0
- package/lib/typescript/src/core/input/types.d.ts.map +1 -1
- package/lib/typescript/src/core/session/createGameSession.d.ts +4 -2
- package/lib/typescript/src/core/session/createGameSession.d.ts.map +1 -1
- package/lib/typescript/src/core/session/deepFreeze.d.ts +21 -1
- package/lib/typescript/src/core/session/deepFreeze.d.ts.map +1 -1
- package/lib/typescript/src/core/session/diagnostics.d.ts +2 -0
- package/lib/typescript/src/core/session/diagnostics.d.ts.map +1 -1
- package/lib/typescript/src/core/session/types.d.ts +69 -4
- package/lib/typescript/src/core/session/types.d.ts.map +1 -1
- package/lib/typescript/src/definition/defineGame.d.ts +12 -1
- package/lib/typescript/src/definition/defineGame.d.ts.map +1 -1
- package/lib/typescript/src/definition/types.d.ts +10 -1
- package/lib/typescript/src/definition/types.d.ts.map +1 -1
- package/lib/typescript/src/events/defineGameEvents.d.ts +26 -0
- package/lib/typescript/src/events/defineGameEvents.d.ts.map +1 -0
- package/lib/typescript/src/events/errors.d.ts +12 -0
- package/lib/typescript/src/events/errors.d.ts.map +1 -0
- package/lib/typescript/src/events/index.d.ts +6 -0
- package/lib/typescript/src/events/index.d.ts.map +1 -0
- package/lib/typescript/src/events/payload.d.ts +21 -0
- package/lib/typescript/src/events/payload.d.ts.map +1 -0
- package/lib/typescript/src/events/seed.d.ts +3 -0
- package/lib/typescript/src/events/seed.d.ts.map +1 -0
- package/lib/typescript/src/events/types.d.ts +42 -0
- package/lib/typescript/src/events/types.d.ts.map +1 -0
- package/lib/typescript/src/events.d.ts +12 -0
- package/lib/typescript/src/events.d.ts.map +1 -0
- package/lib/typescript/src/geometry/helpers.d.ts +35 -0
- package/lib/typescript/src/geometry/helpers.d.ts.map +1 -0
- package/lib/typescript/src/geometry/index.d.ts +4 -0
- package/lib/typescript/src/geometry/index.d.ts.map +1 -0
- package/lib/typescript/src/geometry/types.d.ts +49 -0
- package/lib/typescript/src/geometry/types.d.ts.map +1 -1
- package/lib/typescript/src/geometry/validation.d.ts +44 -0
- package/lib/typescript/src/geometry/validation.d.ts.map +1 -0
- package/lib/typescript/src/geometry.d.ts +7 -0
- package/lib/typescript/src/geometry.d.ts.map +1 -0
- package/lib/typescript/src/haptics/createGameHaptics.d.ts +3 -0
- package/lib/typescript/src/haptics/createGameHaptics.d.ts.map +1 -0
- package/lib/typescript/src/haptics/errors.d.ts +6 -0
- package/lib/typescript/src/haptics/errors.d.ts.map +1 -0
- package/lib/typescript/src/haptics/index.d.ts +4 -0
- package/lib/typescript/src/haptics/index.d.ts.map +1 -0
- package/lib/typescript/src/haptics/resolver.d.ts +22 -0
- package/lib/typescript/src/haptics/resolver.d.ts.map +1 -0
- package/lib/typescript/src/haptics/types.d.ts +37 -0
- package/lib/typescript/src/haptics/types.d.ts.map +1 -0
- package/lib/typescript/src/haptics.d.ts +8 -0
- package/lib/typescript/src/haptics.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +10 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/particles/createParticleSystem.d.ts +5 -0
- package/lib/typescript/src/particles/createParticleSystem.d.ts.map +1 -0
- package/lib/typescript/src/particles/defineParticleEffect.d.ts +3 -0
- package/lib/typescript/src/particles/defineParticleEffect.d.ts.map +1 -0
- package/lib/typescript/src/particles/errors.d.ts +5 -0
- package/lib/typescript/src/particles/errors.d.ts.map +1 -0
- package/lib/typescript/src/particles/index.d.ts +6 -0
- package/lib/typescript/src/particles/index.d.ts.map +1 -0
- package/lib/typescript/src/particles/sampling.d.ts +54 -0
- package/lib/typescript/src/particles/sampling.d.ts.map +1 -0
- package/lib/typescript/src/particles/types.d.ts +292 -0
- package/lib/typescript/src/particles/types.d.ts.map +1 -0
- package/lib/typescript/src/particles.d.ts +2 -0
- package/lib/typescript/src/particles.d.ts.map +1 -0
- package/lib/typescript/src/react/GameButtonPad.d.ts +84 -0
- package/lib/typescript/src/react/GameButtonPad.d.ts.map +1 -0
- package/lib/typescript/src/react/GamePointerInput.d.ts.map +1 -1
- package/lib/typescript/src/react/GameView.d.ts +27 -1
- package/lib/typescript/src/react/GameView.d.ts.map +1 -1
- package/lib/typescript/src/react/assets/createGameAssetStore.d.ts.map +1 -1
- package/lib/typescript/src/react/assets/useGameAssets.d.ts.map +1 -1
- package/lib/typescript/src/react/bindAppLifecycle.d.ts +7 -1
- package/lib/typescript/src/react/bindAppLifecycle.d.ts.map +1 -1
- package/lib/typescript/src/react/bindGameSession.d.ts.map +1 -1
- package/lib/typescript/src/react/camera2d/GameLayer2D.d.ts +24 -0
- package/lib/typescript/src/react/camera2d/GameLayer2D.d.ts.map +1 -0
- package/lib/typescript/src/react/camera2d/defineGameCamera2D.d.ts +44 -0
- package/lib/typescript/src/react/camera2d/defineGameCamera2D.d.ts.map +1 -0
- package/lib/typescript/src/react/camera2d/usePresentedCameraBinding.d.ts +22 -0
- package/lib/typescript/src/react/camera2d/usePresentedCameraBinding.d.ts.map +1 -0
- package/lib/typescript/src/react/cleanupList.d.ts +21 -0
- package/lib/typescript/src/react/cleanupList.d.ts.map +1 -0
- package/lib/typescript/src/react/instrumentation.d.ts +33 -3
- package/lib/typescript/src/react/instrumentation.d.ts.map +1 -1
- package/lib/typescript/src/react/lifecycleSource.d.ts +21 -0
- package/lib/typescript/src/react/lifecycleSource.d.ts.map +1 -0
- package/lib/typescript/src/react/particles/ParticleView.d.ts +65 -0
- package/lib/typescript/src/react/particles/ParticleView.d.ts.map +1 -0
- package/lib/typescript/src/react/particles/culling.d.ts +70 -0
- package/lib/typescript/src/react/particles/culling.d.ts.map +1 -0
- package/lib/typescript/src/react/particles/index.d.ts +7 -0
- package/lib/typescript/src/react/particles/index.d.ts.map +1 -0
- package/lib/typescript/src/react/particles/spriteXForm.d.ts +28 -0
- package/lib/typescript/src/react/particles/spriteXForm.d.ts.map +1 -0
- package/lib/typescript/src/react/particles/useParticlePresentation.d.ts +48 -0
- package/lib/typescript/src/react/particles/useParticlePresentation.d.ts.map +1 -0
- package/lib/typescript/src/react/pointerBinding.d.ts +38 -8
- package/lib/typescript/src/react/pointerBinding.d.ts.map +1 -1
- package/lib/typescript/src/react/pointerCamera.d.ts +20 -0
- package/lib/typescript/src/react/pointerCamera.d.ts.map +1 -0
- package/lib/typescript/src/react/pointerCoalescer.d.ts +17 -1
- package/lib/typescript/src/react/pointerCoalescer.d.ts.map +1 -1
- package/lib/typescript/src/react/sprites/GameSprite.d.ts +3 -10
- package/lib/typescript/src/react/sprites/GameSprite.d.ts.map +1 -1
- package/lib/typescript/src/react/sprites/GameWorld2D.d.ts +51 -6
- package/lib/typescript/src/react/sprites/GameWorld2D.d.ts.map +1 -1
- package/lib/typescript/src/react/sprites/Sprite.d.ts.map +1 -1
- package/lib/typescript/src/react/sprites/SpriteBatch.d.ts +22 -1
- package/lib/typescript/src/react/sprites/SpriteBatch.d.ts.map +1 -1
- package/lib/typescript/src/react/sprites/batchVisibility.d.ts +28 -0
- package/lib/typescript/src/react/sprites/batchVisibility.d.ts.map +1 -0
- package/lib/typescript/src/react/sprites/spriteSelection.d.ts +58 -0
- package/lib/typescript/src/react/sprites/spriteSelection.d.ts.map +1 -0
- package/lib/typescript/src/react/sprites/spriteTransform.d.ts +27 -12
- package/lib/typescript/src/react/sprites/spriteTransform.d.ts.map +1 -1
- package/lib/typescript/src/react/tilemap/TileMapLayer2D.d.ts +69 -0
- package/lib/typescript/src/react/tilemap/TileMapLayer2D.d.ts.map +1 -0
- package/lib/typescript/src/react/tilemap/tilePresentation.d.ts +217 -0
- package/lib/typescript/src/react/tilemap/tilePresentation.d.ts.map +1 -0
- package/lib/typescript/src/react/useGameSession.d.ts +48 -0
- package/lib/typescript/src/react/useGameSession.d.ts.map +1 -0
- package/lib/typescript/src/react/useGameSessionStatus.d.ts +23 -0
- package/lib/typescript/src/react/useGameSessionStatus.d.ts.map +1 -0
- package/lib/typescript/src/react/viewportBinding.d.ts +5 -1
- package/lib/typescript/src/react/viewportBinding.d.ts.map +1 -1
- package/lib/typescript/src/react.d.ts +18 -1
- package/lib/typescript/src/react.d.ts.map +1 -1
- package/lib/typescript/src/scene/defineScene.d.ts +22 -2
- package/lib/typescript/src/scene/defineScene.d.ts.map +1 -1
- package/lib/typescript/src/scene/types.d.ts +24 -4
- package/lib/typescript/src/scene/types.d.ts.map +1 -1
- package/lib/typescript/src/sprites/sampleSpriteClip.d.ts +26 -2
- package/lib/typescript/src/sprites/sampleSpriteClip.d.ts.map +1 -1
- package/lib/typescript/src/sprites/spriteAnimationState.d.ts +6 -7
- package/lib/typescript/src/sprites/spriteAnimationState.d.ts.map +1 -1
- package/lib/typescript/src/sprites.d.ts +10 -0
- package/lib/typescript/src/sprites.d.ts.map +1 -0
- package/lib/typescript/src/storage/adapters/asyncStorage.d.ts +18 -0
- package/lib/typescript/src/storage/adapters/asyncStorage.d.ts.map +1 -0
- package/lib/typescript/src/storage/adapters/memory.d.ts +16 -0
- package/lib/typescript/src/storage/adapters/memory.d.ts.map +1 -0
- package/lib/typescript/src/storage/errors.d.ts +37 -0
- package/lib/typescript/src/storage/errors.d.ts.map +1 -0
- package/lib/typescript/src/storage/index.d.ts +11 -0
- package/lib/typescript/src/storage/index.d.ts.map +1 -0
- package/lib/typescript/src/storage/schema.d.ts +22 -0
- package/lib/typescript/src/storage/schema.d.ts.map +1 -0
- package/lib/typescript/src/storage/serialization.d.ts +23 -0
- package/lib/typescript/src/storage/serialization.d.ts.map +1 -0
- package/lib/typescript/src/storage/store.d.ts +3 -0
- package/lib/typescript/src/storage/store.d.ts.map +1 -0
- package/lib/typescript/src/storage/types.d.ts +69 -0
- package/lib/typescript/src/storage/types.d.ts.map +1 -0
- package/lib/typescript/src/storage/validation.d.ts +24 -0
- package/lib/typescript/src/storage/validation.d.ts.map +1 -0
- package/lib/typescript/src/storage.d.ts +2 -0
- package/lib/typescript/src/storage.d.ts.map +1 -0
- package/lib/typescript/src/testing.d.ts +1 -0
- package/lib/typescript/src/testing.d.ts.map +1 -1
- package/lib/typescript/src/tilemap/chunkStats.d.ts +14 -0
- package/lib/typescript/src/tilemap/chunkStats.d.ts.map +1 -0
- package/lib/typescript/src/tilemap/definitions.d.ts +38 -0
- package/lib/typescript/src/tilemap/definitions.d.ts.map +1 -0
- package/lib/typescript/src/tilemap/errors.d.ts +7 -0
- package/lib/typescript/src/tilemap/errors.d.ts.map +1 -0
- package/lib/typescript/src/tilemap/index.d.ts +8 -0
- package/lib/typescript/src/tilemap/index.d.ts.map +1 -0
- package/lib/typescript/src/tilemap/movement.d.ts +52 -0
- package/lib/typescript/src/tilemap/movement.d.ts.map +1 -0
- package/lib/typescript/src/tilemap/queries.d.ts +21 -0
- package/lib/typescript/src/tilemap/queries.d.ts.map +1 -0
- package/lib/typescript/src/tilemap/tiledAdapter.d.ts +32 -0
- package/lib/typescript/src/tilemap/tiledAdapter.d.ts.map +1 -0
- package/lib/typescript/src/tilemap/types.d.ts +127 -0
- package/lib/typescript/src/tilemap/types.d.ts.map +1 -0
- package/lib/typescript/src/tilemap.d.ts +2 -0
- package/lib/typescript/src/tilemap.d.ts.map +1 -0
- package/package.json +94 -4
- package/src/assets/defineAssets.ts +31 -5
- package/src/assets.ts +27 -0
- package/src/audio/createGameAudio.ts +749 -0
- package/src/audio/errors.ts +12 -0
- package/src/audio/index.ts +9 -0
- package/src/audio/resolver.ts +74 -0
- package/src/audio/types.ts +47 -0
- package/src/audio.ts +13 -0
- package/src/camera2d/bounds.ts +69 -0
- package/src/camera2d/extents.ts +25 -0
- package/src/camera2d/follow.ts +165 -0
- package/src/camera2d/index.ts +29 -0
- package/src/camera2d/interpolation.ts +113 -0
- package/src/camera2d/shake.ts +90 -0
- package/src/camera2d/transform.ts +148 -0
- package/src/camera2d/types.ts +73 -0
- package/src/camera2d/validation.ts +126 -0
- package/src/camera2d/visibility.ts +181 -0
- package/src/camera2d.ts +6 -0
- package/src/collision2d/colliders.ts +292 -0
- package/src/collision2d/debug.ts +133 -0
- package/src/collision2d/filters.ts +48 -0
- package/src/collision2d/index.ts +74 -0
- package/src/collision2d/intersections.ts +82 -0
- package/src/collision2d/manifolds.ts +191 -0
- package/src/collision2d/segments.ts +176 -0
- package/src/collision2d/spatialHash.ts +211 -0
- package/src/collision2d/sweeps.ts +269 -0
- package/src/collision2d.ts +6 -0
- package/src/core/input/buttonPad.ts +235 -0
- package/src/core/input/createInputBuffer.ts +95 -14
- package/src/core/input/types.ts +7 -0
- package/src/core/session/createGameSession.ts +480 -53
- package/src/core/session/deepFreeze.ts +104 -3
- package/src/core/session/diagnostics.ts +2 -0
- package/src/core/session/types.ts +77 -4
- package/src/definition/defineGame.ts +61 -3
- package/src/definition/types.ts +10 -0
- package/src/events/defineGameEvents.ts +46 -0
- package/src/events/errors.ts +14 -0
- package/src/events/index.ts +14 -0
- package/src/events/payload.ts +234 -0
- package/src/events/seed.ts +33 -0
- package/src/events/types.ts +53 -0
- package/src/events.ts +20 -0
- package/src/geometry/helpers.ts +136 -0
- package/src/geometry/index.ts +14 -0
- package/src/geometry/types.ts +54 -0
- package/src/geometry/validation.ts +131 -0
- package/src/geometry.ts +6 -0
- package/src/haptics/createGameHaptics.ts +214 -0
- package/src/haptics/errors.ts +12 -0
- package/src/haptics/index.ts +3 -0
- package/src/haptics/resolver.ts +58 -0
- package/src/haptics/types.ts +48 -0
- package/src/haptics.ts +7 -0
- package/src/index.ts +37 -1
- package/src/particles/createParticleSystem.ts +505 -0
- package/src/particles/defineParticleEffect.ts +164 -0
- package/src/particles/errors.ts +6 -0
- package/src/particles/index.ts +5 -0
- package/src/particles/sampling.ts +141 -0
- package/src/particles/types.ts +327 -0
- package/src/particles.ts +1 -0
- package/src/react/GameButtonPad.tsx +436 -0
- package/src/react/GamePointerInput.tsx +73 -8
- package/src/react/GameView.tsx +160 -61
- package/src/react/assets/createGameAssetStore.ts +140 -107
- package/src/react/assets/useGameAssets.ts +63 -31
- package/src/react/bindAppLifecycle.ts +55 -19
- package/src/react/bindGameSession.ts +12 -2
- package/src/react/camera2d/GameLayer2D.tsx +43 -0
- package/src/react/camera2d/defineGameCamera2D.ts +59 -0
- package/src/react/camera2d/usePresentedCameraBinding.ts +185 -0
- package/src/react/cleanupList.ts +48 -0
- package/src/react/instrumentation.ts +31 -3
- package/src/react/lifecycleSource.ts +58 -0
- package/src/react/particles/ParticleView.tsx +358 -0
- package/src/react/particles/culling.ts +145 -0
- package/src/react/particles/index.ts +6 -0
- package/src/react/particles/spriteXForm.ts +72 -0
- package/src/react/particles/useParticlePresentation.ts +261 -0
- package/src/react/pointerBinding.ts +74 -16
- package/src/react/pointerCamera.ts +33 -0
- package/src/react/pointerCoalescer.ts +36 -10
- package/src/react/sprites/GameSprite.tsx +4 -33
- package/src/react/sprites/GameWorld2D.tsx +113 -7
- package/src/react/sprites/Sprite.tsx +51 -72
- package/src/react/sprites/SpriteBatch.tsx +74 -22
- package/src/react/sprites/batchVisibility.ts +76 -0
- package/src/react/sprites/spriteSelection.ts +133 -0
- package/src/react/sprites/spriteTransform.ts +46 -26
- package/src/react/tilemap/TileMapLayer2D.tsx +274 -0
- package/src/react/tilemap/tilePresentation.ts +491 -0
- package/src/react/useGameSession.ts +90 -0
- package/src/react/useGameSessionStatus.ts +53 -0
- package/src/react/viewportBinding.ts +5 -1
- package/src/react.ts +18 -1
- package/src/scene/defineScene.ts +47 -5
- package/src/scene/types.ts +37 -3
- package/src/sprites/sampleSpriteClip.ts +82 -14
- package/src/sprites/spriteAnimationState.ts +29 -25
- package/src/sprites.ts +22 -0
- package/src/storage/adapters/asyncStorage.ts +77 -0
- package/src/storage/adapters/memory.ts +58 -0
- package/src/storage/errors.ts +88 -0
- package/src/storage/index.ts +18 -0
- package/src/storage/schema.ts +147 -0
- package/src/storage/serialization.ts +248 -0
- package/src/storage/store.ts +380 -0
- package/src/storage/types.ts +76 -0
- package/src/storage/validation.ts +102 -0
- package/src/storage.ts +1 -0
- package/src/testing.ts +4 -0
- package/src/tilemap/chunkStats.ts +24 -0
- package/src/tilemap/definitions.ts +327 -0
- package/src/tilemap/errors.ts +11 -0
- package/src/tilemap/index.ts +10 -0
- package/src/tilemap/movement.ts +368 -0
- package/src/tilemap/queries.ts +136 -0
- package/src/tilemap/tiledAdapter.ts +165 -0
- package/src/tilemap/types.ts +119 -0
- package/src/tilemap.ts +1 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contact manifolds (T11.2).
|
|
3
|
+
*
|
|
4
|
+
* A `CollisionHit2D` reports geometry only: the normal that moves the FIRST
|
|
5
|
+
* argument out of the SECOND, the nonnegative penetration depth, and a
|
|
6
|
+
* stable contact point. Applying `first += normal * depth` resolves an
|
|
7
|
+
* ordinary overlap within documented floating-point tolerance. Misses
|
|
8
|
+
* return `undefined` and allocate nothing.
|
|
9
|
+
*
|
|
10
|
+
* Conventions (locked in T11.0):
|
|
11
|
+
* - Boundary contact counts as intersection and may return a zero-depth hit.
|
|
12
|
+
* - Circle-AABB: the contact point is the closest point on the AABB to the
|
|
13
|
+
* circle center; when the center is inside the AABB, the minimum
|
|
14
|
+
* penetration face wins with ties in the order left, top, right, bottom.
|
|
15
|
+
* - Circle-circle: the contact point is on the first circle's boundary
|
|
16
|
+
* toward the second; coincident centers use the fallback normal `(0, 1)`
|
|
17
|
+
* (straight up the positive-y axis) with full overlap depth `r1 + r2`.
|
|
18
|
+
* - AABB-AABB: the contact point is the center of the overlap rectangle;
|
|
19
|
+
* exact corner ties use the normal `(0, 1)`.
|
|
20
|
+
*/
|
|
21
|
+
import type { Aabb2D, Circle2D, Point2D, Vector2D } from '../geometry/types';
|
|
22
|
+
import {
|
|
23
|
+
assertValidAabb2D,
|
|
24
|
+
assertValidCircle2D,
|
|
25
|
+
} from '../geometry/validation';
|
|
26
|
+
import { closestPointOnAabb2D } from './intersections';
|
|
27
|
+
|
|
28
|
+
/** One contact between two shapes, in the first shape's local resolution. */
|
|
29
|
+
export interface CollisionHit2D {
|
|
30
|
+
/** Unit normal moving the first argument out of the second. */
|
|
31
|
+
readonly normal: Vector2D;
|
|
32
|
+
/** Nonnegative penetration depth in logical world units. */
|
|
33
|
+
readonly depth: number;
|
|
34
|
+
/** Stable contact point in world coordinates. */
|
|
35
|
+
readonly point: Point2D;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Resolution tolerance used by tests: relative to the shape size. */
|
|
39
|
+
export const RESOLUTION_TOLERANCE = 1e-9;
|
|
40
|
+
|
|
41
|
+
/** AABB-AABB contact manifold. `undefined` when the shapes do not touch. */
|
|
42
|
+
export function collideAabbAabb2D(first: Aabb2D, second: Aabb2D): CollisionHit2D | undefined {
|
|
43
|
+
assertValidAabb2D(first, 'first');
|
|
44
|
+
assertValidAabb2D(second, 'second');
|
|
45
|
+
|
|
46
|
+
const firstMaxX = first.x + first.width;
|
|
47
|
+
const firstMaxY = first.y + first.height;
|
|
48
|
+
const secondMaxX = second.x + second.width;
|
|
49
|
+
const secondMaxY = second.y + second.height;
|
|
50
|
+
|
|
51
|
+
if (firstMaxX < second.x || first.x > secondMaxX || firstMaxY < second.y || first.y > secondMaxY) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Directional minimum translation (T11-F1): for each axis, the distance
|
|
56
|
+
// that fully separates the intervals in each direction. This resolves
|
|
57
|
+
// containment completely, not merely to a smaller intersection rectangle.
|
|
58
|
+
const exitLeft = firstMaxX - second.x;
|
|
59
|
+
const exitRight = secondMaxX - first.x;
|
|
60
|
+
const exitUp = firstMaxY - second.y;
|
|
61
|
+
const exitDown = secondMaxY - first.y;
|
|
62
|
+
const depthX = Math.min(exitLeft, exitRight);
|
|
63
|
+
const depthY = Math.min(exitUp, exitDown);
|
|
64
|
+
|
|
65
|
+
let normal: Vector2D;
|
|
66
|
+
let depth: number;
|
|
67
|
+
if (depthX === 0 && depthY === 0) {
|
|
68
|
+
// Exact corner touch: locked deterministic tie rule.
|
|
69
|
+
normal = Object.freeze({ x: 0, y: 1 });
|
|
70
|
+
depth = 0;
|
|
71
|
+
} else if (depthX < depthY) {
|
|
72
|
+
normal = Object.freeze({ x: exitLeft <= exitRight ? -1 : 1, y: 0 });
|
|
73
|
+
depth = depthX;
|
|
74
|
+
} else {
|
|
75
|
+
// Equal axes resolve on Y (locked tie rule); equal directions on the
|
|
76
|
+
// chosen axis resolve toward the negative direction.
|
|
77
|
+
normal = Object.freeze({ x: 0, y: exitUp <= exitDown ? -1 : 1 });
|
|
78
|
+
depth = depthY;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return Object.freeze({
|
|
82
|
+
normal,
|
|
83
|
+
depth,
|
|
84
|
+
point: Object.freeze({
|
|
85
|
+
x: (Math.max(first.x, second.x) + Math.min(firstMaxX, secondMaxX)) / 2,
|
|
86
|
+
y: (Math.max(first.y, second.y) + Math.min(firstMaxY, secondMaxY)) / 2,
|
|
87
|
+
}),
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Circle-circle contact manifold. `undefined` when the circles do not touch. */
|
|
92
|
+
export function collideCircleCircle2D(
|
|
93
|
+
first: Circle2D,
|
|
94
|
+
second: Circle2D,
|
|
95
|
+
): CollisionHit2D | undefined {
|
|
96
|
+
assertValidCircle2D(first, 'first');
|
|
97
|
+
assertValidCircle2D(second, 'second');
|
|
98
|
+
|
|
99
|
+
const dx = first.x - second.x;
|
|
100
|
+
const dy = first.y - second.y;
|
|
101
|
+
const radiusSum = first.radius + second.radius;
|
|
102
|
+
const distanceSquared = dx * dx + dy * dy;
|
|
103
|
+
if (distanceSquared > radiusSum * radiusSum) {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const distance = Math.sqrt(distanceSquared);
|
|
108
|
+
if (distance === 0) {
|
|
109
|
+
// Coincident centers: locked fallback normal (straight up), full
|
|
110
|
+
// overlap depth, contact point on the first circle's boundary along
|
|
111
|
+
// the normal.
|
|
112
|
+
return Object.freeze({
|
|
113
|
+
normal: Object.freeze({ x: 0, y: 1 }),
|
|
114
|
+
depth: radiusSum,
|
|
115
|
+
point: Object.freeze({ x: first.x, y: first.y + first.radius }),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// From the second center toward the first: moves the first argument out
|
|
120
|
+
// of the second.
|
|
121
|
+
const normal: Vector2D = Object.freeze({ x: dx / distance, y: dy / distance });
|
|
122
|
+
// Contact point: on the first circle's boundary, on the side facing the
|
|
123
|
+
// second circle (opposite the push-out normal).
|
|
124
|
+
return Object.freeze({
|
|
125
|
+
normal,
|
|
126
|
+
depth: radiusSum - distance,
|
|
127
|
+
point: Object.freeze({
|
|
128
|
+
x: first.x - normal.x * first.radius,
|
|
129
|
+
y: first.y - normal.y * first.radius,
|
|
130
|
+
}),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Circle-AABB contact manifold. `undefined` when they do not touch. */
|
|
135
|
+
export function collideCircleAabb2D(circle: Circle2D, aabb: Aabb2D): CollisionHit2D | undefined {
|
|
136
|
+
assertValidCircle2D(circle);
|
|
137
|
+
assertValidAabb2D(aabb);
|
|
138
|
+
|
|
139
|
+
const closest = closestPointOnAabb2D(circle, aabb);
|
|
140
|
+
const dx = circle.x - closest.x;
|
|
141
|
+
const dy = circle.y - closest.y;
|
|
142
|
+
const distanceSquared = dx * dx + dy * dy;
|
|
143
|
+
if (distanceSquared > circle.radius * circle.radius) {
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (distanceSquared === 0) {
|
|
148
|
+
// The circle center is inside the AABB: push out along the nearest
|
|
149
|
+
// face; ties resolve left, top, right, bottom (locked).
|
|
150
|
+
const left = circle.x - aabb.x;
|
|
151
|
+
const right = aabb.x + aabb.width - circle.x;
|
|
152
|
+
const top = circle.y - aabb.y;
|
|
153
|
+
const bottom = aabb.y + aabb.height - circle.y;
|
|
154
|
+
const minimum = Math.min(left, right, top, bottom);
|
|
155
|
+
|
|
156
|
+
let normal: Vector2D;
|
|
157
|
+
let point: Point2D;
|
|
158
|
+
if (minimum === left) {
|
|
159
|
+
normal = Object.freeze({ x: -1, y: 0 });
|
|
160
|
+
point = Object.freeze({ x: aabb.x, y: circle.y });
|
|
161
|
+
} else if (minimum === top) {
|
|
162
|
+
normal = Object.freeze({ x: 0, y: -1 });
|
|
163
|
+
point = Object.freeze({ x: circle.x, y: aabb.y });
|
|
164
|
+
} else if (minimum === right) {
|
|
165
|
+
normal = Object.freeze({ x: 1, y: 0 });
|
|
166
|
+
point = Object.freeze({ x: aabb.x + aabb.width, y: circle.y });
|
|
167
|
+
} else {
|
|
168
|
+
normal = Object.freeze({ x: 0, y: 1 });
|
|
169
|
+
point = Object.freeze({ x: circle.x, y: aabb.y + aabb.height });
|
|
170
|
+
}
|
|
171
|
+
return Object.freeze({
|
|
172
|
+
normal,
|
|
173
|
+
depth: minimum + circle.radius,
|
|
174
|
+
point,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const distance = Math.sqrt(distanceSquared);
|
|
179
|
+
// From the closest AABB point toward the circle center: moves the circle
|
|
180
|
+
// (the first argument) out of the AABB.
|
|
181
|
+
const normal: Vector2D = Object.freeze({ x: dx / distance, y: dy / distance });
|
|
182
|
+
return Object.freeze({
|
|
183
|
+
normal,
|
|
184
|
+
depth: circle.radius - distance,
|
|
185
|
+
// GS-COLLISION-01: copy-freeze the contact point at the public result
|
|
186
|
+
// boundary. `closest` is rebuilt per call, but copying keeps the hit
|
|
187
|
+
// independent of any future helper caching; sweeps reuse this object
|
|
188
|
+
// through hitFromManifold, so one fix covers every wrapper.
|
|
189
|
+
point: Object.freeze({ x: closest.x, y: closest.y }),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Segment queries (T11.3).
|
|
3
|
+
*
|
|
4
|
+
* Return the earliest crossing of a directed segment with a shape, with
|
|
5
|
+
* `time` in `[0, 1]`. A segment starting inside a shape returns `time: 0`
|
|
6
|
+
* with the deterministic nearest-face normal (same tie rule as the
|
|
7
|
+
* manifolds: left, top, right, bottom for AABBs; the outward radial
|
|
8
|
+
* direction for circles with the `(0, 1)` fallback at the center).
|
|
9
|
+
*/
|
|
10
|
+
import type { Aabb2D, Circle2D, Point2D, Segment2D, Vector2D } from '../geometry/types';
|
|
11
|
+
import {
|
|
12
|
+
assertValidAabb2D,
|
|
13
|
+
assertValidCircle2D,
|
|
14
|
+
assertValidSegment2D,
|
|
15
|
+
} from '../geometry/validation';
|
|
16
|
+
import { pointInAabb2D, pointInCircle2D } from './intersections';
|
|
17
|
+
|
|
18
|
+
/** Earliest segment crossing of a shape. */
|
|
19
|
+
export interface SegmentHit2D {
|
|
20
|
+
/** Normalized crossing time in `[0, 1]`. */
|
|
21
|
+
readonly time: number;
|
|
22
|
+
/** Unit normal at the crossed boundary (nearest-face rule inside). */
|
|
23
|
+
readonly normal: Vector2D;
|
|
24
|
+
/** Crossing point in world coordinates. */
|
|
25
|
+
readonly point: Point2D;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Earliest crossing of a segment with an AABB (slab method). */
|
|
29
|
+
export function intersectSegmentAabb2D(segment: Segment2D, aabb: Aabb2D): SegmentHit2D | undefined {
|
|
30
|
+
assertValidSegment2D(segment);
|
|
31
|
+
assertValidAabb2D(aabb);
|
|
32
|
+
|
|
33
|
+
if (pointInAabb2D(segment.start, aabb)) {
|
|
34
|
+
return insideStart(segment.start, aabb);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const dx = segment.end.x - segment.start.x;
|
|
38
|
+
const dy = segment.end.y - segment.start.y;
|
|
39
|
+
const minX = aabb.x;
|
|
40
|
+
const maxX = aabb.x + aabb.width;
|
|
41
|
+
const minY = aabb.y;
|
|
42
|
+
const maxY = aabb.y + aabb.height;
|
|
43
|
+
|
|
44
|
+
let tMin = 0;
|
|
45
|
+
let tMax = 1;
|
|
46
|
+
let entryAxis: 'x' | 'y' | undefined;
|
|
47
|
+
let entrySign = 0;
|
|
48
|
+
|
|
49
|
+
for (const axis of ['x', 'y'] as const) {
|
|
50
|
+
const origin = axis === 'x' ? segment.start.x : segment.start.y;
|
|
51
|
+
const delta = axis === 'x' ? dx : dy;
|
|
52
|
+
const min = axis === 'x' ? minX : minY;
|
|
53
|
+
const max = axis === 'x' ? maxX : maxY;
|
|
54
|
+
if (delta === 0) {
|
|
55
|
+
if (origin <= min || origin >= max) {
|
|
56
|
+
// Parallel and outside the slab, or grazing exactly along a
|
|
57
|
+
// boundary: neither is a crossing.
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const tMinFace = (min - origin) / delta;
|
|
63
|
+
const tMaxFace = (max - origin) / delta;
|
|
64
|
+
const t1 = Math.min(tMinFace, tMaxFace);
|
|
65
|
+
const t2 = Math.max(tMinFace, tMaxFace);
|
|
66
|
+
if (t1 > tMin) {
|
|
67
|
+
tMin = t1;
|
|
68
|
+
entryAxis = axis;
|
|
69
|
+
// The outward normal of the face crossed first: the min face points
|
|
70
|
+
// -axis, the max face points +axis.
|
|
71
|
+
entrySign = t1 === tMinFace ? -1 : 1;
|
|
72
|
+
}
|
|
73
|
+
tMax = Math.min(tMax, t2);
|
|
74
|
+
if (tMax < tMin) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (entryAxis === undefined) {
|
|
80
|
+
return undefined; // The segment travels along the boundary without crossing.
|
|
81
|
+
}
|
|
82
|
+
const atX = segment.start.x + dx * tMin;
|
|
83
|
+
const atY = segment.start.y + dy * tMin;
|
|
84
|
+
const normal: Vector2D =
|
|
85
|
+
entryAxis === 'x'
|
|
86
|
+
? Object.freeze({ x: entrySign, y: 0 })
|
|
87
|
+
: Object.freeze({ x: 0, y: entrySign });
|
|
88
|
+
return Object.freeze({
|
|
89
|
+
time: tMin,
|
|
90
|
+
normal,
|
|
91
|
+
point: Object.freeze({ x: atX, y: atY }),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** A segment starting inside an AABB: time 0 with the nearest-face normal. */
|
|
96
|
+
function insideStart(point: Point2D, aabb: Aabb2D): SegmentHit2D {
|
|
97
|
+
const left = point.x - aabb.x;
|
|
98
|
+
const right = aabb.x + aabb.width - point.x;
|
|
99
|
+
const top = point.y - aabb.y;
|
|
100
|
+
const bottom = aabb.y + aabb.height - point.y;
|
|
101
|
+
const minimum = Math.min(left, right, top, bottom);
|
|
102
|
+
let normal: Vector2D;
|
|
103
|
+
if (minimum === left) {
|
|
104
|
+
normal = Object.freeze({ x: -1, y: 0 });
|
|
105
|
+
} else if (minimum === top) {
|
|
106
|
+
normal = Object.freeze({ x: 0, y: -1 });
|
|
107
|
+
} else if (minimum === right) {
|
|
108
|
+
normal = Object.freeze({ x: 1, y: 0 });
|
|
109
|
+
} else {
|
|
110
|
+
normal = Object.freeze({ x: 0, y: 1 });
|
|
111
|
+
}
|
|
112
|
+
return Object.freeze({
|
|
113
|
+
time: 0,
|
|
114
|
+
normal,
|
|
115
|
+
point: Object.freeze({ x: point.x, y: point.y }),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Earliest crossing of a segment with a circle. */
|
|
120
|
+
export function intersectSegmentCircle2D(
|
|
121
|
+
segment: Segment2D,
|
|
122
|
+
circle: Circle2D,
|
|
123
|
+
): SegmentHit2D | undefined {
|
|
124
|
+
assertValidSegment2D(segment);
|
|
125
|
+
assertValidCircle2D(circle);
|
|
126
|
+
|
|
127
|
+
const dx = segment.end.x - segment.start.x;
|
|
128
|
+
const dy = segment.end.y - segment.start.y;
|
|
129
|
+
const fx = segment.start.x - circle.x;
|
|
130
|
+
const fy = segment.start.y - circle.y;
|
|
131
|
+
|
|
132
|
+
if (pointInCircle2D(segment.start, circle)) {
|
|
133
|
+
const distanceSquared = fx * fx + fy * fy;
|
|
134
|
+
const distance = Math.sqrt(distanceSquared);
|
|
135
|
+
// Outward radial: the normalized center-to-start vector. The (0, 1)
|
|
136
|
+
// fallback applies only at the exact center.
|
|
137
|
+
const normal: Vector2D =
|
|
138
|
+
distance === 0
|
|
139
|
+
? Object.freeze({ x: 0, y: 1 })
|
|
140
|
+
: Object.freeze({ x: fx / distance, y: fy / distance });
|
|
141
|
+
return Object.freeze({
|
|
142
|
+
time: 0,
|
|
143
|
+
normal,
|
|
144
|
+
point: Object.freeze({ x: segment.start.x, y: segment.start.y }),
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const a = dx * dx + dy * dy;
|
|
149
|
+
const b = 2 * (fx * dx + fy * dy);
|
|
150
|
+
const c = fx * fx + fy * fy - circle.radius * circle.radius;
|
|
151
|
+
const discriminant = b * b - 4 * a * c;
|
|
152
|
+
if (discriminant < 0) {
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const root = Math.sqrt(discriminant);
|
|
157
|
+
const t = (-b - root) / (2 * a);
|
|
158
|
+
if (t < 0 || t > 1) {
|
|
159
|
+
return undefined;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const atX = segment.start.x + dx * t;
|
|
163
|
+
const atY = segment.start.y + dy * t;
|
|
164
|
+
const outX = atX - circle.x;
|
|
165
|
+
const outY = atY - circle.y;
|
|
166
|
+
const outDistance = Math.hypot(outX, outY);
|
|
167
|
+
const normal: Vector2D =
|
|
168
|
+
outDistance === 0
|
|
169
|
+
? Object.freeze({ x: 0, y: 1 })
|
|
170
|
+
: Object.freeze({ x: outX / outDistance, y: outY / outDistance });
|
|
171
|
+
return Object.freeze({
|
|
172
|
+
time: t,
|
|
173
|
+
normal,
|
|
174
|
+
point: Object.freeze({ x: atX, y: atY }),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic spatial hash broad phase (T11.5).
|
|
3
|
+
*
|
|
4
|
+
* `buildSpatialHash2D` validates and freezes a plain immutable index value;
|
|
5
|
+
* the per-cell buckets live in an internal WeakMap so callers can never
|
|
6
|
+
* mutate or depend on them. `querySpatialHash2D` visits only the query's
|
|
7
|
+
* cells and returns candidate ids deduplicated and in original insertion
|
|
8
|
+
* order. The broad phase is conservative: it returns candidates, never a
|
|
9
|
+
* narrow-phase collision claim.
|
|
10
|
+
*/
|
|
11
|
+
import type { Aabb2D } from '../geometry/types';
|
|
12
|
+
import {
|
|
13
|
+
assertValidAabb2D,
|
|
14
|
+
GeometryError,
|
|
15
|
+
} from '../geometry/validation';
|
|
16
|
+
|
|
17
|
+
/** One indexed item with a stable identifier and AABB bounds. */
|
|
18
|
+
export interface SpatialHashItem2D {
|
|
19
|
+
/** Stable identifier; must be unique within one index. */
|
|
20
|
+
readonly id: string;
|
|
21
|
+
/** AABB bounds in world coordinates. */
|
|
22
|
+
readonly bounds: Aabb2D;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** A frozen, immutable spatial-hash index. */
|
|
26
|
+
export interface SpatialHashIndex2D {
|
|
27
|
+
/** Positive finite cell size in world units. */
|
|
28
|
+
readonly cellSize: number;
|
|
29
|
+
/** The ordered items, deduplicated by identifier. */
|
|
30
|
+
readonly items: readonly SpatialHashItem2D[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Options for building an index. */
|
|
34
|
+
export interface BuildSpatialHash2DOptions {
|
|
35
|
+
/** Items to index, in the order candidates must be returned. */
|
|
36
|
+
readonly items: readonly SpatialHashItem2D[];
|
|
37
|
+
/** Positive finite cell size in world units. */
|
|
38
|
+
readonly cellSize: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Maximum cells an item or query may OCCUPY per axis (bounded execution). */
|
|
42
|
+
export const MAX_SPATIAL_HASH_SPAN_CELLS = 1024;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Maximum cells visited by ONE item insert or ONE query (GS-COLLISION-02).
|
|
46
|
+
*
|
|
47
|
+
* The per-axis bound alone permits ~1M cell visits per operation (~38ms
|
|
48
|
+
* on desktop V8, multiples of that on mobile). The total budget fails
|
|
49
|
+
* clearly before such spans do any work. Ordinary game spans (a few
|
|
50
|
+
* hundred cells per axis at most) pass with wide headroom; aggregate build
|
|
51
|
+
* cost still scales with item count, so prefer an appropriate cell size
|
|
52
|
+
* and reuse static indexes instead of rebuilding per dynamic body per tick.
|
|
53
|
+
*/
|
|
54
|
+
export const MAX_SPATIAL_HASH_TOTAL_CELLS = 65_536;
|
|
55
|
+
|
|
56
|
+
/** Opaque per-index internal buckets and order, never exposed publicly. */
|
|
57
|
+
const internalState = new WeakMap<
|
|
58
|
+
SpatialHashIndex2D,
|
|
59
|
+
{ readonly cells: ReadonlyMap<string, readonly string[]>; readonly order: ReadonlyMap<string, number> }
|
|
60
|
+
>();
|
|
61
|
+
|
|
62
|
+
/** Build a spatial-hash index over the given items. */
|
|
63
|
+
export function buildSpatialHash2D(options: BuildSpatialHash2DOptions): SpatialHashIndex2D {
|
|
64
|
+
const { items, cellSize } = options;
|
|
65
|
+
if (!Number.isFinite(cellSize) || cellSize <= 0) {
|
|
66
|
+
throw new GeometryError(
|
|
67
|
+
'GEOMETRY_INVALID_NUMBER',
|
|
68
|
+
'cellSize',
|
|
69
|
+
`expected a positive finite number, got ${String(cellSize)}`,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
const seen = new Set<string>();
|
|
73
|
+
const cells = new Map<string, string[]>();
|
|
74
|
+
const order = new Map<string, number>();
|
|
75
|
+
const frozenItems: SpatialHashItem2D[] = [];
|
|
76
|
+
for (const item of items) {
|
|
77
|
+
if (seen.has(item.id)) {
|
|
78
|
+
throw new GeometryError(
|
|
79
|
+
'GEOMETRY_DUPLICATE_ID',
|
|
80
|
+
'items.id',
|
|
81
|
+
`expected unique item ids, got duplicate "${item.id}"`,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
seen.add(item.id);
|
|
85
|
+
assertValidAabb2D(item.bounds, `items.${item.id}.bounds`);
|
|
86
|
+
// Clone the caller's item and its bounds: the index must never freeze
|
|
87
|
+
// or retain caller-owned objects, and the private buckets must agree
|
|
88
|
+
// with the public `items` view.
|
|
89
|
+
const cloned: SpatialHashItem2D = Object.freeze({
|
|
90
|
+
id: item.id,
|
|
91
|
+
bounds: Object.freeze({ ...item.bounds }),
|
|
92
|
+
});
|
|
93
|
+
frozenItems.push(cloned);
|
|
94
|
+
order.set(item.id, frozenItems.length - 1);
|
|
95
|
+
for (const cell of cellsOf(cloned.bounds, cellSize)) {
|
|
96
|
+
const key = cellKey(cell.x, cell.y);
|
|
97
|
+
const bucket = cells.get(key);
|
|
98
|
+
if (bucket === undefined) {
|
|
99
|
+
cells.set(key, [item.id]);
|
|
100
|
+
} else {
|
|
101
|
+
bucket.push(item.id);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const index = Object.freeze({
|
|
106
|
+
cellSize,
|
|
107
|
+
items: Object.freeze(frozenItems),
|
|
108
|
+
});
|
|
109
|
+
internalState.set(index, {
|
|
110
|
+
cells: new Map([...cells.entries()].map(([key, ids]) => [key, Object.freeze(ids)])),
|
|
111
|
+
// The local `order` map never escapes this function, so it is stored
|
|
112
|
+
// directly (GS-COLLISION-02): the extra copy served no ownership purpose.
|
|
113
|
+
order,
|
|
114
|
+
});
|
|
115
|
+
return index;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Query candidates whose bounds share a cell with the query bounds. */
|
|
119
|
+
export function querySpatialHash2D(index: SpatialHashIndex2D, bounds: Aabb2D): readonly string[] {
|
|
120
|
+
assertValidAabb2D(bounds, 'bounds');
|
|
121
|
+
const state = internalState.get(index);
|
|
122
|
+
if (state === undefined) {
|
|
123
|
+
throw new GeometryError(
|
|
124
|
+
'GEOMETRY_INVALID_NUMBER',
|
|
125
|
+
'index',
|
|
126
|
+
'expected an index built by buildSpatialHash2D',
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
const seen = new Set<string>();
|
|
130
|
+
const collected: string[] = [];
|
|
131
|
+
for (const cell of cellsOf(bounds, index.cellSize)) {
|
|
132
|
+
const bucket = state.cells.get(cellKey(cell.x, cell.y));
|
|
133
|
+
if (bucket === undefined) {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
for (const id of bucket) {
|
|
137
|
+
if (!seen.has(id)) {
|
|
138
|
+
seen.add(id);
|
|
139
|
+
collected.push(id);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// Preserve original insertion order regardless of bucket order.
|
|
144
|
+
collected.sort((a, b) => state.order.get(a)! - state.order.get(b)!);
|
|
145
|
+
// The public result is frozen (T11-FF5): the immutable contract is
|
|
146
|
+
// runtime-enforced, not only a type-level promise.
|
|
147
|
+
return Object.freeze(collected);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
interface Cell {
|
|
151
|
+
readonly x: number;
|
|
152
|
+
readonly y: number;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** Every cell an AABB occupies, in deterministic order. */
|
|
156
|
+
function* cellsOf(bounds: Aabb2D, cellSize: number): Generator<Cell> {
|
|
157
|
+
const minX = cellIndex(bounds.x, cellSize);
|
|
158
|
+
const maxX = cellIndex(bounds.x + bounds.width, cellSize);
|
|
159
|
+
const minY = cellIndex(bounds.y, cellSize);
|
|
160
|
+
const maxY = cellIndex(bounds.y + bounds.height, cellSize);
|
|
161
|
+
assertSpan(maxX - minX, 'x');
|
|
162
|
+
assertSpan(maxY - minY, 'y');
|
|
163
|
+
assertTotalCells(maxX - minX, maxY - minY);
|
|
164
|
+
for (let y = minY; y <= maxY; y += 1) {
|
|
165
|
+
for (let x = minX; x <= maxX; x += 1) {
|
|
166
|
+
yield { x, y };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Validate a derived cell index as a finite safe integer. */
|
|
172
|
+
function cellIndex(coord: number, cellSize: number): number {
|
|
173
|
+
const index = Math.floor(coord / cellSize);
|
|
174
|
+
if (!Number.isSafeInteger(index)) {
|
|
175
|
+
throw new GeometryError(
|
|
176
|
+
'GEOMETRY_SPATIAL_INDEX_RANGE',
|
|
177
|
+
'bounds',
|
|
178
|
+
`coordinate ${coord} produces an unsafe cell index`,
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
return index;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Reject spans that would block the JS thread (bounded execution). */
|
|
185
|
+
function assertSpan(span: number, axis: 'x' | 'y'): void {
|
|
186
|
+
const cells = span + 1; // The inclusive loop visits span + 1 cells.
|
|
187
|
+
if (cells > MAX_SPATIAL_HASH_SPAN_CELLS) {
|
|
188
|
+
throw new GeometryError(
|
|
189
|
+
'GEOMETRY_SPATIAL_INDEX_RANGE',
|
|
190
|
+
`bounds.${axis}`,
|
|
191
|
+
`bounds occupy ${cells} cells, exceeding the maximum of ${MAX_SPATIAL_HASH_SPAN_CELLS}`,
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** Reject total occupied cells beyond the work budget (GS-COLLISION-02). */
|
|
197
|
+
function assertTotalCells(spanX: number, spanY: number): void {
|
|
198
|
+
// Both axes already passed assertSpan, so the product cannot overflow.
|
|
199
|
+
const total = (spanX + 1) * (spanY + 1);
|
|
200
|
+
if (total > MAX_SPATIAL_HASH_TOTAL_CELLS) {
|
|
201
|
+
throw new GeometryError(
|
|
202
|
+
'GEOMETRY_SPATIAL_INDEX_RANGE',
|
|
203
|
+
'bounds',
|
|
204
|
+
`bounds occupy ${total} cells, exceeding the total maximum of ${MAX_SPATIAL_HASH_TOTAL_CELLS}`,
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function cellKey(x: number, y: number): string {
|
|
210
|
+
return `${x},${y}`;
|
|
211
|
+
}
|