@nayan-ui/games 1.20.0 → 1.21.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/lib/module/games/arrows/Arrows.js +1 -1
- package/lib/module/games/arrows/ArrowsScene.js +1 -1
- package/lib/module/games/balloon-blaster/BalloonBlaster.js +1 -1
- package/lib/module/games/balloon-blaster/BalloonBlasterScene.js +1 -1
- package/lib/module/games/bike-racing/BikeMeshes.js +1 -1
- package/lib/module/games/bike-racing/BikeRacing.js +1 -1
- package/lib/module/games/bike-racing/BikeRacingConstants.js +1 -1
- package/lib/module/games/bike-racing/BikeRacingScene.js +1 -1
- package/lib/module/games/block-blast/BlockBlast.js +1 -1
- package/lib/module/games/block-blast/BlockBlastScene.js +1 -1
- package/lib/module/games/block-breaker/BlockBreaker.js +1 -1
- package/lib/module/games/block-breaker/BlockBreakerScene.js +1 -1
- package/lib/module/games/bluk/Bluk.js +1 -1
- package/lib/module/games/bluk/BlukScene.js +1 -1
- package/lib/module/games/bubble-shooter/BubbleShooter.js +1 -1
- package/lib/module/games/bubble-shooter/BubbleShooterScene.js +1 -1
- package/lib/module/games/candy-crush/CandyCrush.js +1 -1
- package/lib/module/games/candy-crush/CandyCrushScene.js +1 -1
- package/lib/module/games/car-racing/CarMeshes.js +1 -1
- package/lib/module/games/car-racing/CarRacing.js +1 -1
- package/lib/module/games/car-racing/CarRacingScene.js +1 -1
- package/lib/module/games/chameleon-run/ChameleonRun.js +1 -1
- package/lib/module/games/chameleon-run/ChameleonRunBackdrop.js +1 -1
- package/lib/module/games/chameleon-run/ChameleonRunMeshes.js +1 -1
- package/lib/module/games/checkers/Checkers.js +1 -1
- package/lib/module/games/checkers/CheckersScene.js +1 -1
- package/lib/module/games/color-switch/ColorSwitch.js +1 -1
- package/lib/module/games/color-switch/ColorSwitchScene.js +1 -1
- package/lib/module/games/colors-sort/ColorsSort.js +1 -1
- package/lib/module/games/colors-sort/ColorsSortScene.js +1 -1
- package/lib/module/games/connect-em-all/ConnectEmAll.js +1 -1
- package/lib/module/games/connect-em-all/ConnectEmAllScene.js +1 -1
- package/lib/module/games/crossy-road/CrossyRoad.js +1 -1
- package/lib/module/games/crossy-road/CrossyRoadMeshes.js +1 -1
- package/lib/module/games/crossy-road/CrossyRoadPerson.js +1 -1
- package/lib/module/games/dino-jump/DinoJump.js +1 -1
- package/lib/module/games/dino-jump/DinoJumpScene.js +1 -1
- package/lib/module/games/dots-and-boxes/DotsAndBoxes.js +1 -1
- package/lib/module/games/dots-and-boxes/DotsAndBoxesScene.js +1 -1
- package/lib/module/games/falling-sticks/FallingSticks.js +1 -1
- package/lib/module/games/falling-sticks/FallingSticksScene.js +1 -1
- package/lib/module/games/find-different-number/FindDifferentNumber.js +1 -1
- package/lib/module/games/find-different-number/FindDifferentNumberScene.js +1 -1
- package/lib/module/games/flappy-bird/FlappyBird.js +1 -1
- package/lib/module/games/flappy-bird/FlappyBirdScene.js +1 -1
- package/lib/module/games/fruit-merger/FruitMerger.js +1 -1
- package/lib/module/games/fruit-merger/FruitMergerScene.js +1 -1
- package/lib/module/games/fruit-ninja/FruitNinja.js +1 -1
- package/lib/module/games/fruit-ninja/FruitNinjaScene.js +1 -1
- package/lib/module/games/fruit-ninja/FruitNinjaWorld.js +1 -1
- package/lib/module/games/game-2048/Game2048.js +1 -1
- package/lib/module/games/game-2048/Game2048Scene.js +1 -1
- package/lib/module/games/knife-hit/KnifeHit.js +1 -1
- package/lib/module/games/knife-hit/KnifeHitScene.js +1 -1
- package/lib/module/games/ludo-king/LudoKing.js +1 -1
- package/lib/module/games/ludo-king/LudoKingScene.js +1 -1
- package/lib/module/games/maze-runner/MazeRunner.js +1 -1
- package/lib/module/games/maze-runner/MazeRunnerScene.js +1 -1
- package/lib/module/games/memory-match/MemoryMatch.js +1 -1
- package/lib/module/games/memory-match/MemoryMatchScene.js +1 -1
- package/lib/module/games/mine-sweeper/MineSweeper.js +1 -1
- package/lib/module/games/mine-sweeper/MineSweeperScene.js +1 -1
- package/lib/module/games/mob-control/MobControl.js +1 -1
- package/lib/module/games/mob-control/MobControlGame.js +1 -1
- package/lib/module/games/mob-control/MobControlMeshes.js +1 -1
- package/lib/module/games/mob-control/MobControlRenderer.js +1 -1
- package/lib/module/games/mob-control/MobControlRules.js +1 -1
- package/lib/module/games/mob-control/MobControlScene.js +1 -1
- package/lib/module/games/nuts-and-bolts/NutsAndBolts.js +1 -1
- package/lib/module/games/nuts-and-bolts/NutsAndBoltsScene.js +1 -1
- package/lib/module/games/pac-man/PacMan.js +1 -1
- package/lib/module/games/pac-man/PacManGame.js +1 -1
- package/lib/module/games/pac-man/PacManScene.js +1 -1
- package/lib/module/games/paper-io/PaperIo.js +1 -1
- package/lib/module/games/paper-io/PaperIoMeshes.js +1 -1
- package/lib/module/games/paper-io/PaperIoScene.js +1 -1
- package/lib/module/games/penguin-run/PenguinMeshes.js +1 -1
- package/lib/module/games/penguin-run/PenguinRun.js +1 -1
- package/lib/module/games/penguin-run/PenguinRunScene.js +1 -1
- package/lib/module/games/perfect-circle/PerfectCircle.js +1 -1
- package/lib/module/games/perfect-circle/PerfectCircleScene.js +1 -1
- package/lib/module/games/pipe-connect/PipeConnect.js +1 -1
- package/lib/module/games/pipe-connect/PipeConnectScene.js +1 -1
- package/lib/module/games/play-with-tua/PlayWithTua.js +1 -1
- package/lib/module/games/popit-fidget/PopitFidget.js +1 -1
- package/lib/module/games/popit-fidget/PopitFidgetScene.js +1 -1
- package/lib/module/games/reversi/Reversi.js +1 -1
- package/lib/module/games/reversi/ReversiScene.js +1 -1
- package/lib/module/games/search-grid/SearchGrid.js +1 -1
- package/lib/module/games/search-grid/SearchGridScene.js +1 -1
- package/lib/module/games/shared/BackdropCard.js +1 -1
- package/lib/module/games/shared/EngineBackdrop.js +1 -1
- package/lib/module/games/shared/EngineBlasts.js +1 -1
- package/lib/module/games/shared/EngineBlocks.js +1 -1
- package/lib/module/games/shared/EngineDice.js +1 -1
- package/lib/module/games/shared/EngineFruits.js +1 -1
- package/lib/module/games/shared/EngineGameLoader.js +1 -1
- package/lib/module/games/shared/EngineGameScreen.js +1 -1
- package/lib/module/games/shared/EngineGlyphs.js +1 -1
- package/lib/module/games/shared/EngineHud.js +1 -1
- package/lib/module/games/shared/EngineMeadow.js +1 -1
- package/lib/module/games/shared/EngineTouchSurface.js +1 -1
- package/lib/module/games/shared/GameActivity.js +1 -1
- package/lib/module/games/shared/GameLoading.js +1 -1
- package/lib/module/games/shared/GameLoadingTransition.js +1 -1
- package/lib/module/games/sliding-numbers/SlidingNumbers.js +1 -1
- package/lib/module/games/sliding-numbers/SlidingNumbersScene.js +1 -1
- package/lib/module/games/snake-3d/Snake3D.js +1 -1
- package/lib/module/games/snake-3d/Snake3DScene.js +1 -1
- package/lib/module/games/snakes-and-ladders/SnakesAndLadders.js +1 -1
- package/lib/module/games/snakes-and-ladders/SnakesAndLaddersScene.js +1 -1
- package/lib/module/games/space-fighter/SpaceFighter.js +1 -1
- package/lib/module/games/space-fighter/SpaceFighterScene.js +1 -1
- package/lib/module/games/spider-solitaire/SpiderSolitaire.js +1 -1
- package/lib/module/games/spider-solitaire/SpiderSolitaireScene.js +1 -1
- package/lib/module/games/stack-tower/StackTower.js +1 -1
- package/lib/module/games/stack-tower/StackTowerScene.js +1 -1
- package/lib/module/games/sudoku/Sudoku.js +1 -1
- package/lib/module/games/sudoku/SudokuScene.js +1 -1
- package/lib/module/games/tangram/Tangram.js +1 -1
- package/lib/module/games/tangram/TangramScene.js +1 -1
- package/lib/module/games/tank-1990/Tank1990.js +1 -1
- package/lib/module/games/tank-1990/Tank1990Scene.js +1 -1
- package/lib/module/games/tic-tac-toe/TicTacToe.js +1 -1
- package/lib/module/games/tic-tac-toe/TicTacToeScene.js +1 -1
- package/lib/module/games/tile-home/TileHome.js +1 -1
- package/lib/module/games/tile-home/TileHomeScene.js +1 -1
- package/lib/module/games/treasure-hunt/TreasureHunt.js +1 -1
- package/lib/module/games/treasure-hunt/TreasureHuntConstants.js +1 -1
- package/lib/module/games/treasure-hunt/TreasureHuntModel.js +1 -1
- package/lib/module/games/treasure-hunt/TreasureHuntScene.js +1 -1
- package/lib/module/games/whack-a-mole/WhackAMole.js +1 -1
- package/lib/module/games/whack-a-mole/WhackAMoleScene.js +1 -1
- package/lib/module/helpers/GameSettingsModal.js +1 -1
- package/lib/module/helpers/GameTheme.js +1 -1
- package/package.json +1 -2
- package/src/assets/fonts/Inter-SemiBold.ttf +0 -0
- package/src/assets/models/explorer/explorer.glb +0 -0
- package/src/assets/models/explorer/params.json +0 -51
- package/src/assets/models/explorer/source.json +0 -222
- package/src/assets/models/play-with-tua/play-with-tua.glb +0 -0
- package/src/assets/models/play-with-tua/sources.json +0 -141
- package/src/assets/sfx/balloon_pop.wav +0 -0
- package/src/assets/sfx/blocked.wav +0 -0
- package/src/assets/sfx/boing.wav +0 -0
- package/src/assets/sfx/bonus.wav +0 -0
- package/src/assets/sfx/boom.wav +0 -0
- package/src/assets/sfx/bump.wav +0 -0
- package/src/assets/sfx/cannon.wav +0 -0
- package/src/assets/sfx/capture.wav +0 -0
- package/src/assets/sfx/card_flip.wav +0 -0
- package/src/assets/sfx/card_place.wav +0 -0
- package/src/assets/sfx/catch.wav +0 -0
- package/src/assets/sfx/chime.wav +0 -0
- package/src/assets/sfx/chomp.wav +0 -0
- package/src/assets/sfx/chomp_alt.wav +0 -0
- package/src/assets/sfx/clack.wav +0 -0
- package/src/assets/sfx/clang.wav +0 -0
- package/src/assets/sfx/clash.wav +0 -0
- package/src/assets/sfx/click.wav +0 -0
- package/src/assets/sfx/coin.wav +0 -0
- package/src/assets/sfx/combo.wav +0 -0
- package/src/assets/sfx/crash.wav +0 -0
- package/src/assets/sfx/crunch.wav +0 -0
- package/src/assets/sfx/dance.wav +0 -0
- package/src/assets/sfx/deselect.wav +0 -0
- package/src/assets/sfx/dice_roll.wav +0 -0
- package/src/assets/sfx/die.wav +0 -0
- package/src/assets/sfx/draw.wav +0 -0
- package/src/assets/sfx/drop.wav +0 -0
- package/src/assets/sfx/eat.wav +0 -0
- package/src/assets/sfx/engine.wav +0 -0
- package/src/assets/sfx/error.wav +0 -0
- package/src/assets/sfx/flag.wav +0 -0
- package/src/assets/sfx/flap.wav +0 -0
- package/src/assets/sfx/flip_disc.wav +0 -0
- package/src/assets/sfx/footstep_run.wav +0 -0
- package/src/assets/sfx/footstep_walk.wav +0 -0
- package/src/assets/sfx/game_over.wav +0 -0
- package/src/assets/sfx/gate.wav +0 -0
- package/src/assets/sfx/hit.wav +0 -0
- package/src/assets/sfx/hop.wav +0 -0
- package/src/assets/sfx/hurt.wav +0 -0
- package/src/assets/sfx/invalid.wav +0 -0
- package/src/assets/sfx/jump.wav +0 -0
- package/src/assets/sfx/ladder.wav +0 -0
- package/src/assets/sfx/land.wav +0 -0
- package/src/assets/sfx/laugh.wav +0 -0
- package/src/assets/sfx/lose.wav +0 -0
- package/src/assets/sfx/merge.wav +0 -0
- package/src/assets/sfx/miss.wav +0 -0
- package/src/assets/sfx/nitro.wav +0 -0
- package/src/assets/sfx/pew.wav +0 -0
- package/src/assets/sfx/place.wav +0 -0
- package/src/assets/sfx/pling.wav +0 -0
- package/src/assets/sfx/point.wav +0 -0
- package/src/assets/sfx/pop.wav +0 -0
- package/src/assets/sfx/pop_soft.wav +0 -0
- package/src/assets/sfx/power_up.wav +0 -0
- package/src/assets/sfx/reveal.wav +0 -0
- package/src/assets/sfx/robot.wav +0 -0
- package/src/assets/sfx/rotate.wav +0 -0
- package/src/assets/sfx/run_steps.wav +0 -0
- package/src/assets/sfx/select.wav +0 -0
- package/src/assets/sfx/shuffle.wav +0 -0
- package/src/assets/sfx/six.wav +0 -0
- package/src/assets/sfx/slice.wav +0 -0
- package/src/assets/sfx/slide.wav +0 -0
- package/src/assets/sfx/snake.wav +0 -0
- package/src/assets/sfx/snap.wav +0 -0
- package/src/assets/sfx/splash.wav +0 -0
- package/src/assets/sfx/star.wav +0 -0
- package/src/assets/sfx/start.wav +0 -0
- package/src/assets/sfx/swoosh.wav +0 -0
- package/src/assets/sfx/tap.wav +0 -0
- package/src/assets/sfx/thud.wav +0 -0
- package/src/assets/sfx/thunk.wav +0 -0
- package/src/assets/sfx/tick.wav +0 -0
- package/src/assets/sfx/time_up.wav +0 -0
- package/src/assets/sfx/tock.wav +0 -0
- package/src/assets/sfx/walk_steps.wav +0 -0
- package/src/assets/sfx/warning.wav +0 -0
- package/src/assets/sfx/whack.wav +0 -0
- package/src/assets/sfx/whoosh.wav +0 -0
- package/src/assets/sfx/win.wav +0 -0
- package/src/assets/sfx/zap.wav +0 -0
- package/src/assets/textures/ad_bolt.png +0 -0
- package/src/assets/textures/ad_bubbles.png +0 -0
- package/src/assets/textures/ad_chevrons.png +0 -0
- package/src/assets/textures/asphalt.png +0 -0
- package/src/assets/textures/bark.jpg +0 -0
- package/src/assets/textures/explorer-atlas.png +0 -0
- package/src/assets/textures/facade.png +0 -0
- package/src/assets/textures/grass.png +0 -0
- package/src/assets/textures/leaves.png +0 -0
- package/src/assets/textures/limestone.jpg +0 -0
- package/src/assets/textures/meadow.jpg +0 -0
- package/src/assets/textures/nature-sources.json +0 -87
- package/src/assets/textures/pine.png +0 -0
- package/src/assets/textures/river.jpg +0 -0
- package/src/assets/textures/soft_glow.png +0 -0
- package/src/games/arrows/Arrows.tsx +0 -69
- package/src/games/arrows/ArrowsConstants.ts +0 -107
- package/src/games/arrows/ArrowsGame.ts +0 -735
- package/src/games/arrows/ArrowsScene.ts +0 -395
- package/src/games/balloon-blaster/BalloonBlaster.tsx +0 -75
- package/src/games/balloon-blaster/BalloonBlasterConstants.ts +0 -79
- package/src/games/balloon-blaster/BalloonBlasterGame.ts +0 -287
- package/src/games/balloon-blaster/BalloonBlasterPhysics.ts +0 -95
- package/src/games/balloon-blaster/BalloonBlasterScene.ts +0 -225
- package/src/games/bike-racing/BikeMeshes.ts +0 -273
- package/src/games/bike-racing/BikeRacing.tsx +0 -211
- package/src/games/bike-racing/BikeRacingConstants.ts +0 -103
- package/src/games/bike-racing/BikeRacingGame.ts +0 -557
- package/src/games/bike-racing/BikeRacingScene.ts +0 -119
- package/src/games/block-blast/BlockBlast.tsx +0 -73
- package/src/games/block-blast/BlockBlastConstants.ts +0 -179
- package/src/games/block-blast/BlockBlastGame.ts +0 -471
- package/src/games/block-blast/BlockBlastScene.ts +0 -156
- package/src/games/block-breaker/BlockBreaker.tsx +0 -79
- package/src/games/block-breaker/BlockBreakerConstants.ts +0 -139
- package/src/games/block-breaker/BlockBreakerGame.ts +0 -459
- package/src/games/block-breaker/BlockBreakerScene.ts +0 -257
- package/src/games/bluk/Bluk.tsx +0 -82
- package/src/games/bluk/BlukConstants.ts +0 -121
- package/src/games/bluk/BlukGame.ts +0 -323
- package/src/games/bluk/BlukRules.ts +0 -154
- package/src/games/bluk/BlukScene.ts +0 -514
- package/src/games/bubble-shooter/BubbleShooter.tsx +0 -76
- package/src/games/bubble-shooter/BubbleShooterConstants.ts +0 -103
- package/src/games/bubble-shooter/BubbleShooterGame.ts +0 -459
- package/src/games/bubble-shooter/BubbleShooterScene.ts +0 -158
- package/src/games/candy-crush/CandyCrush.tsx +0 -77
- package/src/games/candy-crush/CandyCrushConstants.ts +0 -94
- package/src/games/candy-crush/CandyCrushGame.ts +0 -477
- package/src/games/candy-crush/CandyCrushScene.ts +0 -209
- package/src/games/car-racing/CarMeshes.ts +0 -440
- package/src/games/car-racing/CarRacing.tsx +0 -211
- package/src/games/car-racing/CarRacingConstants.ts +0 -167
- package/src/games/car-racing/CarRacingFacade.ts +0 -40
- package/src/games/car-racing/CarRacingGame.ts +0 -539
- package/src/games/car-racing/CarRacingScene.ts +0 -1026
- package/src/games/car-racing/CarRacingScenery.ts +0 -265
- package/src/games/chameleon-run/ChameleonRun.tsx +0 -96
- package/src/games/chameleon-run/ChameleonRunBackdrop.ts +0 -186
- package/src/games/chameleon-run/ChameleonRunConstants.ts +0 -47
- package/src/games/chameleon-run/ChameleonRunGame.ts +0 -309
- package/src/games/chameleon-run/ChameleonRunMeshes.ts +0 -305
- package/src/games/chameleon-run/ChameleonRunRules.ts +0 -252
- package/src/games/chameleon-run/ChameleonRunScene.ts +0 -310
- package/src/games/checkers/Checkers.tsx +0 -83
- package/src/games/checkers/CheckersAI.ts +0 -255
- package/src/games/checkers/CheckersConstants.ts +0 -68
- package/src/games/checkers/CheckersGame.ts +0 -322
- package/src/games/checkers/CheckersRules.ts +0 -167
- package/src/games/checkers/CheckersScene.ts +0 -308
- package/src/games/color-switch/ColorSwitch.tsx +0 -75
- package/src/games/color-switch/ColorSwitchConstants.ts +0 -61
- package/src/games/color-switch/ColorSwitchGame.ts +0 -329
- package/src/games/color-switch/ColorSwitchScene.ts +0 -220
- package/src/games/colors-sort/ColorsSort.tsx +0 -82
- package/src/games/colors-sort/ColorsSortConstants.ts +0 -119
- package/src/games/colors-sort/ColorsSortGame.ts +0 -246
- package/src/games/colors-sort/ColorsSortScene.ts +0 -315
- package/src/games/connect-em-all/ConnectEmAll.tsx +0 -70
- package/src/games/connect-em-all/ConnectEmAllConstants.ts +0 -77
- package/src/games/connect-em-all/ConnectEmAllGame.ts +0 -401
- package/src/games/connect-em-all/ConnectEmAllScene.ts +0 -235
- package/src/games/crossy-road/CrossyRoad.tsx +0 -74
- package/src/games/crossy-road/CrossyRoadCamera.ts +0 -59
- package/src/games/crossy-road/CrossyRoadConstants.ts +0 -132
- package/src/games/crossy-road/CrossyRoadGame.ts +0 -293
- package/src/games/crossy-road/CrossyRoadMeshes.ts +0 -195
- package/src/games/crossy-road/CrossyRoadPerson.ts +0 -198
- package/src/games/crossy-road/CrossyRoadRules.ts +0 -99
- package/src/games/crossy-road/CrossyRoadScene.ts +0 -355
- package/src/games/dino-jump/DinoJump.tsx +0 -77
- package/src/games/dino-jump/DinoJumpConstants.ts +0 -80
- package/src/games/dino-jump/DinoJumpGame.ts +0 -344
- package/src/games/dino-jump/DinoJumpScene.ts +0 -686
- package/src/games/dots-and-boxes/DotsAndBoxes.tsx +0 -83
- package/src/games/dots-and-boxes/DotsAndBoxesConstants.ts +0 -77
- package/src/games/dots-and-boxes/DotsAndBoxesGame.ts +0 -271
- package/src/games/dots-and-boxes/DotsAndBoxesScene.ts +0 -249
- package/src/games/falling-sticks/FallingSticks.tsx +0 -72
- package/src/games/falling-sticks/FallingSticksConstants.ts +0 -62
- package/src/games/falling-sticks/FallingSticksGame.ts +0 -220
- package/src/games/falling-sticks/FallingSticksRules.ts +0 -145
- package/src/games/falling-sticks/FallingSticksScene.ts +0 -245
- package/src/games/find-different-number/FindDifferentNumber.tsx +0 -74
- package/src/games/find-different-number/FindDifferentNumberConstants.ts +0 -74
- package/src/games/find-different-number/FindDifferentNumberGame.ts +0 -174
- package/src/games/find-different-number/FindDifferentNumberRules.ts +0 -43
- package/src/games/find-different-number/FindDifferentNumberScene.ts +0 -193
- package/src/games/flappy-bird/FlappyBird.tsx +0 -73
- package/src/games/flappy-bird/FlappyBirdConstants.ts +0 -95
- package/src/games/flappy-bird/FlappyBirdGame.ts +0 -375
- package/src/games/flappy-bird/FlappyBirdScene.ts +0 -630
- package/src/games/fruit-merger/FruitMerger.tsx +0 -73
- package/src/games/fruit-merger/FruitMergerConstants.ts +0 -102
- package/src/games/fruit-merger/FruitMergerGame.ts +0 -285
- package/src/games/fruit-merger/FruitMergerRules.ts +0 -286
- package/src/games/fruit-merger/FruitMergerScene.ts +0 -498
- package/src/games/fruit-ninja/FruitNinja.tsx +0 -129
- package/src/games/fruit-ninja/FruitNinjaConstants.ts +0 -107
- package/src/games/fruit-ninja/FruitNinjaGame.ts +0 -391
- package/src/games/fruit-ninja/FruitNinjaScene.ts +0 -319
- package/src/games/fruit-ninja/FruitNinjaWorld.ts +0 -17
- package/src/games/game-2048/Game2048.tsx +0 -84
- package/src/games/game-2048/Game2048Constants.ts +0 -68
- package/src/games/game-2048/Game2048Game.ts +0 -181
- package/src/games/game-2048/Game2048Rules.ts +0 -101
- package/src/games/game-2048/Game2048Scene.ts +0 -206
- package/src/games/knife-hit/KnifeHit.tsx +0 -78
- package/src/games/knife-hit/KnifeHitConstants.ts +0 -89
- package/src/games/knife-hit/KnifeHitGame.ts +0 -264
- package/src/games/knife-hit/KnifeHitScene.ts +0 -360
- package/src/games/ludo-king/LudoKing.tsx +0 -86
- package/src/games/ludo-king/LudoKingConstants.ts +0 -212
- package/src/games/ludo-king/LudoKingGame.ts +0 -326
- package/src/games/ludo-king/LudoKingRules.ts +0 -143
- package/src/games/ludo-king/LudoKingScene.ts +0 -397
- package/src/games/maze-runner/MazeRunner.tsx +0 -88
- package/src/games/maze-runner/MazeRunnerConstants.ts +0 -65
- package/src/games/maze-runner/MazeRunnerGame.ts +0 -176
- package/src/games/maze-runner/MazeRunnerRules.ts +0 -161
- package/src/games/maze-runner/MazeRunnerScene.ts +0 -245
- package/src/games/memory-match/MemoryMatch.tsx +0 -77
- package/src/games/memory-match/MemoryMatchConstants.ts +0 -105
- package/src/games/memory-match/MemoryMatchGame.ts +0 -222
- package/src/games/memory-match/MemoryMatchRules.ts +0 -38
- package/src/games/memory-match/MemoryMatchScene.ts +0 -268
- package/src/games/mine-sweeper/MineSweeper.tsx +0 -77
- package/src/games/mine-sweeper/MineSweeperConstants.ts +0 -94
- package/src/games/mine-sweeper/MineSweeperGame.ts +0 -234
- package/src/games/mine-sweeper/MineSweeperRules.ts +0 -67
- package/src/games/mine-sweeper/MineSweeperScene.ts +0 -262
- package/src/games/mob-control/MobControl.tsx +0 -73
- package/src/games/mob-control/MobControlConstants.ts +0 -106
- package/src/games/mob-control/MobControlGame.ts +0 -176
- package/src/games/mob-control/MobControlMeshes.ts +0 -85
- package/src/games/mob-control/MobControlRenderer.ts +0 -108
- package/src/games/mob-control/MobControlRules.ts +0 -522
- package/src/games/mob-control/MobControlScene.ts +0 -399
- package/src/games/number-search/NumberSearch.tsx +0 -18
- package/src/games/number-search/NumberSearchNumbers.ts +0 -623
- package/src/games/nuts-and-bolts/NutsAndBolts.tsx +0 -85
- package/src/games/nuts-and-bolts/NutsAndBoltsConstants.ts +0 -75
- package/src/games/nuts-and-bolts/NutsAndBoltsGame.ts +0 -298
- package/src/games/nuts-and-bolts/NutsAndBoltsRules.ts +0 -474
- package/src/games/nuts-and-bolts/NutsAndBoltsScene.ts +0 -498
- package/src/games/pac-man/PacMan.tsx +0 -86
- package/src/games/pac-man/PacManConstants.ts +0 -169
- package/src/games/pac-man/PacManGame.ts +0 -406
- package/src/games/pac-man/PacManRules.ts +0 -255
- package/src/games/pac-man/PacManScene.ts +0 -387
- package/src/games/paper-io/PaperIo.tsx +0 -91
- package/src/games/paper-io/PaperIoConstants.ts +0 -86
- package/src/games/paper-io/PaperIoGame.ts +0 -193
- package/src/games/paper-io/PaperIoMeshes.ts +0 -233
- package/src/games/paper-io/PaperIoRules.ts +0 -315
- package/src/games/paper-io/PaperIoScene.ts +0 -310
- package/src/games/penguin-run/PenguinMeshes.ts +0 -269
- package/src/games/penguin-run/PenguinModel.ts +0 -712
- package/src/games/penguin-run/PenguinRun.tsx +0 -77
- package/src/games/penguin-run/PenguinRunConstants.ts +0 -69
- package/src/games/penguin-run/PenguinRunGame.ts +0 -406
- package/src/games/penguin-run/PenguinRunScene.ts +0 -949
- package/src/games/perfect-circle/PerfectCircle.tsx +0 -74
- package/src/games/perfect-circle/PerfectCircleConstants.ts +0 -52
- package/src/games/perfect-circle/PerfectCircleGame.ts +0 -153
- package/src/games/perfect-circle/PerfectCircleRules.ts +0 -111
- package/src/games/perfect-circle/PerfectCircleScene.ts +0 -176
- package/src/games/pipe-connect/PipeConnect.tsx +0 -69
- package/src/games/pipe-connect/PipeConnectConstants.ts +0 -101
- package/src/games/pipe-connect/PipeConnectGame.ts +0 -179
- package/src/games/pipe-connect/PipeConnectRules.ts +0 -326
- package/src/games/pipe-connect/PipeConnectScene.ts +0 -271
- package/src/games/play-with-tua/PlayWithTua.tsx +0 -123
- package/src/games/play-with-tua/PlayWithTuaConstants.ts +0 -70
- package/src/games/play-with-tua/PlayWithTuaGame.ts +0 -167
- package/src/games/play-with-tua/PlayWithTuaModel.ts +0 -42
- package/src/games/play-with-tua/PlayWithTuaScene.ts +0 -36
- package/src/games/popit-fidget/PopitFidget.tsx +0 -72
- package/src/games/popit-fidget/PopitFidgetConstants.ts +0 -71
- package/src/games/popit-fidget/PopitFidgetGame.ts +0 -148
- package/src/games/popit-fidget/PopitFidgetScene.ts +0 -242
- package/src/games/reversi/Reversi.tsx +0 -94
- package/src/games/reversi/ReversiConstants.ts +0 -67
- package/src/games/reversi/ReversiGame.ts +0 -266
- package/src/games/reversi/ReversiRules.ts +0 -176
- package/src/games/reversi/ReversiScene.ts +0 -240
- package/src/games/search-grid/SearchGrid.tsx +0 -92
- package/src/games/search-grid/SearchGridConstants.ts +0 -178
- package/src/games/search-grid/SearchGridGame.ts +0 -209
- package/src/games/search-grid/SearchGridScene.ts +0 -301
- package/src/games/shared/BackdropCard.tsx +0 -54
- package/src/games/shared/EngineBackdrop.ts +0 -300
- package/src/games/shared/EngineBlasts.ts +0 -136
- package/src/games/shared/EngineBlocks.ts +0 -91
- package/src/games/shared/EngineControlText.ts +0 -17
- package/src/games/shared/EngineDice.ts +0 -250
- package/src/games/shared/EngineFootprint.ts +0 -35
- package/src/games/shared/EngineFruits.ts +0 -1435
- package/src/games/shared/EngineGameLoader.tsx +0 -88
- package/src/games/shared/EngineGameScreen.tsx +0 -325
- package/src/games/shared/EngineGameWidth.ts +0 -3
- package/src/games/shared/EngineGameWidth.web.ts +0 -3
- package/src/games/shared/EngineGlyphs.ts +0 -178
- package/src/games/shared/EngineHud.ts +0 -815
- package/src/games/shared/EngineLoading.ts +0 -477
- package/src/games/shared/EngineMeadow.ts +0 -725
- package/src/games/shared/EngineMeshCache.ts +0 -15
- package/src/games/shared/EngineMeshes.ts +0 -10
- package/src/games/shared/EngineRacingChase.ts +0 -21
- package/src/games/shared/EngineRacingHandling.ts +0 -48
- package/src/games/shared/EngineReadyContext.ts +0 -4
- package/src/games/shared/EngineTilt.ts +0 -44
- package/src/games/shared/EngineTouchSurface.tsx +0 -103
- package/src/games/shared/EngineUtils.ts +0 -52
- package/src/games/shared/GameActivity.ts +0 -13
- package/src/games/shared/GameLoading.tsx +0 -202
- package/src/games/shared/GameLoadingTransition.tsx +0 -61
- package/src/games/shared/ProceduralCacheVersion.ts +0 -2
- package/src/games/shared/useEngineGame.ts +0 -240
- package/src/games/shared/useGameResource.ts +0 -21
- package/src/games/shared/useLiveState.ts +0 -58
- package/src/games/sliding-numbers/SlidingNumbers.tsx +0 -71
- package/src/games/sliding-numbers/SlidingNumbersConstants.ts +0 -65
- package/src/games/sliding-numbers/SlidingNumbersGame.ts +0 -192
- package/src/games/sliding-numbers/SlidingNumbersRules.ts +0 -79
- package/src/games/sliding-numbers/SlidingNumbersScene.ts +0 -193
- package/src/games/snake-3d/Snake3D.tsx +0 -76
- package/src/games/snake-3d/Snake3DConstants.ts +0 -61
- package/src/games/snake-3d/Snake3DGame.ts +0 -192
- package/src/games/snake-3d/Snake3DMotion.ts +0 -22
- package/src/games/snake-3d/Snake3DRules.ts +0 -116
- package/src/games/snake-3d/Snake3DScene.ts +0 -322
- package/src/games/snakes-and-ladders/SnakesAndLadders.tsx +0 -87
- package/src/games/snakes-and-ladders/SnakesAndLaddersConstants.ts +0 -136
- package/src/games/snakes-and-ladders/SnakesAndLaddersGame.ts +0 -310
- package/src/games/snakes-and-ladders/SnakesAndLaddersScene.ts +0 -515
- package/src/games/space-fighter/SpaceFighter.tsx +0 -74
- package/src/games/space-fighter/SpaceFighterConstants.ts +0 -86
- package/src/games/space-fighter/SpaceFighterGame.ts +0 -292
- package/src/games/space-fighter/SpaceFighterScene.ts +0 -550
- package/src/games/spider-solitaire/SpiderSolitaire.tsx +0 -80
- package/src/games/spider-solitaire/SpiderSolitaireConstants.ts +0 -107
- package/src/games/spider-solitaire/SpiderSolitaireGame.ts +0 -387
- package/src/games/spider-solitaire/SpiderSolitaireRules.ts +0 -123
- package/src/games/spider-solitaire/SpiderSolitaireScene.ts +0 -352
- package/src/games/stack-tower/StackTower.tsx +0 -76
- package/src/games/stack-tower/StackTowerConstants.ts +0 -74
- package/src/games/stack-tower/StackTowerGame.ts +0 -236
- package/src/games/stack-tower/StackTowerScene.ts +0 -186
- package/src/games/sudoku/Sudoku.tsx +0 -73
- package/src/games/sudoku/SudokuConstants.ts +0 -127
- package/src/games/sudoku/SudokuGame.ts +0 -250
- package/src/games/sudoku/SudokuRules.ts +0 -125
- package/src/games/sudoku/SudokuScene.ts +0 -304
- package/src/games/tangram/Tangram.tsx +0 -79
- package/src/games/tangram/TangramConstants.ts +0 -64
- package/src/games/tangram/TangramGame.ts +0 -356
- package/src/games/tangram/TangramRules.ts +0 -409
- package/src/games/tangram/TangramScene.ts +0 -203
- package/src/games/tank-1990/Tank1990.tsx +0 -78
- package/src/games/tank-1990/Tank1990Constants.ts +0 -81
- package/src/games/tank-1990/Tank1990Game.ts +0 -331
- package/src/games/tank-1990/Tank1990Rules.ts +0 -390
- package/src/games/tank-1990/Tank1990Scene.ts +0 -434
- package/src/games/tic-tac-toe/TicTacToe.tsx +0 -98
- package/src/games/tic-tac-toe/TicTacToeConstants.ts +0 -69
- package/src/games/tic-tac-toe/TicTacToeGame.ts +0 -200
- package/src/games/tic-tac-toe/TicTacToeRules.ts +0 -103
- package/src/games/tic-tac-toe/TicTacToeScene.ts +0 -245
- package/src/games/tile-home/TileHome.tsx +0 -92
- package/src/games/tile-home/TileHomeConstants.ts +0 -139
- package/src/games/tile-home/TileHomeGame.ts +0 -435
- package/src/games/tile-home/TileHomeScene.ts +0 -154
- package/src/games/treasure-hunt/TreasureHunt.tsx +0 -206
- package/src/games/treasure-hunt/TreasureHuntConstants.ts +0 -266
- package/src/games/treasure-hunt/TreasureHuntControls.ts +0 -280
- package/src/games/treasure-hunt/TreasureHuntGame.ts +0 -402
- package/src/games/treasure-hunt/TreasureHuntMeshes.ts +0 -422
- package/src/games/treasure-hunt/TreasureHuntModel.ts +0 -506
- package/src/games/treasure-hunt/TreasureHuntRules.ts +0 -1210
- package/src/games/treasure-hunt/TreasureHuntScene.ts +0 -586
- package/src/games/whack-a-mole/WhackAMole.tsx +0 -79
- package/src/games/whack-a-mole/WhackAMoleConstants.ts +0 -94
- package/src/games/whack-a-mole/WhackAMoleGame.ts +0 -233
- package/src/games/whack-a-mole/WhackAMoleScene.ts +0 -349
- package/src/games/word-search/WordSearch.tsx +0 -18
- package/src/games/word-search/WordSearchWords.ts +0 -1642
- package/src/helpers/GamePatternData.ts +0 -120
- package/src/helpers/GameSettingsModal.tsx +0 -384
- package/src/helpers/GameTheme.tsx +0 -37
- package/src/helpers/IconPaths.ts +0 -6
- package/src/helpers/index.ts +0 -2
- package/src/index.tsx +0 -60
- package/src/services/GameAssetLoader.ts +0 -111
- package/src/services/GameAssets.ts +0 -149
- package/src/services/GameLoaders.ts +0 -93
- package/src/services/GamesConstants.ts +0 -193
- package/src/services/GamesMetadata.ts +0 -711
- package/src/services/GamesService.ts +0 -116
- package/src/services/HapticsService.ts +0 -48
- package/src/services/ScoringService.ts +0 -19
- package/src/services/SfxSources.ts +0 -81
- package/src/services/SoundsService.ts +0 -582
- package/src/services/ThemeService.ts +0 -281
- package/src/services/UtilsService.ts +0 -134
- package/src/services/index.ts +0 -6
|
@@ -1,515 +0,0 @@
|
|
|
1
|
-
// Everything Snakes and Ladders draws. An orthographic camera leaning back from straight down over a
|
|
2
|
-
// wooden board; the board lies in the world's XY plane (x right, y up the board, z up off it), centred
|
|
3
|
-
// on the origin, one board unit (the playing area's width) to `layout.size` world units (view points).
|
|
4
|
-
// The board, its cells, frame, snakes, ladders and the start pad are one static mesh; the cell numbers
|
|
5
|
-
// are ten digit meshes shared by every cell (one instanced draw each); the pawns, the die and their
|
|
6
|
-
// shadows are entities of their own. Every mesh is built once: mesh ids are app-wide and limited.
|
|
7
|
-
import {
|
|
8
|
-
type Camera,
|
|
9
|
-
type Color,
|
|
10
|
-
effects,
|
|
11
|
-
type Entity,
|
|
12
|
-
extrude,
|
|
13
|
-
type GeometryPart,
|
|
14
|
-
lathe,
|
|
15
|
-
merge,
|
|
16
|
-
type Model,
|
|
17
|
-
Path,
|
|
18
|
-
type Quat,
|
|
19
|
-
quat,
|
|
20
|
-
shapeGeometry,
|
|
21
|
-
tube,
|
|
22
|
-
type Vec3,
|
|
23
|
-
type World
|
|
24
|
-
} from '@nayan-ui/engine';
|
|
25
|
-
import type { GameTheme } from '../../services/ThemeService';
|
|
26
|
-
import { setBackdropTheme, spawnBackdrop } from '../shared/EngineBackdrop';
|
|
27
|
-
import { dieMesh, dieRotation as sharedDieRotation, rollDie as rollSharedDie } from '../shared/EngineDice';
|
|
28
|
-
import { flatGlyphMesh, GLYPH_ADVANCE, GLYPH_WIDTH } from '../shared/EngineGlyphs';
|
|
29
|
-
import { noise } from '../shared/EngineMeadow';
|
|
30
|
-
import { cacheGameAsset, createGameMesh as createShape } from '../shared/EngineMeshes';
|
|
31
|
-
import { aimTilted, placeTiltedBackdrop, type TiltView } from '../shared/EngineTilt';
|
|
32
|
-
import { toColor } from '../shared/EngineUtils';
|
|
33
|
-
import {
|
|
34
|
-
AI_COLOR,
|
|
35
|
-
BOARD_SIZE,
|
|
36
|
-
CELL_PALETTE,
|
|
37
|
-
cellCenter,
|
|
38
|
-
DIE_SIZE,
|
|
39
|
-
DIE_Y,
|
|
40
|
-
FINISH_CELL,
|
|
41
|
-
LADDER_AT,
|
|
42
|
-
type LadderData,
|
|
43
|
-
LADDERS,
|
|
44
|
-
type Layout,
|
|
45
|
-
NUMBER_COLOR,
|
|
46
|
-
PLAYER_COLOR,
|
|
47
|
-
RIM,
|
|
48
|
-
SNAKE_AT,
|
|
49
|
-
type SnakeData,
|
|
50
|
-
SNAKES,
|
|
51
|
-
STAR_NUMBER_COLOR,
|
|
52
|
-
START_CELL,
|
|
53
|
-
START_X,
|
|
54
|
-
START_Z,
|
|
55
|
-
TILE_TOP,
|
|
56
|
-
TILT,
|
|
57
|
-
TOKEN_HEIGHT,
|
|
58
|
-
WINNING_POSITION
|
|
59
|
-
} from './SnakesAndLaddersConstants';
|
|
60
|
-
|
|
61
|
-
// ── Helpers ───────────────────────────────────────────────────────────
|
|
62
|
-
|
|
63
|
-
const meshes = new Map<string, Model>();
|
|
64
|
-
const cached = (key: string, build: () => Model) => {
|
|
65
|
-
let m = meshes.get(key);
|
|
66
|
-
if (!m) {
|
|
67
|
-
m = cacheGameAsset('snakes-and-ladders/SnakesAndLaddersScene:' + key, build);
|
|
68
|
-
meshes.set(key, m);
|
|
69
|
-
}
|
|
70
|
-
return m;
|
|
71
|
-
};
|
|
72
|
-
type RGB = [number, number, number];
|
|
73
|
-
const rgb = (css: string): RGB => {
|
|
74
|
-
const [r, g, b] = toColor(css);
|
|
75
|
-
return [r, g, b];
|
|
76
|
-
};
|
|
77
|
-
const mix = (a: RGB, b: RGB, t: number): RGB => [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t, a[2] + (b[2] - a[2]) * t];
|
|
78
|
-
const shade = (c: RGB, k: number): RGB => [c[0] * k, c[1] * k, c[2] * k];
|
|
79
|
-
const smooth = (a: number, b: number, x: number) => {
|
|
80
|
-
const t = Math.min(1, Math.max(0, (x - a) / (b - a)));
|
|
81
|
-
return t * t * (3 - 2 * t);
|
|
82
|
-
};
|
|
83
|
-
const sphere = () => shapeGeometry('sphere');
|
|
84
|
-
const cube = () => shapeGeometry('cube');
|
|
85
|
-
/** Stands a lathe (built around +y) up off the board (+z). */
|
|
86
|
-
const STAND_UP = quat.x(Math.PI / 2);
|
|
87
|
-
type V2 = [number, number];
|
|
88
|
-
const along = (a: V2, b: V2, t: number): V2 => [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
|
|
89
|
-
|
|
90
|
-
// ── Snakes ────────────────────────────────────────────────────────────
|
|
91
|
-
|
|
92
|
-
const SNAKE_POINTS = 30;
|
|
93
|
-
const snakeRadius = (t: number) => 0.0135 * (0.8 + 0.2 * smooth(0, 0.15, t)) * (1 - 0.85 * smooth(0.5, 1, t));
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* A snake's spine from its head (t = 0) to its tail tip (t = 1): an S-curve across the board, on the
|
|
97
|
-
* cells (with `raised`, at the height of its round body, before the board flattens it onto them).
|
|
98
|
-
*/
|
|
99
|
-
export function snakePath(s: SnakeData, raised = false): Vec3[] {
|
|
100
|
-
const head = cellCenter(s.head);
|
|
101
|
-
const tail = cellCenter(s.tail);
|
|
102
|
-
const dx = tail[0] - head[0];
|
|
103
|
-
const dy = tail[1] - head[1];
|
|
104
|
-
const d = Math.hypot(dx, dy);
|
|
105
|
-
const perp: V2 = [-dy / d, dx / d];
|
|
106
|
-
const waves = Math.max(2, Math.round(d / 0.15));
|
|
107
|
-
const amp = Math.min(0.042, d * 0.14);
|
|
108
|
-
return Array.from({ length: SNAKE_POINTS }, (_, i) => {
|
|
109
|
-
const t = i / (SNAKE_POINTS - 1);
|
|
110
|
-
const [x, y] = along(head, tail, t);
|
|
111
|
-
const w = amp * Math.sin(Math.PI * waves * t) * (1 - 0.6 * t);
|
|
112
|
-
return [x + perp[0] * w, y + perp[1] * w, raised ? snakeRadius(t) * 0.8 : TILE_TOP] as Vec3;
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/** A snake's parts, heights measured from the cells' top (the board flattens them onto it). */
|
|
117
|
-
function snakeParts(s: SnakeData): GeometryPart[] {
|
|
118
|
-
const path = snakePath(s, true);
|
|
119
|
-
const base = rgb(s.color);
|
|
120
|
-
const accent = rgb(s.accent);
|
|
121
|
-
const belly = rgb(s.belly);
|
|
122
|
-
const length = Math.hypot(path[0]![0] - path[SNAKE_POINTS - 1]![0], path[0]![1] - path[SNAKE_POINTS - 1]![1]);
|
|
123
|
-
const bands = Math.max(6, Math.round(length * 55));
|
|
124
|
-
const body = tube(path, {
|
|
125
|
-
radius: snakeRadius,
|
|
126
|
-
sides: 12,
|
|
127
|
-
smoothness: 4,
|
|
128
|
-
color: ({ v, normal: n, position: p }) => {
|
|
129
|
-
const band = 0.5 + 0.5 * Math.cos(Math.PI * 2 * bands * v);
|
|
130
|
-
let c = mix(base, accent, smooth(0.62, 0.86, band));
|
|
131
|
-
if (n[2] > 0.55 && band < 0.22) c = mix(c, belly, 0.55); // pale saddles along the back
|
|
132
|
-
if (n[2] < -0.2) c = belly;
|
|
133
|
-
return shade(c, 0.9 + 0.2 * noise(p[0] * 160, p[1] * 160));
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
// The head: a flattened wedge past the neck, looking away from the body
|
|
138
|
-
const [hx, hy] = cellCenter(s.head);
|
|
139
|
-
const neck = path[2]!;
|
|
140
|
-
const hd: V2 = [hx - neck[0], hy - neck[1]];
|
|
141
|
-
const hl = Math.hypot(hd[0], hd[1]) || 1;
|
|
142
|
-
hd[0] /= hl;
|
|
143
|
-
hd[1] /= hl;
|
|
144
|
-
const side: V2 = [-hd[1], hd[0]];
|
|
145
|
-
const angle = Math.atan2(hd[1], hd[0]);
|
|
146
|
-
const yaw = quat.z(angle);
|
|
147
|
-
const at = (forward: number, across: number, z: number): Vec3 => [
|
|
148
|
-
hx + hd[0] * forward + side[0] * across,
|
|
149
|
-
hy + hd[1] * forward + side[1] * across,
|
|
150
|
-
z
|
|
151
|
-
];
|
|
152
|
-
const headColor = mix(base, accent, 0.25);
|
|
153
|
-
const parts: GeometryPart[] = [
|
|
154
|
-
{ geometry: body },
|
|
155
|
-
{ geometry: sphere(), position: at(0.006, 0, 0.011), scale: [0.05, 0.038, 0.022], rotation: yaw, color: [...headColor, 1] },
|
|
156
|
-
{ geometry: sphere(), position: at(0.022, 0, 0.009), scale: [0.03, 0.027, 0.017], rotation: yaw, color: [...headColor, 1] }
|
|
157
|
-
];
|
|
158
|
-
for (const k of [1, -1]) {
|
|
159
|
-
parts.push(
|
|
160
|
-
{ geometry: sphere(), position: at(0.008, 0.012 * k, 0.019), scale: 0.012, color: [1, 1, 0.92, 1] },
|
|
161
|
-
{ geometry: sphere(), position: at(0.01, 0.0125 * k, 0.0245), scale: [0.004, 0.008, 0.004], rotation: yaw, color: [0.05, 0.05, 0.05, 1] },
|
|
162
|
-
{ geometry: sphere(), position: at(0.012, 0.011 * k, 0.026), scale: 0.0022, color: [1, 1, 1, 1] },
|
|
163
|
-
{ geometry: sphere(), position: at(0.033, 0.0055 * k, 0.016), scale: 0.0032, color: [0.08, 0.06, 0.05, 1] }
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
// A forked tongue flicking out
|
|
167
|
-
const red: RGB = [0.85, 0.08, 0.12];
|
|
168
|
-
parts.push({ geometry: tube([at(0.034, 0, 0.007), at(0.05, 0, 0.007)], { radius: 0.0017, sides: 6, color: red }) });
|
|
169
|
-
for (const k of [1, -1])
|
|
170
|
-
parts.push({ geometry: tube([at(0.049, 0, 0.007), at(0.058, 0.0055 * k, 0.007)], { radius: 0.0014, sides: 6, color: red }) });
|
|
171
|
-
return parts;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// ── Ladders ───────────────────────────────────────────────────────────
|
|
175
|
-
|
|
176
|
-
const RAIL_GAP = 0.019; // from the ladder's middle to a rail
|
|
177
|
-
const RAIL_Z = 0.005; // above the cells' top, before the board flattens the ladder onto it
|
|
178
|
-
|
|
179
|
-
/** A ladder's parts, heights measured from the cells' top (the board flattens them onto it). */
|
|
180
|
-
function ladderParts(l: LadderData): GeometryPart[] {
|
|
181
|
-
const a = cellCenter(l.bottom);
|
|
182
|
-
const b = cellCenter(l.top);
|
|
183
|
-
const d = Math.hypot(b[0] - a[0], b[1] - a[1]);
|
|
184
|
-
const u: V2 = [(b[0] - a[0]) / d, (b[1] - a[1]) / d];
|
|
185
|
-
const p: V2 = [-u[1], u[0]];
|
|
186
|
-
const wood = rgb(l.color);
|
|
187
|
-
const light = rgb(l.highlight);
|
|
188
|
-
const grain = ({ v, normal: n }: { v: number; normal: Vec3 }): Color => {
|
|
189
|
-
const g = 0.5 + 0.5 * Math.sin(v * d * 260 + noise(v * d * 40, 3) * 5);
|
|
190
|
-
return shade(mix(wood, light, g * 0.45 + Math.max(0, n[2]) * 0.3), 1);
|
|
191
|
-
};
|
|
192
|
-
const ext = 0.014;
|
|
193
|
-
const parts: GeometryPart[] = [1, -1].map((k) => ({
|
|
194
|
-
geometry: tube(
|
|
195
|
-
[
|
|
196
|
-
[a[0] - u[0] * ext + p[0] * RAIL_GAP * k, a[1] - u[1] * ext + p[1] * RAIL_GAP * k, RAIL_Z],
|
|
197
|
-
[b[0] + u[0] * ext + p[0] * RAIL_GAP * k, b[1] + u[1] * ext + p[1] * RAIL_GAP * k, RAIL_Z]
|
|
198
|
-
],
|
|
199
|
-
{ radius: 0.0045, sides: 8, smoothness: Math.max(8, Math.round(d * 90)), color: grain }
|
|
200
|
-
)
|
|
201
|
-
}));
|
|
202
|
-
const rungs = Math.max(3, Math.floor(d / 0.045));
|
|
203
|
-
for (let r = 1; r <= rungs; r++) {
|
|
204
|
-
const [x, y] = along(a, b, r / (rungs + 1));
|
|
205
|
-
parts.push({
|
|
206
|
-
geometry: tube(
|
|
207
|
-
[
|
|
208
|
-
[x - p[0] * RAIL_GAP, y - p[1] * RAIL_GAP, RAIL_Z + 0.0008],
|
|
209
|
-
[x + p[0] * RAIL_GAP, y + p[1] * RAIL_GAP, RAIL_Z + 0.0008]
|
|
210
|
-
],
|
|
211
|
-
{ radius: 0.0032, sides: 8, color: mix(wood, light, 0.6) }
|
|
212
|
-
)
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
return parts;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/** The ladder's line, from its foot to its top, on the cells where a pawn climbs it. */
|
|
219
|
-
export function ladderPath(l: LadderData): Vec3[] {
|
|
220
|
-
const [ax, ay] = cellCenter(l.bottom);
|
|
221
|
-
const [bx, by] = cellCenter(l.top);
|
|
222
|
-
return [
|
|
223
|
-
[ax, ay, TILE_TOP],
|
|
224
|
-
[bx, by, TILE_TOP]
|
|
225
|
-
];
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// ── The board ─────────────────────────────────────────────────────────
|
|
229
|
-
|
|
230
|
-
const CELL = 1 / BOARD_SIZE;
|
|
231
|
-
|
|
232
|
-
function cellColor(cell: number): RGB {
|
|
233
|
-
const i = cell - 1;
|
|
234
|
-
let c = rgb(CELL_PALETTE[(Math.floor(i / BOARD_SIZE) + (i % BOARD_SIZE)) % CELL_PALETTE.length]!);
|
|
235
|
-
if (cell === 1) c = rgb(START_CELL);
|
|
236
|
-
else if (cell === WINNING_POSITION) c = rgb(FINISH_CELL);
|
|
237
|
-
return c;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/** How much of their height the snakes and ladders keep: pressed flat onto the cells, like a printed board. */
|
|
241
|
-
const FLAT = 0.05;
|
|
242
|
-
/** How thin the flat layers are (cells, star, start pad). */
|
|
243
|
-
const SKIN = 0.0004;
|
|
244
|
-
/**
|
|
245
|
-
* The flat layers' heights above the cells' top, far enough apart that the depth test always knows
|
|
246
|
-
* which is in front (closer, the numbers and the snakes flicker into each other where they overlap),
|
|
247
|
-
* yet well under a pixel on screen: numbers, then the snakes and ladders over them, then pawn shadows.
|
|
248
|
-
*/
|
|
249
|
-
const DIGITS_Z = TILE_TOP + 0.002;
|
|
250
|
-
const ART_Z = TILE_TOP + 0.004;
|
|
251
|
-
export const SHADOW_Z = TILE_TOP + 0.008;
|
|
252
|
-
/** Pawns stand on top of the flat layers (their shadows included), not sunk into them. */
|
|
253
|
-
const PAWN_LIFT = SHADOW_Z + 0.001 - TILE_TOP;
|
|
254
|
-
const pawnAt = (l: Layout, p: Vec3) => toWorld(l, p[0], p[1], p[2] + PAWN_LIFT);
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* The board, all flat (only the pawns and the die stand up in 3D): a slim frame round the grout, the
|
|
258
|
-
* hundred cells, the snakes and ladders pressed onto them, the star on the last cell and the start pad.
|
|
259
|
-
*/
|
|
260
|
-
const boardMesh = () =>
|
|
261
|
-
cached('snl-board', () => {
|
|
262
|
-
const outer = 1 + RIM * 2;
|
|
263
|
-
const frame = rgb('#5C4033');
|
|
264
|
-
const flat = (z: number, scale: Vec3) => ({ position: [0, 0, z] as Vec3, scale });
|
|
265
|
-
const parts: GeometryPart[] = [
|
|
266
|
-
// The frame (the board's edge) and the grout showing between the cells, flush under them
|
|
267
|
-
{ geometry: cube(), ...flat(TILE_TOP - 0.006, [outer, outer, SKIN]), color: [...frame, 1] },
|
|
268
|
-
{ geometry: cube(), ...flat(TILE_TOP - 0.003, [1, 1, SKIN]), color: [...rgb('#CBB894'), 1] }
|
|
269
|
-
];
|
|
270
|
-
for (let cell = 1; cell <= WINNING_POSITION; cell++) {
|
|
271
|
-
const [x, y] = cellCenter(cell);
|
|
272
|
-
parts.push({
|
|
273
|
-
geometry: cube(),
|
|
274
|
-
position: [x, y, TILE_TOP - SKIN / 2],
|
|
275
|
-
scale: [CELL - 0.005, CELL - 0.005, SKIN],
|
|
276
|
-
color: [...cellColor(cell), 1]
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
// A gold star on the last cell
|
|
280
|
-
const [fx, fy] = cellCenter(WINNING_POSITION);
|
|
281
|
-
parts.push({
|
|
282
|
-
geometry: extrude(new Path().addStar(0, 0, 0.5, 0.22), { depth: 0.12 }),
|
|
283
|
-
position: [fx, fy - 0.012, DIGITS_Z],
|
|
284
|
-
scale: [0.042, 0.042, 0.004],
|
|
285
|
-
color: [...rgb('#FFC107'), 1]
|
|
286
|
-
});
|
|
287
|
-
// The start pad: a flat wooden disc for the pawns before their first move
|
|
288
|
-
parts.push({ geometry: extrude(new Path().addCircle(0, 0, 0.08), { depth: SKIN, color: rgb('#A1887F') }), position: [START_X, DIE_Y, START_Z] });
|
|
289
|
-
// Snakes and ladders, pressed onto the cells
|
|
290
|
-
const art = merge([...LADDERS.flatMap(ladderParts), ...SNAKES.flatMap(snakeParts)]);
|
|
291
|
-
parts.push({ geometry: art, position: [0, 0, ART_Z], scale: [1, 1, FLAT] });
|
|
292
|
-
// Matte, like printed card: no glossy highlight on the board (the pawns and die keep theirs)
|
|
293
|
-
return createShape(merge(parts), { center: false, shine: 0 });
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
// ── Cell numbers: the shared 3D glyphs ────────────────────────────────
|
|
297
|
-
|
|
298
|
-
const DIGIT_SCALE = 0.027; // a digit's height on the board
|
|
299
|
-
|
|
300
|
-
/** Each cell's number near its top edge, as children of the board. */
|
|
301
|
-
function spawnNumbers(world: World, board: Entity) {
|
|
302
|
-
const dark = toColor(NUMBER_COLOR);
|
|
303
|
-
const gold = toColor(STAR_NUMBER_COLOR);
|
|
304
|
-
for (let cell = 1; cell <= WINNING_POSITION; cell++) {
|
|
305
|
-
const [x, y] = cellCenter(cell);
|
|
306
|
-
const text = String(cell);
|
|
307
|
-
const width = text.length * GLYPH_ADVANCE - (GLYPH_ADVANCE - GLYPH_WIDTH);
|
|
308
|
-
for (let i = 0; i < text.length; i++) {
|
|
309
|
-
world.spawn({
|
|
310
|
-
mesh: flatGlyphMesh(text[i]!),
|
|
311
|
-
parent: board,
|
|
312
|
-
position: [x + (-width / 2 + GLYPH_WIDTH / 2 + i * GLYPH_ADVANCE) * DIGIT_SCALE, y + CELL * 0.24, DIGITS_Z],
|
|
313
|
-
scale: DIGIT_SCALE,
|
|
314
|
-
color: cell === 1 || cell === WINNING_POSITION ? gold : dark,
|
|
315
|
-
pickable: false
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// ── Pawns, the die, shadows ───────────────────────────────────────────
|
|
322
|
-
|
|
323
|
-
/** A glossy pawn, one unit tall, standing on the origin. */
|
|
324
|
-
const pawnMesh = () =>
|
|
325
|
-
cached('snl-pawn', () =>
|
|
326
|
-
createShape(
|
|
327
|
-
merge([
|
|
328
|
-
{
|
|
329
|
-
geometry: lathe(
|
|
330
|
-
[
|
|
331
|
-
[0.001, 0],
|
|
332
|
-
[0.42, 0],
|
|
333
|
-
[0.44, 0.04],
|
|
334
|
-
[0.42, 0.1],
|
|
335
|
-
[0.31, 0.14],
|
|
336
|
-
[0.25, 0.2],
|
|
337
|
-
[0.19, 0.42],
|
|
338
|
-
[0.15, 0.58],
|
|
339
|
-
[0.27, 0.61],
|
|
340
|
-
[0.27, 0.66],
|
|
341
|
-
[0.14, 0.69]
|
|
342
|
-
],
|
|
343
|
-
{ segments: 32 }
|
|
344
|
-
)
|
|
345
|
-
},
|
|
346
|
-
{ geometry: sphere(), position: [0, 0.84, 0], scale: 0.4 }
|
|
347
|
-
]),
|
|
348
|
-
{ center: false, shine: 0.65 }
|
|
349
|
-
)
|
|
350
|
-
);
|
|
351
|
-
|
|
352
|
-
/** The die showing `value` toward the camera (shared/EngineDice), turned `twist` round its up axis. */
|
|
353
|
-
export const dieRotation = (value: number, twist = 0): Quat => sharedDieRotation(TILT, value, twist);
|
|
354
|
-
|
|
355
|
-
const discMesh = () => cached('snl-disc', () => createShape(extrude(new Path().addCircle(0, 0, 0.5), { depth: 0 })));
|
|
356
|
-
const ringMesh = () =>
|
|
357
|
-
cached('snl-ring', () => createShape(extrude(new Path().addCircle(0, 0, 0.5).addCircle(0, 0, 0.42), { depth: 0, fillRule: 'evenodd' })));
|
|
358
|
-
|
|
359
|
-
// ── Spawning ──────────────────────────────────────────────────────────
|
|
360
|
-
|
|
361
|
-
const SHADOW: Color = [0, 0, 0, 0.22];
|
|
362
|
-
const BACKDROP_DEPTH = 25; // below the board, in world units
|
|
363
|
-
|
|
364
|
-
export type Scene = {
|
|
365
|
-
backdrop: Entity;
|
|
366
|
-
board: Entity;
|
|
367
|
-
tokens: [Entity, Entity];
|
|
368
|
-
shadows: [Entity, Entity];
|
|
369
|
-
die: Entity;
|
|
370
|
-
dieShadow: Entity;
|
|
371
|
-
ring: Entity;
|
|
372
|
-
};
|
|
373
|
-
|
|
374
|
-
/** Board units to world units (view points). */
|
|
375
|
-
export const toWorld = (l: Layout, x: number, y: number, z: number): Vec3 => [x * l.size, y * l.size, z * l.size];
|
|
376
|
-
|
|
377
|
-
const tiltView = (l: Layout): TiltView => ({ width: l.width, height: l.height, centerY: l.centerY, tilt: TILT });
|
|
378
|
-
|
|
379
|
-
/** Points the camera at the board so it lands where the layout puts it. */
|
|
380
|
-
export const aimCamera = (camera: Camera, l: Layout) => aimTilted(camera, tiltView(l));
|
|
381
|
-
|
|
382
|
-
export function buildScene(world: World, l: Layout, theme: GameTheme): Scene {
|
|
383
|
-
const backdrop = spawnBackdrop(world, l.width, l.height, -BACKDROP_DEPTH, theme);
|
|
384
|
-
placeTiltedBackdrop(world, backdrop, tiltView(l), BACKDROP_DEPTH);
|
|
385
|
-
const board = world.spawn({ mesh: boardMesh(), scale: l.size, color: [1, 1, 1, 1], pickable: false });
|
|
386
|
-
spawnNumbers(world, board);
|
|
387
|
-
const token = (color: string) =>
|
|
388
|
-
world.spawn({ mesh: pawnMesh(), rotation: STAND_UP, scale: TOKEN_HEIGHT * l.size, color: toColor(color), pickable: false });
|
|
389
|
-
const shadow = () => world.spawn({ mesh: discMesh(), scale: 0.052 * l.size, color: SHADOW, pickable: false });
|
|
390
|
-
const dieShadow = world.spawn({
|
|
391
|
-
mesh: discMesh(),
|
|
392
|
-
position: toWorld(l, 0.012, DIE_Y - 0.01, 0.001),
|
|
393
|
-
scale: [DIE_SIZE * 1.25 * l.size, DIE_SIZE * 1.1 * l.size, 1],
|
|
394
|
-
color: SHADOW,
|
|
395
|
-
pickable: false
|
|
396
|
-
});
|
|
397
|
-
const ring = world.spawn({ mesh: ringMesh(), position: toWorld(l, 0, DIE_Y, 0.002), scale: 0, color: [1, 0.78, 0.15, 0.85], pickable: false });
|
|
398
|
-
const die = world.spawn({ mesh: dieMesh(), position: dieRest(l), rotation: dieRotation(1), scale: DIE_SIZE * l.size, pickable: false });
|
|
399
|
-
return { backdrop, board, tokens: [token(PLAYER_COLOR), token(AI_COLOR)], shadows: [shadow(), shadow()], die, dieShadow, ring };
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
export function removeScene(world: World, s: Scene) {
|
|
403
|
-
for (const e of [s.backdrop, s.board, ...s.tokens, ...s.shadows, s.die, s.dieShadow, s.ring]) world.despawn(e);
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
export function setSceneTheme(world: World, s: Scene, theme: GameTheme) {
|
|
407
|
-
setBackdropTheme(world, s.backdrop, theme);
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// ── Motion ────────────────────────────────────────────────────────────
|
|
411
|
-
|
|
412
|
-
export const dieRest = (l: Layout): Vec3 => toWorld(l, 0, DIE_Y, DIE_SIZE / 2);
|
|
413
|
-
|
|
414
|
-
/** The die is tossed, tumbles and bounces to rest showing `value` (shared/EngineDice). */
|
|
415
|
-
export function rollDie(world: World, l: Layout, s: Scene, value: number, time: number, disposed?: () => boolean) {
|
|
416
|
-
rollSharedDie(world, {
|
|
417
|
-
die: s.die,
|
|
418
|
-
shadow: s.dieShadow,
|
|
419
|
-
rest: dieRest(l),
|
|
420
|
-
shadowAt: toWorld(l, 0.012, DIE_Y - 0.01, 0.001),
|
|
421
|
-
shadowScale: [DIE_SIZE * 1.25 * l.size, DIE_SIZE * 1.1 * l.size, 1],
|
|
422
|
-
size: DIE_SIZE * l.size,
|
|
423
|
-
tilt: TILT,
|
|
424
|
-
value,
|
|
425
|
-
duration: time,
|
|
426
|
-
disposed
|
|
427
|
-
});
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/** The gold ring under the die pulses while it's the player's roll. */
|
|
431
|
-
export function showRollHint(world: World, l: Layout, s: Scene, on: boolean) {
|
|
432
|
-
world.stopAnimation(s.ring);
|
|
433
|
-
if (!on) {
|
|
434
|
-
world.set(s.ring, { scale: 0 });
|
|
435
|
-
return;
|
|
436
|
-
}
|
|
437
|
-
const size = DIE_SIZE * 1.55 * l.size;
|
|
438
|
-
world.set(s.ring, { scale: size });
|
|
439
|
-
world.animate(s.ring, { scale: size * 1.15 }, { duration: 0.6, easing: 'easeInOut', repeat: 'forever', yoyo: true });
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
/** A pawn's place on a board point (x, y) at height z, and its shadow's under it. */
|
|
443
|
-
export function placeToken(world: World, l: Layout, s: Scene, who: number, at: Vec3) {
|
|
444
|
-
world.stopAnimation(s.tokens[who]!);
|
|
445
|
-
world.stopAnimation(s.shadows[who]!);
|
|
446
|
-
world.set(s.tokens[who]!, { position: pawnAt(l, at) });
|
|
447
|
-
world.set(s.shadows[who]!, { position: toWorld(l, at[0] + 0.006, at[1] - 0.006, SHADOW_Z) });
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
/**
|
|
451
|
-
* Moves a pawn through board points (x, y, z) in `time` seconds, along a smooth curve; with `hop`, it
|
|
452
|
-
* arcs up between them. Its shadow follows along the board.
|
|
453
|
-
*/
|
|
454
|
-
export function moveToken(world: World, l: Layout, s: Scene, who: number, points: Vec3[], time: number, hop = 0) {
|
|
455
|
-
const token = s.tokens[who]!;
|
|
456
|
-
const shadow = s.shadows[who]!;
|
|
457
|
-
const end = points[points.length - 1]!;
|
|
458
|
-
const keys = hop
|
|
459
|
-
? [
|
|
460
|
-
{ position: pawnAt(l, [(points[0]![0] + end[0]) / 2, (points[0]![1] + end[1]) / 2, Math.max(points[0]![2], end[2]) + hop]), at: 0.5 },
|
|
461
|
-
{ position: pawnAt(l, end), at: 1 }
|
|
462
|
-
]
|
|
463
|
-
: points.slice(1).map((p, i) => ({ position: pawnAt(l, p), at: (i + 1) / (points.length - 1) }));
|
|
464
|
-
world.stopAnimation(token);
|
|
465
|
-
world.stopAnimation(shadow);
|
|
466
|
-
world.animate(token, keys, { duration: time, path: 'smooth', easing: hop ? 'linear' : 'easeInOut' });
|
|
467
|
-
world.animate(shadow, { position: toWorld(l, end[0] + 0.006, end[1] - 0.006, SHADOW_Z) }, { duration: time, easing: hop ? 'linear' : 'easeInOut' });
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
/** The pawn whose turn it is bobs gently. */
|
|
471
|
-
export function bobToken(world: World, l: Layout, s: Scene, who: number | null) {
|
|
472
|
-
s.tokens.forEach((t, i) => world.set(t, { bob: i === who ? { amplitude: [0, 0, 0.008 * l.size], speed: 6 } : null }));
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
/** A snake's bite: the pawn shakes and the board jolts. */
|
|
476
|
-
export function snakeBite(world: World, l: Layout, s: Scene, camera: Camera, who: number) {
|
|
477
|
-
world.animate(s.tokens[who]!, { shake: 0.01 * l.size }, { duration: 0.3 });
|
|
478
|
-
camera.shake = 0.008 * l.size;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
/** Sparkles at a board point (a ladder's top). */
|
|
482
|
-
export function sparkle(world: World, l: Layout, at: Vec3) {
|
|
483
|
-
effects.sparkle(world, {
|
|
484
|
-
position: toWorld(l, at[0], at[1], at[2] + 0.03),
|
|
485
|
-
count: 16,
|
|
486
|
-
size: 0.009 * l.size,
|
|
487
|
-
speed: 0.25 * l.size,
|
|
488
|
-
lifetime: 0.6,
|
|
489
|
-
colors: [toColor('#FFD54F'), toColor('#FFF59D'), toColor('#FFFFFF')]
|
|
490
|
-
});
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
/** Confetti over the winning pawn. */
|
|
494
|
-
export function confetti(world: World, l: Layout, at: Vec3) {
|
|
495
|
-
effects.confetti(world, {
|
|
496
|
-
position: toWorld(l, at[0], at[1], at[2] + 0.06),
|
|
497
|
-
count: 48,
|
|
498
|
-
size: 0.012 * l.size,
|
|
499
|
-
speed: 0.7 * l.size,
|
|
500
|
-
lifetime: 1.3,
|
|
501
|
-
gravity: -1.2 * l.size,
|
|
502
|
-
colors: ['#FF5252', '#FFD740', '#69F0AE', '#448AFF'].map((c) => toColor(c))
|
|
503
|
-
});
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
/** The line a pawn slides down a snake (head to tail) or climbs a ladder (foot to top), in board points. */
|
|
507
|
-
const slidePaths = new Map<number, Vec3[] | null>();
|
|
508
|
-
export function slidePath(from: number): Vec3[] | null {
|
|
509
|
-
if (slidePaths.has(from)) return slidePaths.get(from)!;
|
|
510
|
-
const snake = SNAKE_AT.get(from);
|
|
511
|
-
const ladder = LADDER_AT.get(from);
|
|
512
|
-
const path = snake ? snakePath(snake).filter((_, i) => i % 3 === 0 || i === SNAKE_POINTS - 1) : ladder ? ladderPath(ladder) : null;
|
|
513
|
-
if (snake || ladder) slidePaths.set(from, path);
|
|
514
|
-
return path;
|
|
515
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
// Space Fighter's screen, on the Nayan engine: deep space, the ship and the asteroid belts are one 3D
|
|
2
|
-
// scene (a perspective camera looking out into space), under Playtura's scoreboard, controls and
|
|
3
|
-
// modals. The rules are in SpaceFighterGame.ts, what it draws in SpaceFighterScene.ts.
|
|
4
|
-
//
|
|
5
|
-
// One world serves the whole visit: Start, Stop and Play Again reset it in place, so the GPU view is
|
|
6
|
-
// never rebuilt. Rocks tumble, stars drift and the exhausts flicker in the engine's Rust core; JS runs
|
|
7
|
-
// the field (a handful of boxes) and steps the world once a frame.
|
|
8
|
-
import { HapticType } from '../../services/HapticsService';
|
|
9
|
-
import { GAME_SOUNDS } from '../../services/SoundsService';
|
|
10
|
-
import { GAME_IDS } from '../../services/UtilsService';
|
|
11
|
-
import { engineGame, EngineGameScreen } from '../shared/EngineGameScreen';
|
|
12
|
-
import { livesColumn, scoreColumn, timerColumn } from '../shared/EngineHud';
|
|
13
|
-
import { toRgb } from '../shared/EngineUtils';
|
|
14
|
-
import { useEngineGame } from '../shared/useEngineGame';
|
|
15
|
-
import { useLiveState } from '../shared/useLiveState';
|
|
16
|
-
import { BACKGROUND, DAY_BACKGROUND, getLayout, LIGHT, LIVES, TIME_LIMIT } from './SpaceFighterConstants';
|
|
17
|
-
import { createGame, dispose, drag, type GameEvent, reset, setLayout, setTheme, start, tick } from './SpaceFighterGame';
|
|
18
|
-
|
|
19
|
-
const SOUNDS = GAME_SOUNDS.SPACE_FIGHTER;
|
|
20
|
-
const NIGHT_RGB = toRgb(BACKGROUND);
|
|
21
|
-
const DAY_RGB = toRgb(DAY_BACKGROUND);
|
|
22
|
-
|
|
23
|
-
/** Each event's sound and haptic, as the original version played them. */
|
|
24
|
-
const FEEDBACK: Record<GameEvent, { sound: (typeof SOUNDS)[keyof typeof SOUNDS]; haptic: HapticType }> = {
|
|
25
|
-
grab: { sound: SOUNDS.GRAB, haptic: HapticType.MEDIUM },
|
|
26
|
-
release: { sound: SOUNDS.RELEASE, haptic: HapticType.LIGHT },
|
|
27
|
-
dodge: { sound: SOUNDS.DODGE, haptic: HapticType.LIGHT },
|
|
28
|
-
hit: { sound: SOUNDS.COLLISION, haptic: HapticType.HEAVY }
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export const SpaceFighter = engineGame(GAME_IDS.SPACE_FIGHTER, (props) => {
|
|
32
|
-
const [score, setScore] = useLiveState(0);
|
|
33
|
-
const [lives, setLives] = useLiveState(LIVES);
|
|
34
|
-
const [timeLeft, setTimeLeft] = useLiveState(TIME_LIMIT);
|
|
35
|
-
|
|
36
|
-
// A win when the time runs out, a loss with no lives left
|
|
37
|
-
const { theme, status, screen, gameOver } = useEngineGame(props, {
|
|
38
|
-
gameId: GAME_IDS.SPACE_FIGHTER,
|
|
39
|
-
create: createGame,
|
|
40
|
-
setTheme,
|
|
41
|
-
start,
|
|
42
|
-
reset,
|
|
43
|
-
dispose,
|
|
44
|
-
tick,
|
|
45
|
-
resize: (g, width, height, offset) => setLayout(g, getLayout(width, height, offset)),
|
|
46
|
-
drag,
|
|
47
|
-
sounds: SOUNDS,
|
|
48
|
-
onStart: (fx) => fx(SOUNDS.START, HapticType.SUCCESS),
|
|
49
|
-
onOver: (fx, s) => fx(s === 'win' ? SOUNDS.WIN : SOUNDS.GAME_OVER, s === 'win' ? HapticType.SUCCESS : HapticType.ERROR),
|
|
50
|
-
wire: (g, fx) => {
|
|
51
|
-
g.onScore = setScore;
|
|
52
|
-
g.onLives = setLives;
|
|
53
|
-
g.onTime = setTimeLeft;
|
|
54
|
-
g.onEvent = (event) => fx(FEEDBACK[event].sound, FEEDBACK[event].haptic);
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
return (
|
|
59
|
-
<EngineGameScreen
|
|
60
|
-
{...screen}
|
|
61
|
-
light={LIGHT}
|
|
62
|
-
background={theme.mode === 'dark' ? NIGHT_RGB : DAY_RGB}
|
|
63
|
-
columns={[scoreColumn(score), livesColumn(lives, LIVES), timerColumn(timeLeft, theme, 0)]}
|
|
64
|
-
subtext="Navigate through space!"
|
|
65
|
-
gameOver={gameOver({
|
|
66
|
-
title: 'GAME OVER',
|
|
67
|
-
message: status === 'win' ? 'You survived the asteroid field!' : 'Your ship was destroyed!',
|
|
68
|
-
scoreLabel: 'Final Score',
|
|
69
|
-
score,
|
|
70
|
-
buttonText: 'Fly Again!'
|
|
71
|
-
})}
|
|
72
|
-
/>
|
|
73
|
-
);
|
|
74
|
-
});
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import type { Light } from '@nayan-ui/engine';
|
|
2
|
-
// Space Fighter's rules, physics, timings and layout. Rules, scoring and sizing match the original version
|
|
3
|
-
// (games/space-fighter): everything is in screen points, scaled from a 390 x 844 phone, so the field
|
|
4
|
-
// takes the same time to cross and the gaps are as wide on every device.
|
|
5
|
-
import { getScoreBoardTop } from '../shared/EngineHud';
|
|
6
|
-
|
|
7
|
-
// ── Rules ─────────────────────────────────────────────────────────────
|
|
8
|
-
|
|
9
|
-
export const TIME_LIMIT = 120; // seconds; surviving them wins
|
|
10
|
-
export const LIVES = 3;
|
|
11
|
-
export const DODGE_POINTS = 500; // a pair of asteroid belts passed
|
|
12
|
-
export const HIT_COOLDOWN = 2; // seconds of blinking safety after a hit
|
|
13
|
-
|
|
14
|
-
// ── Sizes and speeds (points, at the 390 x 844 base) ──────────────────
|
|
15
|
-
|
|
16
|
-
const BASE_WIDTH = 390;
|
|
17
|
-
const BASE_HEIGHT = 844;
|
|
18
|
-
const TABLET_WIDTH = 640;
|
|
19
|
-
const SHIP_SIZE = { phone: 28, tablet: 22 }; // the ship's hitbox, a square
|
|
20
|
-
const BELT_HEIGHT = { phone: 80, tablet: 60 }; // each belt's depth down the screen
|
|
21
|
-
const GAP = 120; // the opening between a pair's belts
|
|
22
|
-
const SPAWN_INTERVAL = { phone: 1.5, tablet: 1.8 }; // seconds, at the base height
|
|
23
|
-
const FALL_SPEED = 3.5; // points per 16 ms frame, at the base height
|
|
24
|
-
const GAP_VARIANCE = 0.15; // of the width: how far the opening wanders from the centre
|
|
25
|
-
const MIN_EDGE = 0.08; // of the width: the narrowest a belt gets
|
|
26
|
-
const SPAWN_ABOVE = 0.3; // of the height: where a pair starts, above the top edge
|
|
27
|
-
|
|
28
|
-
export const BASE_FRAME = 0.016; // the fall speed is per this much time
|
|
29
|
-
export const MAX_FRAME = 0.064; // a long frame moves the field at most this much
|
|
30
|
-
|
|
31
|
-
// ── The scene ─────────────────────────────────────────────────────────
|
|
32
|
-
|
|
33
|
-
/** How far ahead of the camera the game plays, in world units: screen points map onto this plane. */
|
|
34
|
-
export const PLAY_DEPTH = 12;
|
|
35
|
-
export const FOV = 0.9;
|
|
36
|
-
export const BACKGROUND = '#050311'; // night: deep black space
|
|
37
|
-
export const DAY_BACKGROUND = '#A8DCF7'; // day (light mode): a bright daytime sky
|
|
38
|
-
/** A cool starlight from the upper left, a touch of violet in the shadows. */
|
|
39
|
-
export const LIGHT: Light = { direction: [-0.45, 0.6, 0.65], ambient: 0.38, shadows: false, color: [1.05, 1.02, 1.1] };
|
|
40
|
-
|
|
41
|
-
// ── Layout ────────────────────────────────────────────────────────────
|
|
42
|
-
|
|
43
|
-
export type Layout = {
|
|
44
|
-
width: number;
|
|
45
|
-
height: number;
|
|
46
|
-
offset: number;
|
|
47
|
-
/** World units per screen point on the play plane. */
|
|
48
|
-
k: number;
|
|
49
|
-
shipSize: number;
|
|
50
|
-
shipY: number;
|
|
51
|
-
beltHeight: number;
|
|
52
|
-
gap: number;
|
|
53
|
-
spawnInterval: number;
|
|
54
|
-
/** Points per second. */
|
|
55
|
-
fallSpeed: number;
|
|
56
|
-
spawnY: number;
|
|
57
|
-
/** Where the scoreboard ends, for the start hint. */
|
|
58
|
-
scoreboardBottom: number;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
export function getLayout(width: number, height: number, offset: number): Layout {
|
|
62
|
-
const tablet = width > TABLET_WIDTH;
|
|
63
|
-
const sx = width / BASE_WIDTH;
|
|
64
|
-
const sy = height / BASE_HEIGHT;
|
|
65
|
-
return {
|
|
66
|
-
width,
|
|
67
|
-
height,
|
|
68
|
-
offset,
|
|
69
|
-
k: (2 * PLAY_DEPTH * Math.tan(FOV / 2)) / height,
|
|
70
|
-
shipSize: Math.round((tablet ? SHIP_SIZE.tablet : SHIP_SIZE.phone) * sx),
|
|
71
|
-
shipY: height * (offset > 0 ? 0.77 : 0.68),
|
|
72
|
-
beltHeight: Math.round((tablet ? BELT_HEIGHT.tablet : BELT_HEIGHT.phone) * sy),
|
|
73
|
-
gap: Math.round(GAP * sx),
|
|
74
|
-
spawnInterval: (tablet ? SPAWN_INTERVAL.tablet : SPAWN_INTERVAL.phone) / sy,
|
|
75
|
-
fallSpeed: (FALL_SPEED * sy) / BASE_FRAME,
|
|
76
|
-
spawnY: -Math.round(height * SPAWN_ABOVE),
|
|
77
|
-
scoreboardBottom: getScoreBoardTop(offset) + 82
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/** Where a pair's opening goes: near the centre, wandering a little, never squeezing a belt off the edge. */
|
|
82
|
-
export function gapLeft(l: Layout, random = Math.random) {
|
|
83
|
-
const centre = l.width / 2 + (random() - 0.5) * 2 * l.width * GAP_VARIANCE;
|
|
84
|
-
const minEdge = Math.round(l.width * MIN_EDGE);
|
|
85
|
-
return Math.max(minEdge, Math.min(centre - l.gap / 2, l.width - l.gap - minEdge));
|
|
86
|
-
}
|