@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,240 +0,0 @@
|
|
|
1
|
-
// Everything an engine game's screen does besides its own HUD, in one hook: makes the game once and
|
|
2
|
-
// disposes it on leave, follows the theme, keeps the phase and result, plays sounds and haptics with
|
|
3
|
-
// the current settings, reports each game exactly once (win / lose when it ends, cancel on Stop or on
|
|
4
|
-
// leaving mid-game), and hands back the props EngineGameScreen needs.
|
|
5
|
-
//
|
|
6
|
-
// const { game, theme, phase, won, fx, screen, gameOver } = useEngineGame(props, {
|
|
7
|
-
// gameId: GAME_IDS.MY_GAME, create: createGame, reset, start, dispose, tick, setTheme,
|
|
8
|
-
// wire: (g, fx) => { g.onScore = setScore; g.onHit = () => fx(SOUNDS.HIT, HapticType.LIGHT); }
|
|
9
|
-
// });
|
|
10
|
-
// return <EngineGameScreen {...screen} columns={...} subtext="..." gameOver={gameOver({ title: ... })} />;
|
|
11
|
-
import { useEffect, useLayoutEffect, useRef } from 'react';
|
|
12
|
-
import type { Camera, DragEvent, World } from '@nayan-ui/engine';
|
|
13
|
-
import { type HapticType, playHaptic } from '../../services/HapticsService';
|
|
14
|
-
import { playSound, preloadGameSounds, preloadSounds, type SoundConfig, stopAllSounds } from '../../services/SoundsService';
|
|
15
|
-
import { type GameTheme, resolveGameTheme } from '../../services/ThemeService';
|
|
16
|
-
import type { GameProps } from '../../services/UtilsService';
|
|
17
|
-
import type { EngineGameScreenProps } from './EngineGameScreen';
|
|
18
|
-
import type { EngineHud, GameOverCard, HudFeedback } from './EngineHud';
|
|
19
|
-
import { useGameResource } from './useGameResource';
|
|
20
|
-
import { useLiveState } from './useLiveState';
|
|
21
|
-
|
|
22
|
-
type Phase = 'ready' | 'playing' | 'over';
|
|
23
|
-
/** How an ended game came out; a draw is reported as a cancel. */
|
|
24
|
-
export type GameResult = 'win' | 'lose' | 'draw';
|
|
25
|
-
|
|
26
|
-
/** What every engine game's state exposes to its screen. */
|
|
27
|
-
export type EngineGameModel = {
|
|
28
|
-
world: World | null;
|
|
29
|
-
camera: Camera;
|
|
30
|
-
score?: number;
|
|
31
|
-
phase: Phase;
|
|
32
|
-
won?: boolean;
|
|
33
|
-
onPhase: (phase: Phase) => void;
|
|
34
|
-
hudFeedback?: HudFeedback;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
/** Plays a sound and/or a haptic, each only if the player has it switched on. */
|
|
38
|
-
export type Feedback = (sound?: SoundConfig | null, haptic?: HapticType | null) => void;
|
|
39
|
-
|
|
40
|
-
export type EngineGameSpec<G extends EngineGameModel> = {
|
|
41
|
-
gameId: string;
|
|
42
|
-
create: (theme: GameTheme) => G;
|
|
43
|
-
start: (g: G) => void;
|
|
44
|
-
reset: (g: G) => void;
|
|
45
|
-
/** What Play Again does; `reset` by default. */
|
|
46
|
-
replay?: (g: G) => void;
|
|
47
|
-
dispose: (g: G) => void;
|
|
48
|
-
tick?: (g: G, dt: number) => void;
|
|
49
|
-
hud?: (g: G, hud: EngineHud) => void;
|
|
50
|
-
setTheme?: (g: G, theme: GameTheme) => void;
|
|
51
|
-
setActive?: (g: G, active: boolean) => void;
|
|
52
|
-
resize?: (g: G, width: number, height: number, offset: number) => number | void;
|
|
53
|
-
drag?: (g: G, e: DragEvent) => void;
|
|
54
|
-
tap?: (g: G, x: number, y: number) => void;
|
|
55
|
-
/** How an ended game came out (reported, and returned as `status`); from `g.won` by default. */
|
|
56
|
-
outcome?: (g: G) => GameResult;
|
|
57
|
-
/** The score reported with a result; `g.score` by default. */
|
|
58
|
-
reportScore?: (g: G, status: 'win' | 'lose' | 'cancel') => number;
|
|
59
|
-
/** Optional game-specific completion metrics, sampled at the same time as the final score. */
|
|
60
|
-
reportData?: (g: G, status: 'win' | 'lose' | 'cancel') => Record<string, unknown>;
|
|
61
|
-
/** Hooks the game's events up to React state and feedback; called once. May return a cleanup, run on leaving. */
|
|
62
|
-
wire?: (g: G, fx: Feedback) => void | (() => void);
|
|
63
|
-
/** Cached ahead of the first sound. */
|
|
64
|
-
sounds?: Record<string, SoundConfig>;
|
|
65
|
-
/** Feedback on Start / Stop. */
|
|
66
|
-
onStart?: (fx: Feedback) => void;
|
|
67
|
-
onStop?: (fx: Feedback) => void;
|
|
68
|
-
onPlayAgain?: (fx: Feedback) => void;
|
|
69
|
-
/** Feedback as the game ends, beyond what its own events play. */
|
|
70
|
-
onOver?: (fx: Feedback, status: GameResult, game: G) => void;
|
|
71
|
-
/** Lets an ending play out (ms) before the game-over card covers it. */
|
|
72
|
-
resultsDelay?: (status: GameResult) => number;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
type ScreenProps = Pick<
|
|
76
|
-
EngineGameScreenProps,
|
|
77
|
-
| 'onActiveChange'
|
|
78
|
-
| 'feedback'
|
|
79
|
-
| 'gameId'
|
|
80
|
-
| 'settings'
|
|
81
|
-
| 'onSettingsChange'
|
|
82
|
-
| 'onShare'
|
|
83
|
-
| 'onShowLeaderboard'
|
|
84
|
-
| 'bannerAd'
|
|
85
|
-
| 'source'
|
|
86
|
-
| 'camera'
|
|
87
|
-
| 'onUpdate'
|
|
88
|
-
| 'onResize'
|
|
89
|
-
| 'onDrag'
|
|
90
|
-
| 'onTap'
|
|
91
|
-
| 'playing'
|
|
92
|
-
| 'onStart'
|
|
93
|
-
| 'onStop'
|
|
94
|
-
>;
|
|
95
|
-
|
|
96
|
-
export function useEngineGame<G extends EngineGameModel>(
|
|
97
|
-
props: GameProps & { settings: NonNullable<GameProps['settings']> },
|
|
98
|
-
spec: EngineGameSpec<G>
|
|
99
|
-
) {
|
|
100
|
-
const { settings } = props;
|
|
101
|
-
const theme = resolveGameTheme(settings.theme);
|
|
102
|
-
// Live state: the result and the game-over card show the moment the game ends, however busy the frame loop is
|
|
103
|
-
const [phase, setPhase] = useLiveState<Phase>('ready', 0);
|
|
104
|
-
const [status, setStatus] = useLiveState<GameResult>('lose', 0);
|
|
105
|
-
const [showResults, setShowResults] = useLiveState(false, 0);
|
|
106
|
-
|
|
107
|
-
// The latest props and spec, for the handlers made once below
|
|
108
|
-
const latest = useRef({ props, spec });
|
|
109
|
-
latest.current = { props, spec };
|
|
110
|
-
|
|
111
|
-
const session = useGameResource(
|
|
112
|
-
() => {
|
|
113
|
-
const game = spec.create(theme);
|
|
114
|
-
let reported = false;
|
|
115
|
-
let disposed = false;
|
|
116
|
-
const fx: Feedback = (sound, haptic) => {
|
|
117
|
-
if (disposed || latest.current.props.settings.isVisible) return;
|
|
118
|
-
const { enableSounds, enableHaptics } = latest.current.props.settings;
|
|
119
|
-
if (sound) playSound(sound, enableSounds);
|
|
120
|
-
if (haptic != null) playHaptic(haptic, enableHaptics);
|
|
121
|
-
};
|
|
122
|
-
const report = (status: 'win' | 'lose' | 'cancel') => {
|
|
123
|
-
if (reported) return;
|
|
124
|
-
reported = true;
|
|
125
|
-
const score = latest.current.spec.reportScore?.(game, status) ?? game.score ?? 0;
|
|
126
|
-
const additionalData = latest.current.spec.reportData?.(game, status);
|
|
127
|
-
latest.current.props.onEndGame?.({ status, score: score.toString(), ...(additionalData ? { additionalData } : {}) });
|
|
128
|
-
};
|
|
129
|
-
// The result is set with the phase, so the card never shows the previous game's
|
|
130
|
-
game.onPhase = (next) => {
|
|
131
|
-
if (next === 'over') {
|
|
132
|
-
const result = latest.current.spec.outcome?.(game) ?? (game.won ? 'win' : 'lose');
|
|
133
|
-
setStatus(result);
|
|
134
|
-
report(result === 'draw' ? 'cancel' : result);
|
|
135
|
-
latest.current.spec.onOver?.(fx, result, game);
|
|
136
|
-
}
|
|
137
|
-
setPhase(next);
|
|
138
|
-
};
|
|
139
|
-
const s = () => latest.current.spec;
|
|
140
|
-
const handlers = {
|
|
141
|
-
onActiveChange: (active: boolean) => s().setActive?.(game, active),
|
|
142
|
-
onUpdate: (dt: number, hud?: EngineHud) => {
|
|
143
|
-
s().tick?.(game, dt);
|
|
144
|
-
if (hud) s().hud?.(game, hud);
|
|
145
|
-
},
|
|
146
|
-
onResize: (w: number, h: number, offset: number) => s().resize?.(game, w, h, offset),
|
|
147
|
-
onDrag: (e: DragEvent) => s().drag?.(game, e),
|
|
148
|
-
onTap: (x: number, y: number) => s().tap?.(game, x, y),
|
|
149
|
-
onStart: () => {
|
|
150
|
-
stopAllSounds();
|
|
151
|
-
reported = false;
|
|
152
|
-
s().start(game);
|
|
153
|
-
s().onStart?.(fx);
|
|
154
|
-
},
|
|
155
|
-
onStop: () => {
|
|
156
|
-
stopAllSounds();
|
|
157
|
-
report('cancel');
|
|
158
|
-
s().onStop?.(fx);
|
|
159
|
-
s().reset(game);
|
|
160
|
-
},
|
|
161
|
-
playAgain: () => {
|
|
162
|
-
stopAllSounds();
|
|
163
|
-
reported = false;
|
|
164
|
-
latest.current.props.onReplayGame?.();
|
|
165
|
-
(s().replay ?? s().reset)(game);
|
|
166
|
-
s().onPlayAgain?.(fx);
|
|
167
|
-
}
|
|
168
|
-
};
|
|
169
|
-
return {
|
|
170
|
-
game,
|
|
171
|
-
fx,
|
|
172
|
-
report,
|
|
173
|
-
handlers,
|
|
174
|
-
closeFeedback: () => {
|
|
175
|
-
disposed = true;
|
|
176
|
-
stopAllSounds();
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
},
|
|
180
|
-
(session) => {
|
|
181
|
-
const { game, fx } = session;
|
|
182
|
-
// Wire once; a real unmount reports cancellation and releases the native world.
|
|
183
|
-
// Direct component consumers don't go through GameLoaders; warm their effects too.
|
|
184
|
-
preloadGameSounds(spec.gameId);
|
|
185
|
-
if (spec.sounds) preloadSounds(spec.sounds);
|
|
186
|
-
const cleanup = spec.wire?.(game, fx);
|
|
187
|
-
return () => {
|
|
188
|
-
session.closeFeedback();
|
|
189
|
-
cleanup?.();
|
|
190
|
-
if (game.phase === 'playing') session.report('cancel');
|
|
191
|
-
latest.current.spec.dispose(game);
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
);
|
|
195
|
-
const { game, fx, handlers } = session;
|
|
196
|
-
|
|
197
|
-
// create(theme) already applied the initial theme. Rebuilding it on mount used to
|
|
198
|
-
// create and immediately destroy a second board in games without their own guard.
|
|
199
|
-
const appliedTheme = useRef(theme);
|
|
200
|
-
useLayoutEffect(() => {
|
|
201
|
-
if (appliedTheme.current === theme) return;
|
|
202
|
-
appliedTheme.current = theme;
|
|
203
|
-
latest.current.spec.setTheme?.(game, theme);
|
|
204
|
-
}, [game, theme]);
|
|
205
|
-
|
|
206
|
-
// The card shows at once, or after the ending has played out
|
|
207
|
-
useEffect(() => {
|
|
208
|
-
if (phase !== 'over') return setShowResults(false);
|
|
209
|
-
const delay = latest.current.spec.resultsDelay?.(status) ?? 0;
|
|
210
|
-
if (!delay) return setShowResults(true);
|
|
211
|
-
const t = setTimeout(() => setShowResults(true), delay);
|
|
212
|
-
return () => clearTimeout(t);
|
|
213
|
-
}, [phase, status, setShowResults]);
|
|
214
|
-
|
|
215
|
-
const screen: ScreenProps = {
|
|
216
|
-
gameId: spec.gameId,
|
|
217
|
-
feedback: game.hudFeedback,
|
|
218
|
-
onActiveChange: handlers.onActiveChange,
|
|
219
|
-
settings,
|
|
220
|
-
onSettingsChange: props.onSettingsChange,
|
|
221
|
-
onShare: props.onShareScreenshot ?? props.onShare,
|
|
222
|
-
onShowLeaderboard: props.onShowLeaderboard,
|
|
223
|
-
bannerAd: props.bannerAd,
|
|
224
|
-
source: game.world,
|
|
225
|
-
camera: game.camera,
|
|
226
|
-
onUpdate: handlers.onUpdate,
|
|
227
|
-
onResize: spec.resize ? handlers.onResize : undefined,
|
|
228
|
-
onDrag: spec.drag ? handlers.onDrag : undefined,
|
|
229
|
-
onTap: spec.tap ? handlers.onTap : undefined,
|
|
230
|
-
playing: phase === 'playing',
|
|
231
|
-
onStart: handlers.onStart,
|
|
232
|
-
onStop: handlers.onStop
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
/** The game-over card once it's due (Play Again and Share are filled in), else null. */
|
|
236
|
-
const gameOver = (card: Omit<GameOverCard, 'onPlayAgain' | 'onShare'>): GameOverCard | null =>
|
|
237
|
-
showResults ? { ...card, onPlayAgain: handlers.playAgain, onShare: props.onShareScreenshot } : null;
|
|
238
|
-
|
|
239
|
-
return { game, theme, phase, status, fx, screen, gameOver };
|
|
240
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { useEffect, useRef } from 'react';
|
|
2
|
-
|
|
3
|
-
/** Keep native resources through React's effect replay; release them after a real unmount. */
|
|
4
|
-
export function useGameResource<T>(create: () => T, connect: (value: T) => () => void): T {
|
|
5
|
-
const resource = useRef<{ value: T; users: number; cleanup?: () => void } | null>(null);
|
|
6
|
-
resource.current ??= { value: create(), users: 0 };
|
|
7
|
-
const current = resource.current;
|
|
8
|
-
useEffect(() => {
|
|
9
|
-
current.users++;
|
|
10
|
-
current.cleanup ??= connect(current.value);
|
|
11
|
-
return () => {
|
|
12
|
-
current.users--;
|
|
13
|
-
queueMicrotask(() => {
|
|
14
|
-
if (current.users !== 0) return;
|
|
15
|
-
current.cleanup?.();
|
|
16
|
-
current.cleanup = undefined;
|
|
17
|
-
});
|
|
18
|
-
};
|
|
19
|
-
}, [current]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
20
|
-
return current.value;
|
|
21
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
// `useState` for what a game shows while its frame loop runs (score, timer, lives, phase, the result).
|
|
2
|
-
// React runs ordinary state updates as normal-priority tasks; when every frame takes its whole slot
|
|
3
|
-
// (a busy, slower device) those wait until they expire, about 5 s, so the scoreboard and the
|
|
4
|
-
// game-over card lagged by seconds. An external store's updates render on React's synchronous lane
|
|
5
|
-
// instead, straight after the task that made them. Changes are published at most every
|
|
6
|
-
// `minInterval` ms (the latest value always lands), so a score changing every frame doesn't
|
|
7
|
-
// re-render every frame.
|
|
8
|
-
import { useRef, useSyncExternalStore } from 'react';
|
|
9
|
-
|
|
10
|
-
type SetState<T> = (next: T | ((previous: T) => T)) => void;
|
|
11
|
-
|
|
12
|
-
/** Updates at most this often by default (ms): the scoreboard still reads as live. */
|
|
13
|
-
const MIN_INTERVAL = 100;
|
|
14
|
-
|
|
15
|
-
type Store<T> = { get: () => T; subscribe: (listener: () => void) => () => void; set: SetState<T> };
|
|
16
|
-
|
|
17
|
-
function createStore<T>(initial: T, minInterval: number): Store<T> {
|
|
18
|
-
let shown = initial;
|
|
19
|
-
let latest = initial;
|
|
20
|
-
let last = -Infinity;
|
|
21
|
-
let timer: ReturnType<typeof setTimeout> | null = null;
|
|
22
|
-
const listeners = new Set<() => void>();
|
|
23
|
-
const publish = () => {
|
|
24
|
-
timer = null;
|
|
25
|
-
last = Date.now();
|
|
26
|
-
if (Object.is(shown, latest)) return;
|
|
27
|
-
shown = latest;
|
|
28
|
-
for (const listener of listeners) listener();
|
|
29
|
-
};
|
|
30
|
-
return {
|
|
31
|
-
get: () => shown,
|
|
32
|
-
subscribe: (listener) => {
|
|
33
|
-
listeners.add(listener);
|
|
34
|
-
return () => {
|
|
35
|
-
listeners.delete(listener);
|
|
36
|
-
if (!listeners.size && timer) {
|
|
37
|
-
clearTimeout(timer);
|
|
38
|
-
timer = null;
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
},
|
|
42
|
-
set: (next) => {
|
|
43
|
-
latest = typeof next === 'function' ? (next as (previous: T) => T)(latest) : next;
|
|
44
|
-
if (timer) return;
|
|
45
|
-
const wait = minInterval - (Date.now() - last);
|
|
46
|
-
if (wait <= 0) publish();
|
|
47
|
-
else timer = setTimeout(publish, wait);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** Like `useState`, but its updates show at once even while the frame loop keeps the JS thread busy (see above). */
|
|
53
|
-
export function useLiveState<T>(initial: T | (() => T), minInterval = MIN_INTERVAL): [T, SetState<T>] {
|
|
54
|
-
const store = useRef<Store<T> | null>(null);
|
|
55
|
-
if (!store.current) store.current = createStore(typeof initial === 'function' ? (initial as () => T)() : initial, minInterval);
|
|
56
|
-
const value = useSyncExternalStore(store.current.subscribe, store.current.get);
|
|
57
|
-
return [value, store.current.set];
|
|
58
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
// Sliding Numbers' screen, on the Nayan engine: the board and its tiles are one 3D scene (an
|
|
2
|
-
// orthographic camera leaning back over the board), under Playtura's scoreboard, controls and modals.
|
|
3
|
-
// The play is in SlidingNumbersGame.ts (the board's rules in SlidingNumbersRules.ts), what it draws in
|
|
4
|
-
// SlidingNumbersScene.ts.
|
|
5
|
-
//
|
|
6
|
-
// One world serves the whole visit: Start, Stop and Play Again reset it in place (a new shuffle glides
|
|
7
|
-
// the tiles to their places) and a theme change rebuilds just the board, so the GPU view is never
|
|
8
|
-
// rebuilt. Tiles glide, sink and hop in the engine's Rust core; JS reads the finger and steps the clock.
|
|
9
|
-
import { HapticType } from '../../services/HapticsService';
|
|
10
|
-
import { GAME_SOUNDS } from '../../services/SoundsService';
|
|
11
|
-
import { GAME_IDS, isTablet } from '../../services/UtilsService';
|
|
12
|
-
import { engineGame, EngineGameScreen } from '../shared/EngineGameScreen';
|
|
13
|
-
import { timerColumn } from '../shared/EngineHud';
|
|
14
|
-
import { useEngineGame } from '../shared/useEngineGame';
|
|
15
|
-
import { useLiveState } from '../shared/useLiveState';
|
|
16
|
-
import { GAME_DURATION, getLayout, LIGHT } from './SlidingNumbersConstants';
|
|
17
|
-
import { createGame, dispose, drag, newBoard, setLayout, setTheme, start, stop, tick } from './SlidingNumbersGame';
|
|
18
|
-
|
|
19
|
-
const SOUNDS = GAME_SOUNDS.SLIDING_NUMBERS;
|
|
20
|
-
|
|
21
|
-
export const SlidingNumbers = engineGame(GAME_IDS.SLIDING_NUMBERS, (props) => {
|
|
22
|
-
const [time, setTime] = useLiveState(GAME_DURATION);
|
|
23
|
-
|
|
24
|
-
// Win or lose as it ends
|
|
25
|
-
const { game, theme, status, screen, gameOver } = useEngineGame(props, {
|
|
26
|
-
gameId: GAME_IDS.SLIDING_NUMBERS,
|
|
27
|
-
create: createGame,
|
|
28
|
-
start,
|
|
29
|
-
// Stop: the same board, the clock back to five minutes
|
|
30
|
-
reset: stop,
|
|
31
|
-
// Play Again: a fresh shuffle, waiting for Start
|
|
32
|
-
replay: newBoard,
|
|
33
|
-
dispose,
|
|
34
|
-
tick,
|
|
35
|
-
setTheme,
|
|
36
|
-
resize: (g, width, height, offset) => {
|
|
37
|
-
const l = getLayout(width, height, offset, isTablet);
|
|
38
|
-
setLayout(g, l);
|
|
39
|
-
return l.size + l.pad * 2;
|
|
40
|
-
},
|
|
41
|
-
drag,
|
|
42
|
-
sounds: SOUNDS,
|
|
43
|
-
onStart: (fx) => fx(SOUNDS.START),
|
|
44
|
-
wire: (g, fx) => {
|
|
45
|
-
g.onTime = setTime;
|
|
46
|
-
// As the original game: a slide pops and buzzes; the end plays its sound; a blocked tile only shakes
|
|
47
|
-
g.onEvent = (event) => {
|
|
48
|
-
if (event === 'blocked') fx(SOUNDS.BLOCKED, HapticType.WARNING);
|
|
49
|
-
else if (event === 'move') fx(SOUNDS.MOVE, HapticType.LIGHT);
|
|
50
|
-
else if (event === 'win') fx(SOUNDS.WIN);
|
|
51
|
-
else if (event === 'lose') fx(SOUNDS.GAME_OVER);
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
return (
|
|
57
|
-
<EngineGameScreen
|
|
58
|
-
{...screen}
|
|
59
|
-
light={LIGHT}
|
|
60
|
-
columns={[timerColumn(time, theme)]}
|
|
61
|
-
subtext="Slide tiles to solve!"
|
|
62
|
-
gameOver={gameOver({
|
|
63
|
-
title: status === 'win' ? 'SOLVED!' : 'TIME UP!',
|
|
64
|
-
message: status === 'win' ? 'Puzzle completed!' : 'You ran out of time!',
|
|
65
|
-
scoreLabel: 'Score',
|
|
66
|
-
score: game.score,
|
|
67
|
-
buttonText: status === 'win' ? 'Play Again!' : 'Try Again!'
|
|
68
|
-
})}
|
|
69
|
-
/>
|
|
70
|
-
);
|
|
71
|
-
});
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
// Sliding Numbers' timings, colors and layout. Rules and scores match the original version
|
|
2
|
-
// (games/sliding-numbers), so scores carry over.
|
|
3
|
-
import { getScoreBoardTop } from '../shared/EngineHud';
|
|
4
|
-
import type { TiltView } from '../shared/EngineTilt';
|
|
5
|
-
import { frontLight, gameWidthFor } from '../shared/EngineUtils';
|
|
6
|
-
|
|
7
|
-
// ── Rules and timing ──────────────────────────────────────────────────
|
|
8
|
-
|
|
9
|
-
export const GAME_DURATION = 300; // seconds
|
|
10
|
-
export const SLIDE_TIME = 0.2; // a tile gliding into the gap, as the original slide
|
|
11
|
-
export const PRESS_SCALE = 0.92; // a tile under the finger
|
|
12
|
-
export const TAP_SLOP = 10; // points a finger may wander and still tap
|
|
13
|
-
export const SWIPE = 18; // points a finger must travel for a swipe
|
|
14
|
-
|
|
15
|
-
// ── Colors ────────────────────────────────────────────────────────────
|
|
16
|
-
|
|
17
|
-
/** Tiles 1..8, as the original tiles. */
|
|
18
|
-
export const TILE_COLORS = ['#FF6B6B', '#51CF66', '#339AF0', '#FCC419', '#CC5DE8', '#FF922B', '#22B8CF', '#F06595'] as const;
|
|
19
|
-
export const NUMBER_WORDS = ['', 'ONE', 'TWO', 'THREE', 'FOUR', 'FIVE', 'SIX', 'SEVEN', 'EIGHT'] as const;
|
|
20
|
-
export const COLORS = {
|
|
21
|
-
// The wooden board (classic), as the original board
|
|
22
|
-
FRAME: '#5c4033',
|
|
23
|
-
WELL: '#3a2518',
|
|
24
|
-
SLOT: '#2e1d12',
|
|
25
|
-
NUMBER: '#FFFFFF'
|
|
26
|
-
} as const;
|
|
27
|
-
|
|
28
|
-
// ── The scene ─────────────────────────────────────────────────────────
|
|
29
|
-
|
|
30
|
-
/** The camera leans back from straight down, so the tiles stand up off the board. */
|
|
31
|
-
export const TILT = 0; // straight down
|
|
32
|
-
/** Lit straight on, with no light falling from the top: every face toward the camera keeps its exact color. */
|
|
33
|
-
export const LIGHT = frontLight([0, 0, 1], 0.6);
|
|
34
|
-
/** A tile's height, of its width. */
|
|
35
|
-
export const TILE_HEIGHT = 0.4; // as deep as Candy Crush's blocks, of a tile
|
|
36
|
-
|
|
37
|
-
// ── Layout (view points) ──────────────────────────────────────────────
|
|
38
|
-
|
|
39
|
-
const SCOREBOARD_HEIGHT = 82;
|
|
40
|
-
const CONTROLS_HEIGHT = 120;
|
|
41
|
-
|
|
42
|
-
export type Layout = TiltView & { tile: number; gap: number; pitch: number; pad: number; size: number };
|
|
43
|
-
|
|
44
|
-
/** The board as big as the original board (88% of the width, at most 340 points, 420 on a tablet), smaller if the screen is short. */
|
|
45
|
-
export function getLayout(width: number, height: number, offset: number, tablet: boolean): Layout {
|
|
46
|
-
const gap = tablet ? 6 : 4;
|
|
47
|
-
const pad = tablet ? 18 : 14;
|
|
48
|
-
const top = getScoreBoardTop(offset) + SCOREBOARD_HEIGHT;
|
|
49
|
-
const room = Math.max(180, height - top - CONTROLS_HEIGHT);
|
|
50
|
-
// As wide as the game area (as every game: 30 narrower than the screen, at most 500), shorter if the screen is
|
|
51
|
-
const board = Math.max(150, Math.min(gameWidthFor(width), room / Math.cos(TILT) - 30));
|
|
52
|
-
const tile = Math.floor((board - pad * 2 - gap * 2) / 3);
|
|
53
|
-
const size = tile * 3 + gap * 2;
|
|
54
|
-
return { width, height, tilt: TILT, centerY: top + room / 2, tile, gap, pitch: tile + gap, pad, size };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** A cell's centre on the board (row 0 along the top), in world units. */
|
|
58
|
-
export const cellCentre = (l: Layout, row: number, col: number): [number, number] => [(col - 1) * l.pitch, (1 - row) * l.pitch];
|
|
59
|
-
|
|
60
|
-
/** The cell under a board point, or null. */
|
|
61
|
-
export function cellAt(l: Layout, x: number, y: number): [number, number] | null {
|
|
62
|
-
const col = Math.floor((x + l.size / 2) / l.pitch);
|
|
63
|
-
const row = Math.floor((l.size / 2 - y) / l.pitch);
|
|
64
|
-
return row < 0 || row > 2 || col < 0 || col > 2 ? null : [row, col];
|
|
65
|
-
}
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
// Sliding Numbers' play, with no React: build a game with `createGame`, give it a layout, `start` it and
|
|
2
|
-
// `tick` it every frame. Tap a tile beside the gap (or swipe it toward the gap) to slide it in; put
|
|
3
|
-
// 1 to 8 back in order inside five minutes to win (the quicker, the higher the score).
|
|
4
|
-
//
|
|
5
|
-
// The board's rules are the original store's (SlidingNumbersRules.ts); the clock runs on the game's own clock.
|
|
6
|
-
import { type Camera, type DragEvent, World } from '@nayan-ui/engine';
|
|
7
|
-
import { calculateTimeBasedScore } from '../../services/ScoringService';
|
|
8
|
-
import type { GameTheme } from '../../services/ThemeService';
|
|
9
|
-
import { aimTilted, unproject } from '../shared/EngineTilt';
|
|
10
|
-
import { cellAt, GAME_DURATION, type Layout, SWIPE, TAP_SLOP, TILE_HEIGHT } from './SlidingNumbersConstants';
|
|
11
|
-
import { type Board, canSlide, shuffled, slide, solved, type Tile, tileAt } from './SlidingNumbersRules';
|
|
12
|
-
import { buildScene, celebrate, dim, placeTile, press, removeScene, type Scene, setSceneTheme, shake, undim } from './SlidingNumbersScene';
|
|
13
|
-
|
|
14
|
-
export type Phase = 'ready' | 'playing' | 'over';
|
|
15
|
-
/** move: a tile slid; blocked: a tile that can't move; win / lose: how it ended. */
|
|
16
|
-
export type GameEvent = 'move' | 'blocked' | 'win' | 'lose';
|
|
17
|
-
|
|
18
|
-
const WORLD_CAPACITY = 400; // the board and slots, eight tiles with their shadows and embossed letters, and the confetti
|
|
19
|
-
|
|
20
|
-
export function createGame(theme: GameTheme) {
|
|
21
|
-
const world = new World(WORLD_CAPACITY);
|
|
22
|
-
const camera: Camera = { eye: [0, 0, 240], target: [0, 0, 0], fov: 1, ortho: 1 };
|
|
23
|
-
const g = {
|
|
24
|
-
world,
|
|
25
|
-
camera,
|
|
26
|
-
theme,
|
|
27
|
-
layout: null as Layout | null,
|
|
28
|
-
scene: null as Scene | null,
|
|
29
|
-
phase: 'ready' as Phase,
|
|
30
|
-
board: shuffled() as Board,
|
|
31
|
-
won: false,
|
|
32
|
-
/** Score and the countdown live in the engine (Rust), advanced by world.update. */
|
|
33
|
-
get score() {
|
|
34
|
-
return world.scoreboard.score;
|
|
35
|
-
},
|
|
36
|
-
get timeLeft() {
|
|
37
|
-
return world.scoreboard.shownSeconds;
|
|
38
|
-
},
|
|
39
|
-
/** A finger down on a tile: where, and which. */
|
|
40
|
-
press: null as { x: number; y: number; id: number } | null,
|
|
41
|
-
// UI hooks, set by the screen.
|
|
42
|
-
onPhase: (_p: Phase) => {},
|
|
43
|
-
onTime: (_t: number) => {},
|
|
44
|
-
onEvent: (_e: GameEvent) => {}
|
|
45
|
-
};
|
|
46
|
-
world.scoreboard.reset(0, GAME_DURATION);
|
|
47
|
-
world.scoreboard.handlers = {
|
|
48
|
-
onSecond: (t) => g.onTime(t),
|
|
49
|
-
onTimeUp: () => g.phase === 'playing' && end(g, false)
|
|
50
|
-
};
|
|
51
|
-
return g;
|
|
52
|
-
}
|
|
53
|
-
export type Game = ReturnType<typeof createGame>;
|
|
54
|
-
|
|
55
|
-
// ── Scene ─────────────────────────────────────────────────────────────
|
|
56
|
-
|
|
57
|
-
/** Lays the board out for the view (first layout, header height, rotation): rebuilt where things stand. */
|
|
58
|
-
export function setLayout(g: Game, l: Layout) {
|
|
59
|
-
if (g.scene) removeScene(g.world, g.scene);
|
|
60
|
-
g.layout = l;
|
|
61
|
-
aimTilted(g.camera, l);
|
|
62
|
-
g.scene = buildScene(g.world, l, g.theme, g.board.tiles);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function setTheme(g: Game, theme: GameTheme) {
|
|
66
|
-
g.theme = theme;
|
|
67
|
-
if (g.layout && g.scene) setSceneTheme(g.world, g.layout, g.scene, theme);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// ── Run ───────────────────────────────────────────────────────────────
|
|
71
|
-
|
|
72
|
-
/** Starts on the board already shown. */
|
|
73
|
-
export function start(g: Game) {
|
|
74
|
-
if (g.phase !== 'ready') return;
|
|
75
|
-
g.won = false;
|
|
76
|
-
g.world.scoreboard.reset();
|
|
77
|
-
g.world.scoreboard.startCountdown(GAME_DURATION);
|
|
78
|
-
g.phase = 'playing';
|
|
79
|
-
g.onTime(GAME_DURATION);
|
|
80
|
-
g.onPhase('playing');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/** Stop: the same board, the clock back to five minutes (as the original game). */
|
|
84
|
-
export function stop(g: Game) {
|
|
85
|
-
g.press = null;
|
|
86
|
-
g.won = false;
|
|
87
|
-
g.world.scoreboard.reset(0, GAME_DURATION);
|
|
88
|
-
g.phase = 'ready';
|
|
89
|
-
if (g.scene) undim(g.world, g.scene, g.board.tiles);
|
|
90
|
-
g.onTime(GAME_DURATION);
|
|
91
|
-
g.onPhase('ready');
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** Play Again: a fresh shuffle, the tiles gliding to their new places. */
|
|
95
|
-
export function newBoard(g: Game) {
|
|
96
|
-
g.board = shuffled();
|
|
97
|
-
const { layout: l, scene: s } = g;
|
|
98
|
-
if (l && s) {
|
|
99
|
-
undim(g.world, s, g.board.tiles);
|
|
100
|
-
for (const t of g.board.tiles) placeTile(g.world, l, s, t);
|
|
101
|
-
}
|
|
102
|
-
stop(g);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export function dispose(g: Game) {
|
|
106
|
-
g.world.dispose();
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export function tick(g: Game, dt: number) {
|
|
110
|
-
if (g.world.isDisposed) return;
|
|
111
|
-
g.world.update(dt);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function end(g: Game, won: boolean) {
|
|
115
|
-
g.world.scoreboard.stop();
|
|
116
|
-
g.won = won;
|
|
117
|
-
if (!won) g.world.scoreboard.set(0);
|
|
118
|
-
g.phase = 'over';
|
|
119
|
-
if (g.press && g.layout && g.scene) press(g.world, g.scene, g.press.id, false);
|
|
120
|
-
g.press = null;
|
|
121
|
-
if (g.layout && g.scene) {
|
|
122
|
-
if (won) celebrate(g.world, g.layout, g.scene, g.board.tiles);
|
|
123
|
-
else dim(g.world, g.scene, g.board.tiles);
|
|
124
|
-
}
|
|
125
|
-
g.onPhase('over');
|
|
126
|
-
g.onEvent(won ? 'win' : 'lose');
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// ── Moves ─────────────────────────────────────────────────────────────
|
|
130
|
-
|
|
131
|
-
/** Slides a tile into the gap if it's beside it; shakes it if not. A solved board wins. */
|
|
132
|
-
export function move(g: Game, t: Tile) {
|
|
133
|
-
if (g.phase !== 'playing' || t.value === 0) return;
|
|
134
|
-
const { layout: l, scene: s } = g;
|
|
135
|
-
if (!canSlide(g.board, t)) {
|
|
136
|
-
if (l && s) shake(g.world, l, s, t.id);
|
|
137
|
-
g.onEvent('blocked');
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
slide(g.board, t);
|
|
141
|
-
if (l && s) placeTile(g.world, l, s, t);
|
|
142
|
-
g.onEvent('move');
|
|
143
|
-
if (solved(g.board)) {
|
|
144
|
-
// The time saved under five minutes, as the original score (on a base of 0)
|
|
145
|
-
g.world.scoreboard.set(calculateTimeBasedScore(GAME_DURATION - g.timeLeft, GAME_DURATION, 0));
|
|
146
|
-
end(g, true);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// ── The finger ────────────────────────────────────────────────────────
|
|
151
|
-
|
|
152
|
-
/** The tile under a view point (on the tiles' tops), or null. */
|
|
153
|
-
export function tileUnder(g: Game, x: number, y: number): Tile | null {
|
|
154
|
-
const l = g.layout;
|
|
155
|
-
if (!l) return null;
|
|
156
|
-
const [wx, wy] = unproject(l, x, y, 1 + l.tile * TILE_HEIGHT);
|
|
157
|
-
const cell = cellAt(l, wx, wy);
|
|
158
|
-
const t = cell ? tileAt(g.board, cell[0], cell[1]) : null;
|
|
159
|
-
return t && t.value !== 0 ? t : null;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/** A finger down sinks the tile under it; a tap slides it, and so does a swipe toward the gap. */
|
|
163
|
-
export function drag(g: Game, { phase, x, y }: DragEvent) {
|
|
164
|
-
const { layout: l, scene: s } = g;
|
|
165
|
-
if (phase === 'start') {
|
|
166
|
-
const t = g.phase === 'playing' ? tileUnder(g, x, y) : null;
|
|
167
|
-
g.press = t ? { x, y, id: t.id } : null;
|
|
168
|
-
if (t && l && s) press(g.world, s, t.id, true);
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
const p = g.press;
|
|
172
|
-
if (!p) return;
|
|
173
|
-
const t = g.board.tiles.find((k) => k.id === p.id)!;
|
|
174
|
-
const dx = x - p.x;
|
|
175
|
-
const dy = y - p.y;
|
|
176
|
-
// A swipe: once it's gone far enough one way, the tile slides if that way is the gap
|
|
177
|
-
const far = Math.hypot(dx, dy);
|
|
178
|
-
if (far >= SWIPE || phase === 'end') {
|
|
179
|
-
g.press = null;
|
|
180
|
-
if (l && s) press(g.world, s, p.id, false);
|
|
181
|
-
if (far < TAP_SLOP) return move(g, t); // a tap
|
|
182
|
-
if (far < SWIPE) return; // wandered, then let go
|
|
183
|
-
const horizontal = Math.abs(dx) > Math.abs(dy);
|
|
184
|
-
const toRow = t.row + (horizontal ? 0 : dy > 0 ? 1 : -1);
|
|
185
|
-
const toCol = t.col + (horizontal ? (dx > 0 ? 1 : -1) : 0);
|
|
186
|
-
if (toRow === g.board.emptyRow && toCol === g.board.emptyCol) move(g, t);
|
|
187
|
-
else {
|
|
188
|
-
if (l && s) shake(g.world, l, s, t.id);
|
|
189
|
-
g.onEvent('blocked');
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|