rn-gamekit 0.1.0 → 0.2.1
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 +75 -0
- package/README.md +97 -16
- 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 +100 -10
- 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,491 @@
|
|
|
1
|
+
import type { TileMap2D, TileSet2D } from '../../tilemap/types';
|
|
2
|
+
import { rotatedHalfExtents2D } from '../../camera2d/extents';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Tile presentation binding (T16-F3/F4).
|
|
6
|
+
*
|
|
7
|
+
* Pure module shared between the JS thread and UI-runtime worklets:
|
|
8
|
+
*
|
|
9
|
+
* - `buildFrameTable` runs ONCE on JS at bind time and produces a flat,
|
|
10
|
+
* worklet-safe numeric lookup (`frameFlat[id*4..id*4+3]`) — no `Map`,
|
|
11
|
+
* no objects, no per-frame lookups on the UI runtime.
|
|
12
|
+
* - `buildTileWindowSnapshot` runs on JS whenever the visible cell window
|
|
13
|
+
* or source binding changes and produces a BOUNDED snapshot sized by the
|
|
14
|
+
* viewport capacity, never by map dimensions.
|
|
15
|
+
* - `writeLayerVisibleBounds` / `fillTileSlots` are worklet-callable and
|
|
16
|
+
* allocation-free: camera interpolation inside the transferred window
|
|
17
|
+
* only reads scalars and pre-transferred arrays.
|
|
18
|
+
*
|
|
19
|
+
* Full map authority stays on the simulation side; the UI runtime never
|
|
20
|
+
* sees `layer.data`, the chunk index, or the map value itself.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/** Flat numeric frame lookup: frameFlat[tileId*4] = x, [+1]=y, [+2]=w, [+3]=h. */
|
|
24
|
+
export type TileFrameTable = readonly number[];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Resolve every declared tile to sheet-frame rectangles ONCE at bind time.
|
|
28
|
+
*
|
|
29
|
+
* Throws a structured error when a referenced frame is missing from the
|
|
30
|
+
* bound sheet OR when its size differs from the map cell — v1 requires
|
|
31
|
+
* frame dimensions to equal cell dimensions (T16-F3).
|
|
32
|
+
*/
|
|
33
|
+
export function buildFrameTable(
|
|
34
|
+
tileset: TileSet2D,
|
|
35
|
+
frames: Readonly<Record<string, { x: number; y: number; width: number; height: number }>>,
|
|
36
|
+
cellWidth: number,
|
|
37
|
+
cellHeight: number,
|
|
38
|
+
): TileFrameTable {
|
|
39
|
+
const maxId = tileset.names.length;
|
|
40
|
+
const flat: number[] = new Array((maxId + 1) * 4).fill(0);
|
|
41
|
+
for (let id = 1; id <= maxId; id++) {
|
|
42
|
+
const name = tileset.nameOfId[id]!;
|
|
43
|
+
const def = tileset.tiles[name]!;
|
|
44
|
+
const rect = frames[def.frame];
|
|
45
|
+
if (rect === undefined) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`[rn-gamekit/tilemap] frame "${def.frame}" for tile "${name}" is missing from the bound sheet`,
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
if (rect.width !== cellWidth || rect.height !== cellHeight) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`[rn-gamekit/tilemap] frame "${def.frame}" for tile "${name}" is ${rect.width}x${rect.height} but the map cell is ${cellWidth}x${cellHeight}; v1 requires frame dimensions to equal cell dimensions`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
flat[id * 4] = rect.x;
|
|
56
|
+
flat[id * 4 + 1] = rect.y;
|
|
57
|
+
flat[id * 4 + 2] = rect.width;
|
|
58
|
+
flat[id * 4 + 3] = rect.height;
|
|
59
|
+
}
|
|
60
|
+
return Object.freeze(flat);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Bounded visible-window snapshot transferred to the UI runtime. */
|
|
64
|
+
export interface TileWindowSnapshot {
|
|
65
|
+
/** Window origin in cell coordinates. */
|
|
66
|
+
readonly x0: number;
|
|
67
|
+
readonly y0: number;
|
|
68
|
+
/** Window extent in cells (ids.length === w*h). */
|
|
69
|
+
readonly w: number;
|
|
70
|
+
readonly h: number;
|
|
71
|
+
/** Row-major tile ids for the window; 0 = empty. */
|
|
72
|
+
readonly ids: readonly number[];
|
|
73
|
+
/** Flat frame lookup shared by all windows of one binding. */
|
|
74
|
+
readonly frameFlat: readonly number[];
|
|
75
|
+
/**
|
|
76
|
+
* Binding generation that published this window (GS-TILE-01). Stamp
|
|
77
|
+
* applied by the binding when it publishes; snapshots built directly
|
|
78
|
+
* (tests, initial empty) carry no generation and never satisfy a bound
|
|
79
|
+
* update. A generation mismatch means a same-size replacement or a
|
|
80
|
+
* remount happened: the window is ignored, never displayed.
|
|
81
|
+
*/
|
|
82
|
+
readonly gen?: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export const EMPTY_TILE_WINDOW: TileWindowSnapshot = Object.freeze({
|
|
86
|
+
x0: 0,
|
|
87
|
+
y0: 0,
|
|
88
|
+
w: 0,
|
|
89
|
+
h: 0,
|
|
90
|
+
ids: Object.freeze([]),
|
|
91
|
+
frameFlat: Object.freeze([]),
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Build a bounded snapshot for the inclusive cell range [x0..x1]×[y0..y1].
|
|
96
|
+
* The range is clamped to the layer; the result size depends ONLY on the
|
|
97
|
+
* requested range (bounded by viewport capacity), never on map size.
|
|
98
|
+
*/
|
|
99
|
+
export function buildTileWindowSnapshot(
|
|
100
|
+
map: TileMap2D,
|
|
101
|
+
layerId: string,
|
|
102
|
+
x0: number, y0: number, x1: number, y1: number,
|
|
103
|
+
frameFlat: TileFrameTable,
|
|
104
|
+
): TileWindowSnapshot {
|
|
105
|
+
const layer = map.layerById[layerId];
|
|
106
|
+
if (layer === undefined) return EMPTY_TILE_WINDOW;
|
|
107
|
+
const cx0 = Math.max(0, Math.min(x0, x1));
|
|
108
|
+
const cy0 = Math.max(0, Math.min(y0, y1));
|
|
109
|
+
const cx1 = Math.min(layer.width - 1, Math.max(x0, x1));
|
|
110
|
+
const cy1 = Math.min(layer.height - 1, Math.max(y0, y1));
|
|
111
|
+
if (cx0 > cx1 || cy0 > cy1) return EMPTY_TILE_WINDOW;
|
|
112
|
+
const w = cx1 - cx0 + 1;
|
|
113
|
+
const h = cy1 - cy0 + 1;
|
|
114
|
+
const ids: number[] = new Array(w * h).fill(0);
|
|
115
|
+
for (let cy = cy0; cy <= cy1; cy++) {
|
|
116
|
+
for (let cx = cx0; cx <= cx1; cx++) {
|
|
117
|
+
const id = layer.data[cy * layer.width + cx]!;
|
|
118
|
+
if (id !== 0) ids[(cy - cy0) * w + (cx - cx0)] = id;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return Object.freeze({
|
|
122
|
+
x0: cx0,
|
|
123
|
+
y0: cy0,
|
|
124
|
+
w,
|
|
125
|
+
h,
|
|
126
|
+
ids: Object.freeze(ids),
|
|
127
|
+
frameFlat,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Whether the snapshot fully covers the inclusive cell range. */
|
|
132
|
+
export function windowCovers(
|
|
133
|
+
snap: TileWindowSnapshot,
|
|
134
|
+
x0: number, y0: number, x1: number, y1: number,
|
|
135
|
+
): boolean {
|
|
136
|
+
'worklet';
|
|
137
|
+
if (snap.w === 0 || snap.h === 0) return false;
|
|
138
|
+
return snap.x0 <= x0 && snap.y0 <= y0 && snap.x0 + snap.w - 1 >= x1 && snap.y0 + snap.h - 1 >= y1;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Minimal structural mirrors of the shared refs, keeping this pure module
|
|
142
|
+
// free of Reanimated/RN imports while accepting real SharedValues.
|
|
143
|
+
interface SharedLike<T> {
|
|
144
|
+
readonly value?: T;
|
|
145
|
+
}
|
|
146
|
+
export type SharedCameraRef = SharedLike<
|
|
147
|
+
{ camera?: { center: { x: number; y: number }; zoom: number; rotationRadians: number } } | undefined
|
|
148
|
+
>;
|
|
149
|
+
export type SharedViewportRef = SharedLike<
|
|
150
|
+
{ visibleLogicalBounds?: { x: number; y: number; width: number; height: number } } | undefined
|
|
151
|
+
>;
|
|
152
|
+
|
|
153
|
+
export interface LayerBounds {
|
|
154
|
+
minX: number;
|
|
155
|
+
minY: number;
|
|
156
|
+
maxX: number;
|
|
157
|
+
maxY: number;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Write the conservative world-space bounds visible through the PRESENTED
|
|
162
|
+
* camera into `out` (T16-F3, reworked per T16-RF2).
|
|
163
|
+
*
|
|
164
|
+
* - With a presented camera: the logical view rect is rotated/zoomed by the
|
|
165
|
+
* camera, so its axis-aligned world bounds are the center plus rotated
|
|
166
|
+
* half-extents; the GameLayer2D parallax model applies ONCE afterwards
|
|
167
|
+
* (effective layer center C′ = L + (C − L)·p; zoom and rotation apply
|
|
168
|
+
* fully at every factor). Padding is world units.
|
|
169
|
+
* - WITHOUT a presented camera, GameWorld2D's viewport-only path applies:
|
|
170
|
+
* the bounds are `viewport.visibleLogicalBounds` expanded by the padding.
|
|
171
|
+
*
|
|
172
|
+
* Worklet-callable and allocation-free on the steady path: scalars only,
|
|
173
|
+
* results written into the caller-owned `out` scratch object. Returns false
|
|
174
|
+
* when no viewport bounds exist yet.
|
|
175
|
+
*/
|
|
176
|
+
export function writeLayerVisibleBounds(
|
|
177
|
+
camera: SharedCameraRef | null,
|
|
178
|
+
viewport: SharedViewportRef | null,
|
|
179
|
+
parallaxX: number,
|
|
180
|
+
parallaxY: number,
|
|
181
|
+
paddingWorld: number,
|
|
182
|
+
): LayerBounds | null {
|
|
183
|
+
'worklet';
|
|
184
|
+
const view = viewport?.value?.visibleLogicalBounds;
|
|
185
|
+
if (view === undefined) return null;
|
|
186
|
+
const cam = camera?.value?.camera;
|
|
187
|
+
if (cam === undefined) {
|
|
188
|
+
// Viewport-only world: no zoom, no rotation, no parallax correction.
|
|
189
|
+
return {
|
|
190
|
+
minX: view.x - paddingWorld,
|
|
191
|
+
minY: view.y - paddingWorld,
|
|
192
|
+
maxX: view.x + view.width + paddingWorld,
|
|
193
|
+
maxY: view.y + view.height + paddingWorld,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
const hx = view.width / (2 * cam.zoom);
|
|
197
|
+
const hy = view.height / (2 * cam.zoom);
|
|
198
|
+
const extent = rotatedHalfExtents2D(hx, hy, cam.rotationRadians);
|
|
199
|
+
const ex = extent.x + paddingWorld;
|
|
200
|
+
const ey = extent.y + paddingWorld;
|
|
201
|
+
// Parallax AFTER base bounds: shift the center contribution only.
|
|
202
|
+
let centerX = cam.center.x;
|
|
203
|
+
let centerY = cam.center.y;
|
|
204
|
+
if (parallaxX !== 1 || parallaxY !== 1) {
|
|
205
|
+
const logicalCx = view.x + view.width / 2;
|
|
206
|
+
const logicalCy = view.y + view.height / 2;
|
|
207
|
+
centerX = logicalCx + (centerX - logicalCx) * parallaxX;
|
|
208
|
+
centerY = logicalCy + (centerY - logicalCy) * parallaxY;
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
minX: centerX - ex,
|
|
212
|
+
minY: centerY - ey,
|
|
213
|
+
maxX: centerX + ex,
|
|
214
|
+
maxY: centerY + ey,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** Slot-buffer contract shared by the component and tests. */
|
|
219
|
+
export interface TileSlotBuffers {
|
|
220
|
+
readonly rects: readonly (SlotRect | undefined)[];
|
|
221
|
+
readonly xforms: readonly (SlotXform | undefined)[];
|
|
222
|
+
}
|
|
223
|
+
export interface SlotRect {
|
|
224
|
+
setXYWH(x: number, y: number, w: number, h: number): void;
|
|
225
|
+
}
|
|
226
|
+
export interface SlotXform {
|
|
227
|
+
set(scos: number, ssin: number, tx: number, ty: number): void;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface FillParams {
|
|
231
|
+
readonly cw: number;
|
|
232
|
+
readonly ch: number;
|
|
233
|
+
readonly originX: number;
|
|
234
|
+
readonly originY: number;
|
|
235
|
+
readonly layerWidth: number;
|
|
236
|
+
readonly layerHeight: number;
|
|
237
|
+
readonly capacity: number;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Fill Atlas slot buffers from the transferred window for the currently
|
|
242
|
+
* visible cell span (worklet-callable, T16-F3/F4).
|
|
243
|
+
*
|
|
244
|
+
* - Cell range derives from `bounds` (already camera+parallax+padding).
|
|
245
|
+
* - Tiles place UNROTATED at their CELL TOP-LEFT: the RSXform translation
|
|
246
|
+
* is the cell's world top-left corner.
|
|
247
|
+
* - Stale slots past the filled count are hidden atomically (zero-size).
|
|
248
|
+
* - Returns the filled slot count on success; returns -1 when the window
|
|
249
|
+
* does not cover the visible span (caller should request a new window)
|
|
250
|
+
* and -2 when the visible span exceeds the fixed capacity (caller must
|
|
251
|
+
* hide the whole layer and never claim partial success) — T16-SF2.
|
|
252
|
+
*/
|
|
253
|
+
export function fillTileSlots(
|
|
254
|
+
snap: TileWindowSnapshot,
|
|
255
|
+
bounds: LayerBounds,
|
|
256
|
+
rects: readonly (SlotRect | undefined)[],
|
|
257
|
+
xforms: readonly (SlotXform | undefined)[],
|
|
258
|
+
params: FillParams,
|
|
259
|
+
): number {
|
|
260
|
+
'worklet';
|
|
261
|
+
const { cw, ch, originX, originY, layerWidth, layerHeight, capacity } = params;
|
|
262
|
+
let cx0 = Math.floor((bounds.minX - originX) / cw);
|
|
263
|
+
let cy0 = Math.floor((bounds.minY - originY) / ch);
|
|
264
|
+
let cx1 = Math.floor((bounds.maxX - originX) / cw);
|
|
265
|
+
let cy1 = Math.floor((bounds.maxY - originY) / ch);
|
|
266
|
+
cx0 = Math.max(0, cx0);
|
|
267
|
+
cy0 = Math.max(0, cy0);
|
|
268
|
+
cx1 = Math.min(layerWidth - 1, cx1);
|
|
269
|
+
cy1 = Math.min(layerHeight - 1, cy1);
|
|
270
|
+
if (cx0 > cx1 || cy0 > cy1) {
|
|
271
|
+
hideRange(rects, 0, capacity);
|
|
272
|
+
return 0;
|
|
273
|
+
}
|
|
274
|
+
// Preflight the span against capacity so a rotated AABB never produces a
|
|
275
|
+
// partial visible region (T16-SF2). Every cell in the span could be
|
|
276
|
+
// occupied, so compare the worst-case span size to the fixed buffer.
|
|
277
|
+
const spanCells = (cx1 - cx0 + 1) * (cy1 - cy0 + 1);
|
|
278
|
+
if (spanCells > capacity) {
|
|
279
|
+
hideRange(rects, 0, capacity);
|
|
280
|
+
return -2;
|
|
281
|
+
}
|
|
282
|
+
if (!windowCovers(snap, cx0, cy0, cx1, cy1)) {
|
|
283
|
+
return -1;
|
|
284
|
+
}
|
|
285
|
+
let slot = 0;
|
|
286
|
+
for (let cy = cy0; cy <= cy1; cy++) {
|
|
287
|
+
for (let cx = cx0; cx <= cx1; cx++) {
|
|
288
|
+
const id = snap.ids[(cy - snap.y0) * snap.w + (cx - snap.x0)]!;
|
|
289
|
+
if (id === 0) continue;
|
|
290
|
+
if (slot >= capacity) {
|
|
291
|
+
hideRange(rects, 0, capacity);
|
|
292
|
+
return -2;
|
|
293
|
+
}
|
|
294
|
+
const rectSlot = rects[slot];
|
|
295
|
+
const xformSlot = xforms[slot];
|
|
296
|
+
if (rectSlot === undefined || xformSlot === undefined) continue;
|
|
297
|
+
rectSlot.setXYWH(
|
|
298
|
+
snap.frameFlat[id * 4]!,
|
|
299
|
+
snap.frameFlat[id * 4 + 1]!,
|
|
300
|
+
snap.frameFlat[id * 4 + 2]!,
|
|
301
|
+
snap.frameFlat[id * 4 + 3]!,
|
|
302
|
+
);
|
|
303
|
+
// Unrotated placement at the cell's world TOP-LEFT corner.
|
|
304
|
+
xformSlot.set(1, 0, originX + cx * cw, originY + cy * ch);
|
|
305
|
+
slot++;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
// Hide remaining stale slots atomically.
|
|
309
|
+
for (let i = slot; i < capacity; i++) {
|
|
310
|
+
rects[i]?.setXYWH(0, 0, 0, 0);
|
|
311
|
+
}
|
|
312
|
+
return slot;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function hideRange(rects: readonly (SlotRect | undefined)[], from: number, to: number): void {
|
|
316
|
+
'worklet';
|
|
317
|
+
for (let i = from; i < to; i++) {
|
|
318
|
+
rects[i]?.setXYWH(0, 0, 0, 0);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** Stable per-binding generation from object identity (GS-TILE-01). */
|
|
323
|
+
const bindingGenerations = new WeakMap<object, number>();
|
|
324
|
+
let nextBindingGeneration = 1;
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Mint (or recall) the generation for one binding identity object. The
|
|
328
|
+
* component creates a fresh identity per binding-affecting prop change, so
|
|
329
|
+
* each binding gets a distinct generation with no counters in React state.
|
|
330
|
+
*/
|
|
331
|
+
export function bindingGeneration(binding: object): number {
|
|
332
|
+
let gen = bindingGenerations.get(binding);
|
|
333
|
+
if (gen === undefined) {
|
|
334
|
+
gen = nextBindingGeneration;
|
|
335
|
+
nextBindingGeneration += 1;
|
|
336
|
+
bindingGenerations.set(binding, gen);
|
|
337
|
+
}
|
|
338
|
+
return gen;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/** Shared-value mirrors kept structural so headless fakes can drive updates. */
|
|
342
|
+
export interface TileWindowShared {
|
|
343
|
+
value: TileWindowSnapshot;
|
|
344
|
+
}
|
|
345
|
+
export interface TileNumberShared {
|
|
346
|
+
value: number;
|
|
347
|
+
}
|
|
348
|
+
export interface TileBooleanShared {
|
|
349
|
+
value: boolean;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Inputs for one tile-layer UI update (GS-TILE-01).
|
|
354
|
+
*
|
|
355
|
+
* Everything the update may touch is listed here: scalars, shared values,
|
|
356
|
+
* buffers, and callbacks. Map, layer, and frame-table objects are
|
|
357
|
+
* deliberately absent — the UI closure provably cannot capture layer data
|
|
358
|
+
* because it is never passed (scalar layer dims travel in `layerWidth` /
|
|
359
|
+
* `layerHeight`). The binding `generation` gates every window and request.
|
|
360
|
+
*/
|
|
361
|
+
export interface TileLayerUIParams {
|
|
362
|
+
readonly camera: SharedCameraRef | null;
|
|
363
|
+
readonly viewport: SharedViewportRef | null;
|
|
364
|
+
readonly window: TileWindowShared;
|
|
365
|
+
/** Generation of the in-flight request, or -1 when none is pending. */
|
|
366
|
+
readonly pendingGen: TileNumberShared;
|
|
367
|
+
readonly warnedCapacity: TileBooleanShared;
|
|
368
|
+
readonly capacityWarnPending: TileBooleanShared;
|
|
369
|
+
readonly rects: { value: readonly (SlotRect | undefined)[] };
|
|
370
|
+
readonly xforms: { value: readonly (SlotXform | undefined)[] };
|
|
371
|
+
/**
|
|
372
|
+
* Publish a window for `gen` (JS side). Stale deliveries whose `gen`
|
|
373
|
+
* predates the publisher's binding are rejected before publishing; the
|
|
374
|
+
* update additionally refuses to display any window whose stamp differs
|
|
375
|
+
* from the live generation.
|
|
376
|
+
*/
|
|
377
|
+
readonly requestWindow: (gen: number, x0: number, y0: number, x1: number, y1: number) => void;
|
|
378
|
+
/** Bridge crossing to the JS side (scheduleOnRN in production). */
|
|
379
|
+
readonly scheduleOnRN: (fn: () => void) => void;
|
|
380
|
+
readonly onBeyondCapacity: () => void;
|
|
381
|
+
readonly generation: number;
|
|
382
|
+
readonly capacity: number;
|
|
383
|
+
readonly originX: number;
|
|
384
|
+
readonly originY: number;
|
|
385
|
+
readonly cw: number;
|
|
386
|
+
readonly ch: number;
|
|
387
|
+
readonly layerWidth: number;
|
|
388
|
+
readonly layerHeight: number;
|
|
389
|
+
readonly padWorld: number;
|
|
390
|
+
readonly px: number;
|
|
391
|
+
readonly py: number;
|
|
392
|
+
readonly minZoom: number;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* One tile-layer UI update: the body of the layer's derived value,
|
|
397
|
+
* extracted so binding identity, stale-request rejection, and capacity
|
|
398
|
+
* policy execute identically in tests and on the UI runtime (GS-TILE-01).
|
|
399
|
+
*
|
|
400
|
+
* Returns the filled slot count; -1 when a window was requested, -2 when
|
|
401
|
+
* the span exceeds capacity or zoom left the declared bounds, 0 when
|
|
402
|
+
* nothing is visible. A window whose generation stamp differs from the
|
|
403
|
+
* live binding is treated exactly like a missing window.
|
|
404
|
+
*/
|
|
405
|
+
export function updateTileLayerUI(params: TileLayerUIParams): number {
|
|
406
|
+
'worklet';
|
|
407
|
+
const {
|
|
408
|
+
camera,
|
|
409
|
+
viewport,
|
|
410
|
+
window,
|
|
411
|
+
pendingGen,
|
|
412
|
+
warnedCapacity,
|
|
413
|
+
capacityWarnPending,
|
|
414
|
+
rects,
|
|
415
|
+
xforms,
|
|
416
|
+
requestWindow,
|
|
417
|
+
scheduleOnRN,
|
|
418
|
+
onBeyondCapacity,
|
|
419
|
+
generation,
|
|
420
|
+
capacity,
|
|
421
|
+
originX,
|
|
422
|
+
originY,
|
|
423
|
+
cw,
|
|
424
|
+
ch,
|
|
425
|
+
layerWidth,
|
|
426
|
+
layerHeight,
|
|
427
|
+
padWorld,
|
|
428
|
+
px,
|
|
429
|
+
py,
|
|
430
|
+
minZoom,
|
|
431
|
+
} = params;
|
|
432
|
+
// Rejected camera state: zoomed out beyond the declared capacity.
|
|
433
|
+
const camZoom = camera?.value?.camera?.zoom;
|
|
434
|
+
if (camZoom !== undefined && camZoom < minZoom * (1 - 1e-3)) {
|
|
435
|
+
for (let i = 0; i < capacity; i++) {
|
|
436
|
+
rects.value[i]?.setXYWH(0, 0, 0, 0);
|
|
437
|
+
}
|
|
438
|
+
if (!warnedCapacity.value && !capacityWarnPending.value) {
|
|
439
|
+
capacityWarnPending.value = true;
|
|
440
|
+
scheduleOnRN(onBeyondCapacity);
|
|
441
|
+
}
|
|
442
|
+
return -2;
|
|
443
|
+
}
|
|
444
|
+
const bounds = writeLayerVisibleBounds(camera, viewport, px, py, padWorld);
|
|
445
|
+
if (bounds === null) {
|
|
446
|
+
return 0;
|
|
447
|
+
}
|
|
448
|
+
const cx0 = Math.max(0, Math.floor((bounds.minX - originX) / cw));
|
|
449
|
+
const cy0 = Math.max(0, Math.floor((bounds.minY - originY) / ch));
|
|
450
|
+
const cx1 = Math.min(layerWidth - 1, Math.floor((bounds.maxX - originX) / cw));
|
|
451
|
+
const cy1 = Math.min(layerHeight - 1, Math.floor((bounds.maxY - originY) / ch));
|
|
452
|
+
if (cx0 > cx1 || cy0 > cy1) {
|
|
453
|
+
// Off-map view: hide everything.
|
|
454
|
+
for (let i = 0; i < capacity; i++) {
|
|
455
|
+
rects.value[i]?.setXYWH(0, 0, 0, 0);
|
|
456
|
+
}
|
|
457
|
+
return 0;
|
|
458
|
+
}
|
|
459
|
+
const snap = window.value;
|
|
460
|
+
// GS-TILE-01: the generation stamp decides before coordinates do. A stale
|
|
461
|
+
// window (same-size replacement, remount, late delivery) takes the
|
|
462
|
+
// request path exactly like a missing window.
|
|
463
|
+
if (snap.gen !== generation) {
|
|
464
|
+
if (pendingGen.value !== generation) {
|
|
465
|
+
pendingGen.value = generation;
|
|
466
|
+
scheduleOnRN(() => requestWindow(generation, cx0, cy0, cx1, cy1));
|
|
467
|
+
}
|
|
468
|
+
return -1;
|
|
469
|
+
}
|
|
470
|
+
const filled = fillTileSlots(
|
|
471
|
+
snap,
|
|
472
|
+
bounds,
|
|
473
|
+
rects.value,
|
|
474
|
+
xforms.value,
|
|
475
|
+
{ cw, ch, originX, originY, layerWidth, layerHeight, capacity },
|
|
476
|
+
);
|
|
477
|
+
if (filled === -1 && pendingGen.value !== generation) {
|
|
478
|
+
pendingGen.value = generation;
|
|
479
|
+
scheduleOnRN(() => requestWindow(generation, cx0, cy0, cx1, cy1));
|
|
480
|
+
return -1;
|
|
481
|
+
}
|
|
482
|
+
if (filled === -2) {
|
|
483
|
+
// Capacity insufficient even at a valid zoom (e.g. extreme rotation
|
|
484
|
+
// on a fully occupied span) — hide everything, never partial.
|
|
485
|
+
for (let i = 0; i < capacity; i++) {
|
|
486
|
+
rects.value[i]?.setXYWH(0, 0, 0, 0);
|
|
487
|
+
}
|
|
488
|
+
return -2;
|
|
489
|
+
}
|
|
490
|
+
return filled;
|
|
491
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { createGameSession } from '../core/session/createGameSession';
|
|
3
|
+
import type { GameSession } from '../core/session/types';
|
|
4
|
+
import type { GameDefinition, InputMap, SceneMap } from '../definition/types';
|
|
5
|
+
|
|
6
|
+
type SessionCreator<TScenes extends SceneMap, TInput extends InputMap> = (
|
|
7
|
+
definition: GameDefinition<TScenes, TInput>,
|
|
8
|
+
) => GameSession<TScenes, TInput>;
|
|
9
|
+
|
|
10
|
+
interface OwnedSession<TScenes extends SceneMap, TInput extends InputMap> {
|
|
11
|
+
/** The definition this session was created from, compared by identity. */
|
|
12
|
+
readonly definition: GameDefinition<TScenes, TInput>;
|
|
13
|
+
/** The live session owned by this hook instance. */
|
|
14
|
+
readonly session: GameSession<TScenes, TInput>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Create and own a `GameSession` for a `GameDefinition`, with React
|
|
19
|
+
* ownership.
|
|
20
|
+
*
|
|
21
|
+
* The hook creates an idle session during the commit phase, publishes it,
|
|
22
|
+
* and disposes it exactly once when it is replaced or the owner unmounts.
|
|
23
|
+
* React Strict Mode's development setup/cleanup rehearsal is safe: every
|
|
24
|
+
* rehearsal session is disposed exactly once and a disposed session is never
|
|
25
|
+
* published.
|
|
26
|
+
*
|
|
27
|
+
* Ownership rules:
|
|
28
|
+
*
|
|
29
|
+
* - The return value is `undefined` until React commits a live session for
|
|
30
|
+
* the current definition: the initial render, and the boundary while a
|
|
31
|
+
* definition replacement is being created. Render a deliberate fallback
|
|
32
|
+
* instead of hiding it.
|
|
33
|
+
* - The same definition object returns the same session across re-renders.
|
|
34
|
+
* A different definition object unpublishes the old session, disposes it,
|
|
35
|
+
* and publishes a fresh one. Disposed sessions are never revived, so
|
|
36
|
+
* declaring definitions at module scope keeps identity stable.
|
|
37
|
+
* - The hook owns terminal disposal. Do not call `session.dispose()` on a
|
|
38
|
+
* hook-owned session.
|
|
39
|
+
* - The hook does not start the session. Pass it to `GameView`, which binds,
|
|
40
|
+
* starts, pauses on unmount/backgrounding, and never terminally disposes a
|
|
41
|
+
* borrowed session.
|
|
42
|
+
* - For an asset-backed game, mount the component that calls this hook only
|
|
43
|
+
* after `useGameAssets()` reports `ready`; this hook does not load assets.
|
|
44
|
+
*
|
|
45
|
+
* Use `createGameSession()` with explicit `try/finally` disposal for headless
|
|
46
|
+
* tests, non-React programs, and custom surface controllers that need to own
|
|
47
|
+
* sessions imperatively.
|
|
48
|
+
*/
|
|
49
|
+
export function useGameSession<TScenes extends SceneMap, TInput extends InputMap>(
|
|
50
|
+
definition: GameDefinition<TScenes, TInput>,
|
|
51
|
+
): GameSession<TScenes, TInput> | undefined {
|
|
52
|
+
return useOwnedGameSession(definition, createGameSession);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @internal
|
|
57
|
+
*
|
|
58
|
+
* The injectable-creator seam behind `useGameSession`, exported from this
|
|
59
|
+
* module only (never from the `rn-gamekit/react` barrel). Tests supply a
|
|
60
|
+
* deterministic creator (for example `createGameSessionWithDriver` with a
|
|
61
|
+
* `ManualFrameDriver`, since node has no `requestAnimationFrame`) and must
|
|
62
|
+
* pass a stable factory identity across renders.
|
|
63
|
+
*/
|
|
64
|
+
export function useOwnedGameSession<TScenes extends SceneMap, TInput extends InputMap>(
|
|
65
|
+
definition: GameDefinition<TScenes, TInput>,
|
|
66
|
+
create: SessionCreator<TScenes, TInput>,
|
|
67
|
+
): GameSession<TScenes, TInput> | undefined {
|
|
68
|
+
const [owned, setOwned] = useState<OwnedSession<TScenes, TInput> | undefined>(undefined);
|
|
69
|
+
|
|
70
|
+
// Render-phase selector: publish a session only while its definition is
|
|
71
|
+
// the current prop and its status is not disposed. A replacement render
|
|
72
|
+
// therefore unpublishes the old session before any effect runs, and
|
|
73
|
+
// `undefined` is the only other value.
|
|
74
|
+
const session =
|
|
75
|
+
owned !== undefined &&
|
|
76
|
+
owned.definition === definition &&
|
|
77
|
+
owned.session.status !== 'disposed'
|
|
78
|
+
? owned.session
|
|
79
|
+
: undefined;
|
|
80
|
+
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
const next = create(definition);
|
|
83
|
+
setOwned({ definition, session: next });
|
|
84
|
+
return () => {
|
|
85
|
+
next.dispose();
|
|
86
|
+
};
|
|
87
|
+
}, [definition, create]);
|
|
88
|
+
|
|
89
|
+
return session;
|
|
90
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useCallback, useSyncExternalStore } from 'react';
|
|
2
|
+
import type { GameSession, GameSessionStatus } from '../core/session/types';
|
|
3
|
+
import type { InputMap, SceneMap } from '../definition/types';
|
|
4
|
+
|
|
5
|
+
/** Stable no-op cleanup for the absent/disposed session branch. */
|
|
6
|
+
const unsubscribeNothing = (): void => {};
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Observe a session's lifecycle status from React.
|
|
10
|
+
*
|
|
11
|
+
* Returns the current `session.status` on the render that observes a
|
|
12
|
+
* session, and re-renders once per actual lifecycle transition. `undefined`
|
|
13
|
+
* means no session is currently available — the same meaning Task 9's
|
|
14
|
+
* `useGameSession()` gives its pre-commit value, so both hooks compose
|
|
15
|
+
* unconditionally:
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* const session = useGameSession(game);
|
|
19
|
+
* const status = useGameSessionStatus(session);
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* The hook subscribes through `addStatusListener` and never polls; it owns
|
|
23
|
+
* no session and never disposes one. Replacing the session argument detaches
|
|
24
|
+
* the old subscription before the replacement's status is reported, and
|
|
25
|
+
* idempotent lifecycle commands do not cause redundant re-renders.
|
|
26
|
+
*/
|
|
27
|
+
export function useGameSessionStatus<
|
|
28
|
+
TScenes extends SceneMap,
|
|
29
|
+
TInput extends InputMap,
|
|
30
|
+
>(session: GameSession<TScenes, TInput> | undefined): GameSessionStatus | undefined {
|
|
31
|
+
// The callbacks are memoized on the session identity only, so unrelated
|
|
32
|
+
// parent renders never tear down and recreate the subscription; a session
|
|
33
|
+
// prop change produces new identities and React detaches the old session
|
|
34
|
+
// before attaching the replacement.
|
|
35
|
+
const subscribe = useCallback(
|
|
36
|
+
(onStoreChange: () => void) => {
|
|
37
|
+
// Never subscribe to a disposed session: its terminal notification is
|
|
38
|
+
// already delivered, and addStatusListener follows the disposed-error
|
|
39
|
+
// policy for new subscribers.
|
|
40
|
+
if (session === undefined || session.status === 'disposed') {
|
|
41
|
+
return unsubscribeNothing;
|
|
42
|
+
}
|
|
43
|
+
const subscription = session.addStatusListener(onStoreChange);
|
|
44
|
+
return () => {
|
|
45
|
+
subscription.remove();
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
[session],
|
|
49
|
+
);
|
|
50
|
+
const getSnapshot = useCallback(() => session?.status, [session]);
|
|
51
|
+
|
|
52
|
+
return useSyncExternalStore(subscribe, getSnapshot);
|
|
53
|
+
}
|
|
@@ -76,7 +76,11 @@ export class ViewportBinding {
|
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
/**
|
|
79
|
+
/**
|
|
80
|
+
* Release current subscribers (GS-VIEWPORT-01). This is not a lifecycle
|
|
81
|
+
* gate: late subscriptions still register and setSurfaceSize still
|
|
82
|
+
* resolves. Discard the binding after disposal instead of reusing it.
|
|
83
|
+
*/
|
|
80
84
|
dispose(): void {
|
|
81
85
|
this.#listeners.clear();
|
|
82
86
|
}
|
package/src/react.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
export { GameView } from './react/GameView';
|
|
2
|
+
export { useGameSession } from './react/useGameSession';
|
|
3
|
+
export { useGameSessionStatus } from './react/useGameSessionStatus';
|
|
4
|
+
export { createGameLifecycleSource, GameLifecycleProvider, useGameLifecycleSource } from './react/lifecycleSource';
|
|
5
|
+
export type { GameLifecycleSource } from './core/session/types';
|
|
2
6
|
export { createGameAssetStore } from './react/assets/decodeSkiaImage';
|
|
3
7
|
export { useGameAssets, stableGroupsKey } from './react/assets/useGameAssets';
|
|
4
8
|
export type { GameAssetsState } from './react/assets/useGameAssets';
|
|
5
|
-
export { GameWorld2D, viewportTransform } from './react/sprites/GameWorld2D';
|
|
9
|
+
export { GameWorld2D, viewportTransform, cameraViewportTransform2D, layerParallaxTransform2D } from './react/sprites/GameWorld2D';
|
|
10
|
+
export { GameLayer2D } from './react/camera2d/GameLayer2D';
|
|
11
|
+
export { defineGameCamera2D } from './react/camera2d/defineGameCamera2D';
|
|
12
|
+
export type { GameCamera2DDefinition } from './react/camera2d/defineGameCamera2D';
|
|
6
13
|
export { Sprite, resolveSpriteFrameRect } from './react/sprites/Sprite';
|
|
7
14
|
export type { SpriteAnimatable, SpriteAnimatableBoolean, SpriteProps } from './react/sprites/Sprite';
|
|
8
15
|
export { GameSprite, spriteFrameNameForClip } from './react/sprites/GameSprite';
|
|
@@ -34,4 +41,14 @@ export type {
|
|
|
34
41
|
export type { GameRendererProps, GameViewProps } from './react/GameView';
|
|
35
42
|
export { GamePointerInput } from './react/GamePointerInput';
|
|
36
43
|
export type { GamePointerInputProps } from './react/GamePointerInput';
|
|
44
|
+
export { GameButtonPad, GameButton } from './react/GameButtonPad';
|
|
45
|
+
export type { GameButtonPadProps, GameButtonProps, ButtonActionName } from './react/GameButtonPad';
|
|
37
46
|
export type { GamePointerInstrumentation, GameViewInstrumentation } from './react/instrumentation';
|
|
47
|
+
export { ParticleView } from './react/particles/ParticleView';
|
|
48
|
+
export type { ParticleViewProps } from './react/particles/ParticleView';
|
|
49
|
+
export { useParticlePresentation } from './react/particles/useParticlePresentation';
|
|
50
|
+
export type { ParticlePresentation } from './react/particles/useParticlePresentation';
|
|
51
|
+
export { particleSpriteXform, assertUniformParticleSpriteRatio } from './react/particles/spriteXForm';
|
|
52
|
+
export { cameraVisibleWorldBounds, visibleInBounds, PARTICLE_CULL_PADDING } from './react/particles/culling';
|
|
53
|
+
export { TileMapLayer2D } from './react/tilemap/TileMapLayer2D';
|
|
54
|
+
export type { TileMapLayer2DProps } from './react/tilemap/TileMapLayer2D';
|