@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,319 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type Color,
|
|
3
|
-
effects,
|
|
4
|
-
type Entity,
|
|
5
|
-
extrude,
|
|
6
|
-
merge,
|
|
7
|
-
type Model,
|
|
8
|
-
Path,
|
|
9
|
-
quat,
|
|
10
|
-
shapeGeometry,
|
|
11
|
-
type TransformBatch,
|
|
12
|
-
tube,
|
|
13
|
-
type Vec3,
|
|
14
|
-
type World
|
|
15
|
-
} from '@nayan-ui/engine';
|
|
16
|
-
import { lighten } from '../../services/GamesConstants';
|
|
17
|
-
import type { Fruit, FruitKind } from '../shared/EngineFruits';
|
|
18
|
-
import { cacheGameAsset, createGameMesh as createShape } from '../shared/EngineMeshes';
|
|
19
|
-
// Everything Fruit Ninja throws, slices and swipes, in front of its 3D world (FruitNinjaWorld). Positions
|
|
20
|
-
// come in screen points (y down) and land on the play plane a few metres ahead of the camera, where the
|
|
21
|
-
// original game drew them; sizes and speeds are scaled to metres there.
|
|
22
|
-
// Fruit are EngineFruits' 3D models (each also modelled in halves for slicing), the bomb and the star
|
|
23
|
-
// are built here once; all are shared meshes, as mesh ids are app-wide and limited. A thrown item is an
|
|
24
|
-
// invisible root at its centre (it spins about it) carrying the model.
|
|
25
|
-
// Sliced halves and splashes fly on their own in the engine's Rust core (velocity, gravity, lifetime).
|
|
26
|
-
import { toColor } from '../shared/EngineUtils';
|
|
27
|
-
import {
|
|
28
|
-
BLADE_POINTS,
|
|
29
|
-
BOMB_COLORS,
|
|
30
|
-
FRAME_TIME,
|
|
31
|
-
type Layout,
|
|
32
|
-
PIECE_LIFETIME,
|
|
33
|
-
PIECE_SPREAD,
|
|
34
|
-
SPAWN_FROM,
|
|
35
|
-
SPAWN_SPRING,
|
|
36
|
-
STAR_COLORS,
|
|
37
|
-
TRAIL_FADE
|
|
38
|
-
} from './FruitNinjaConstants';
|
|
39
|
-
import { at, facing, planeVector, PLAY_DEPTH, pointSize, type View3D } from './FruitNinjaWorld';
|
|
40
|
-
|
|
41
|
-
const HIDDEN = 0;
|
|
42
|
-
const PER_SECOND = 1 / FRAME_TIME; // the physics is per frame; the engine's motion is per second
|
|
43
|
-
/** The trail floats this far in front of the play plane, so it's drawn over the fruit it cuts. */
|
|
44
|
-
const TRAIL_DEPTH = PLAY_DEPTH - 0.35;
|
|
45
|
-
|
|
46
|
-
// ── Models (built once per app: mesh ids last for the whole app) ──────
|
|
47
|
-
|
|
48
|
-
export type ItemKind = { kind: 'fruit'; fruit: FruitKind } | { kind: 'bomb' } | { kind: 'star' };
|
|
49
|
-
export type Models = { fruits: Record<FruitKind, Fruit>; bomb: Model; spark: Model; star: Model; disc: Model };
|
|
50
|
-
|
|
51
|
-
let extras: Omit<Models, 'fruits'> | undefined;
|
|
52
|
-
/** The bomb, its fuse spark, the star and a flat disc (glows, trail joints). Needs the native core. */
|
|
53
|
-
export function buildModels(fruits: Record<FruitKind, Fruit>): Models {
|
|
54
|
-
extras ??= cacheGameAsset('fruit-ninja/extras', () => ({
|
|
55
|
-
// A dark glossy ball with a cap and a curling fuse
|
|
56
|
-
bomb: createShape(
|
|
57
|
-
merge([
|
|
58
|
-
{ geometry: shapeGeometry('sphere'), color: [0.13, 0.14, 0.17] },
|
|
59
|
-
{ geometry: shapeGeometry('cylinder'), position: [0, 0.5, 0], scale: [0.26, 0.14, 0.26], color: [0.35, 0.37, 0.42] },
|
|
60
|
-
{
|
|
61
|
-
geometry: tube(
|
|
62
|
-
[
|
|
63
|
-
[0, 0.55, 0],
|
|
64
|
-
[0.04, 0.7, 0],
|
|
65
|
-
[0.14, 0.78, 0],
|
|
66
|
-
[0.22, 0.76, 0]
|
|
67
|
-
],
|
|
68
|
-
{ radius: 0.035 }
|
|
69
|
-
),
|
|
70
|
-
color: [0.76, 0.6, 0.38]
|
|
71
|
-
}
|
|
72
|
-
]),
|
|
73
|
-
{ fit: 1, shine: 0.7 }
|
|
74
|
-
),
|
|
75
|
-
spark: createShape(shapeGeometry('sphere')),
|
|
76
|
-
star: createShape(extrude(new Path().addStar(0, 0, 0.5, 0.22, 5), { depth: 0.22, color: toColor(STAR_COLORS[0]) }), { fit: 1, shine: 0.6 }),
|
|
77
|
-
disc: createShape(extrude(new Path().addCircle(0, 0, 0.5), { depth: 0 }))
|
|
78
|
-
}));
|
|
79
|
-
return { fruits, ...extras };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// ── Thrown items ──────────────────────────────────────────────────────
|
|
83
|
-
|
|
84
|
-
const SPARK: Color = [3, 2.1, 0.6]; // above 1: self-lit
|
|
85
|
-
const WHITE: Color = [1, 1, 1, 1];
|
|
86
|
-
|
|
87
|
-
/** A model's offset and scale so it fills `size` metres, centred on its bounding box. */
|
|
88
|
-
function fitted(model: Model, size: number, center: Vec3 = [0, 0, 0]) {
|
|
89
|
-
const s = size / Math.max(model.size[0], model.size[1]);
|
|
90
|
-
return { scale: s, position: [-center[0] * s, -center[1] * s, -center[2] * s] as Vec3 };
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* A thrown item at screen point (x, y) (its centre), springing up to full size and spinning: `spin` is
|
|
95
|
-
* its turn per frame in the picture's plane (clockwise positive, as original), plus a little tumble.
|
|
96
|
-
*/
|
|
97
|
-
export function spawnItem(world: World, v: View3D, l: Layout, m: Models, item: ItemKind, x: number, y: number, spin: number): Entity {
|
|
98
|
-
const tumble = (Math.random() - 0.5) * 3;
|
|
99
|
-
const size = l.size * pointSize(v);
|
|
100
|
-
const root = world.spawn({
|
|
101
|
-
mesh: 'none',
|
|
102
|
-
position: at(v, x, y),
|
|
103
|
-
scale: SPAWN_FROM,
|
|
104
|
-
spin: [tumble * 0.4, tumble, -spin * PER_SECOND],
|
|
105
|
-
pickable: false
|
|
106
|
-
});
|
|
107
|
-
world.animate(root, { scale: 1 }, { spring: SPAWN_SPRING });
|
|
108
|
-
const add = (mesh: Model, f: ReturnType<typeof fitted>, color: Color = WHITE) =>
|
|
109
|
-
world.spawn({ mesh, parent: root, position: f.position, scale: f.scale, color, pickable: false });
|
|
110
|
-
if (item.kind === 'fruit') {
|
|
111
|
-
const fruit = m.fruits[item.fruit];
|
|
112
|
-
add(fruit.whole, fitted(fruit.whole, size, fruit.center));
|
|
113
|
-
} else {
|
|
114
|
-
if (item.kind === 'bomb') {
|
|
115
|
-
add(m.bomb, fitted(m.bomb, size * 0.92));
|
|
116
|
-
const spark = world.spawn({
|
|
117
|
-
mesh: m.spark,
|
|
118
|
-
parent: root,
|
|
119
|
-
position: [size * 0.2, size * 0.36, 0],
|
|
120
|
-
scale: size * 0.1,
|
|
121
|
-
color: SPARK,
|
|
122
|
-
pickable: false
|
|
123
|
-
});
|
|
124
|
-
world.animate(spark, { scale: size * 0.16 }, { duration: 0.12, repeat: 'forever', yoyo: true });
|
|
125
|
-
} else {
|
|
126
|
-
add(m.star, fitted(m.star, size * 0.95), toColor(STAR_COLORS[0]));
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return root;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const itemPosition: [number, number, number] = [0, 0, 0];
|
|
133
|
-
export function placeItem(world: World, v: View3D, root: Entity, x: number, y: number, updates?: TransformBatch) {
|
|
134
|
-
const k = pointSize(v);
|
|
135
|
-
const dy = (v.height / 2 - y) * k;
|
|
136
|
-
itemPosition[0] = v.eye[0] + v.forward[0] * v.playDepth + (x - v.width / 2) * k;
|
|
137
|
-
itemPosition[1] = v.eye[1] + v.forward[1] * v.playDepth + dy * v.up[1];
|
|
138
|
-
itemPosition[2] = v.eye[2] + v.forward[2] * v.playDepth + dy * v.up[2];
|
|
139
|
-
if (updates) updates.position(root, itemPosition[0], itemPosition[1], itemPosition[2]);
|
|
140
|
-
else world.set(root, { position: itemPosition });
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// ── Slicing ───────────────────────────────────────────────────────────
|
|
144
|
-
|
|
145
|
-
const SPLASH_FRUIT = (juice: Color): Color[] => [juice, [Math.min(1, juice[0] + 0.25), Math.min(1, juice[1] + 0.25), Math.min(1, juice[2] + 0.25)]];
|
|
146
|
-
const BOMB_BURST = BOMB_COLORS.map((c) => toColor(c));
|
|
147
|
-
const STAR_BURST = STAR_COLORS.map((c) => toColor(c));
|
|
148
|
-
const STAR_SPARK = toColor(lighten(STAR_COLORS[0], 0.5));
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* The blade cuts an item at screen (x, y), moving (vx, vy) points per frame, along screen direction
|
|
152
|
-
* (dx, dy). A fruit falls apart in two halves split along the stroke, pushed apart and tumbling, under a
|
|
153
|
-
* splash of its juice; a star bursts into gold; a bomb explodes.
|
|
154
|
-
*/
|
|
155
|
-
export function sliceItem(
|
|
156
|
-
world: World,
|
|
157
|
-
v: View3D,
|
|
158
|
-
l: Layout,
|
|
159
|
-
m: Models,
|
|
160
|
-
root: Entity,
|
|
161
|
-
item: ItemKind,
|
|
162
|
-
x: number,
|
|
163
|
-
y: number,
|
|
164
|
-
vx: number,
|
|
165
|
-
vy: number,
|
|
166
|
-
dx: number,
|
|
167
|
-
dy: number
|
|
168
|
-
) {
|
|
169
|
-
world.despawn(root);
|
|
170
|
-
const k = pointSize(v);
|
|
171
|
-
const size = l.size * k;
|
|
172
|
-
const centre = at(v, x, y);
|
|
173
|
-
const near = at(v, x, y, PLAY_DEPTH - size * 0.5); // just in front of it, toward the camera
|
|
174
|
-
const fall = l.gravity * PER_SECOND * PER_SECOND; // points per second², down the screen
|
|
175
|
-
const gravity = planeVector(v, 0, fall);
|
|
176
|
-
if (item.kind === 'fruit') {
|
|
177
|
-
const fruit = m.fruits[item.fruit];
|
|
178
|
-
// The cut runs along the stroke; the halves part across it (the normal, in screen points, y down)
|
|
179
|
-
const len = Math.hypot(dx, dy) || 1;
|
|
180
|
-
const nx = dy / len;
|
|
181
|
-
const ny = -dx / len;
|
|
182
|
-
const cut = facing(v, Math.atan2(-ny, nx));
|
|
183
|
-
const f = fitted(fruit.whole, size, fruit.center);
|
|
184
|
-
[-1, 1].forEach((side, i) => {
|
|
185
|
-
const half = world.spawn({
|
|
186
|
-
mesh: 'none',
|
|
187
|
-
position: centre,
|
|
188
|
-
// pieces[0] turned so its cut faces +x is the left half; pieces[1] the other way
|
|
189
|
-
rotation: quat.multiply(cut, quat.y(side < 0 ? Math.PI / 2 : -Math.PI / 2)),
|
|
190
|
-
velocity: planeVector(v, (vx + side * nx * PIECE_SPREAD) * PER_SECOND, (vy + side * ny * PIECE_SPREAD) * PER_SECOND),
|
|
191
|
-
acceleration: gravity,
|
|
192
|
-
spin: [0, 0, side * 2.5],
|
|
193
|
-
lifetime: PIECE_LIFETIME,
|
|
194
|
-
pickable: false
|
|
195
|
-
});
|
|
196
|
-
world.spawn({ mesh: fruit.pieces[i]!, parent: half, position: f.position, scale: f.scale, color: WHITE, pickable: false });
|
|
197
|
-
});
|
|
198
|
-
effects.splash(world, {
|
|
199
|
-
position: near,
|
|
200
|
-
count: 14,
|
|
201
|
-
size: size * 0.09,
|
|
202
|
-
speed: size * 5,
|
|
203
|
-
lifetime: 0.55,
|
|
204
|
-
gravity: -fall * k * 0.6,
|
|
205
|
-
colors: SPLASH_FRUIT(fruit.juice)
|
|
206
|
-
});
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
const bomb = item.kind === 'bomb';
|
|
210
|
-
if (bomb)
|
|
211
|
-
effects.explosion(world, {
|
|
212
|
-
position: near,
|
|
213
|
-
count: 16,
|
|
214
|
-
size: size * 0.7,
|
|
215
|
-
speed: size * 2.6,
|
|
216
|
-
lifetime: 0.6,
|
|
217
|
-
gravity: -fall * k * 0.5,
|
|
218
|
-
debris: BOMB_BURST,
|
|
219
|
-
flash: false
|
|
220
|
-
});
|
|
221
|
-
else
|
|
222
|
-
effects.sparkle(world, {
|
|
223
|
-
position: near,
|
|
224
|
-
count: 16,
|
|
225
|
-
size: size * 0.1,
|
|
226
|
-
speed: size * 6,
|
|
227
|
-
lifetime: 0.6,
|
|
228
|
-
gravity: -fall * k * 0.3,
|
|
229
|
-
colors: STAR_BURST,
|
|
230
|
-
flash: false
|
|
231
|
-
});
|
|
232
|
-
// A flash that swells and fades, facing the camera: orange for the bomb, white-gold for the star
|
|
233
|
-
const flash = world.spawn({
|
|
234
|
-
mesh: m.disc,
|
|
235
|
-
position: at(v, x, y, PLAY_DEPTH - size),
|
|
236
|
-
rotation: facing(v),
|
|
237
|
-
scale: size,
|
|
238
|
-
color: bomb ? [2, 1.1, 0.3, 0.85] : [STAR_SPARK[0] * 2, STAR_SPARK[1] * 2, STAR_SPARK[2] * 2, 0.8],
|
|
239
|
-
pickable: false
|
|
240
|
-
});
|
|
241
|
-
world.animate(flash, { scale: size * (bomb ? 3.2 : 2.2), color: [2, bomb ? 0.8 : 1.8, 0.2, 0] }, { duration: bomb ? 0.4 : 0.3 }).then(() => {
|
|
242
|
-
if (world.has(flash)) world.despawn(flash);
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// ── Blade trail ───────────────────────────────────────────────────────
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* The blade's trail, as Falling Sticks draws its finger: glowing beads through the last touch points,
|
|
250
|
-
* shrinking toward the tail. It remembers how many beads are showing and whether they are fading, so a
|
|
251
|
-
* redraw sets only the beads that change (one native call each) and stops animations only after a fade.
|
|
252
|
-
*/
|
|
253
|
-
export type Trail = { beads: Entity[]; shown: number; fading: boolean };
|
|
254
|
-
|
|
255
|
-
const BEAD_SIZE = 7; // points, the newest bead
|
|
256
|
-
// Self-lit white (channels above 1), so the sun and the night don't shade it
|
|
257
|
-
const BEAD: Color = [1.6, 1.6, 1.6, 0.75];
|
|
258
|
-
const FADED: Color = [1.6, 1.6, 1.6, 0];
|
|
259
|
-
|
|
260
|
-
export function spawnTrail(world: World): Trail {
|
|
261
|
-
return {
|
|
262
|
-
beads: Array.from({ length: BLADE_POINTS }, () => world.spawn({ mesh: 'sphere', scale: HIDDEN, color: BEAD, pickable: false })),
|
|
263
|
-
shown: 0,
|
|
264
|
-
fading: false
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/** Draws the trail through the first `n` points of `xs`, `ys` (screen points, oldest first). */
|
|
269
|
-
export function drawTrail(world: World, v: View3D, t: Trail, xs: ArrayLike<number>, ys: ArrayLike<number>, n: number) {
|
|
270
|
-
const updates = world.transforms;
|
|
271
|
-
const count = Math.min(n, t.beads.length);
|
|
272
|
-
if (t.fading) {
|
|
273
|
-
for (let i = 0; i < t.shown; i++) world.stopAnimation(t.beads[i]!);
|
|
274
|
-
t.fading = false;
|
|
275
|
-
}
|
|
276
|
-
// `at` inlined: the plane's centre and metres per point once, then no allocation per bead
|
|
277
|
-
const m = pointSize(v, TRAIL_DEPTH);
|
|
278
|
-
const centre = at(v, v.width / 2, v.height / 2, TRAIL_DEPTH);
|
|
279
|
-
const size = BEAD_SIZE * m;
|
|
280
|
-
for (let i = 0; i < count; i++) {
|
|
281
|
-
const j = n - 1 - i;
|
|
282
|
-
const dx = (xs[j]! - v.width / 2) * m;
|
|
283
|
-
const dy = (v.height / 2 - ys[j]!) * m;
|
|
284
|
-
const bead = t.beads[i]!;
|
|
285
|
-
updates.position(bead, centre[0] + dx, centre[1] + dy * v.up[1], centre[2] + dy * v.up[2]);
|
|
286
|
-
updates.scale(bead, size * (1 - i / BLADE_POINTS));
|
|
287
|
-
updates.color(bead, BEAD[0], BEAD[1], BEAD[2], BEAD[3] ?? 1);
|
|
288
|
-
}
|
|
289
|
-
for (let i = count; i < t.shown; i++) updates.scale(t.beads[i]!, HIDDEN);
|
|
290
|
-
t.shown = count;
|
|
291
|
-
updates.flush();
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/** The finger lifted: the trail shrinks and fades out where it is. */
|
|
295
|
-
export function fadeTrail(world: World, t: Trail) {
|
|
296
|
-
if (!t.shown) return;
|
|
297
|
-
world.animate(t.beads.slice(0, t.shown), { color: FADED, scale: HIDDEN }, { duration: TRAIL_FADE });
|
|
298
|
-
t.fading = true;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
export function hideTrail(world: World, t: Trail) {
|
|
302
|
-
const updates = world.transforms;
|
|
303
|
-
for (let i = 0; i < t.shown; i++) {
|
|
304
|
-
if (t.fading) world.stopAnimation(t.beads[i]!);
|
|
305
|
-
updates.scale(t.beads[i]!, HIDDEN);
|
|
306
|
-
}
|
|
307
|
-
updates.flush();
|
|
308
|
-
t.shown = 0;
|
|
309
|
-
t.fading = false;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
export function removeTrail(world: World, t: Trail) {
|
|
313
|
-
for (const e of t.beads) world.despawn(e);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/** Reusable assets; the game loader advances one builder per frame. */
|
|
317
|
-
export function* warmAssets(): Iterable<() => unknown> {
|
|
318
|
-
yield () => buildModels({} as Record<FruitKind, Fruit>);
|
|
319
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
// Fruit Ninja's world: the shared 3D meadow (EngineMeadow) framed for it. The camera stands at eye
|
|
2
|
-
// height with the horizon a little below the middle of the screen, and the fruit fly on a plane 3.6 m
|
|
3
|
-
// ahead, close enough that the ground never passes in front of them. The big oak and pine frame the
|
|
4
|
-
// play area, with grass and flowers right in front.
|
|
5
|
-
import type { Entity, World } from '@nayan-ui/engine';
|
|
6
|
-
import type { GameTheme } from '../../services/ThemeService';
|
|
7
|
-
import { makeView as meadowView, spawnWorld as spawnMeadow, type View3D } from '../shared/EngineMeadow';
|
|
8
|
-
|
|
9
|
-
export { at, backgroundFor, cameraFor, facing, lightFor, planeVector, pointSize, type View3D } from '../shared/EngineMeadow';
|
|
10
|
-
|
|
11
|
-
/** Metres from the eye to the play plane. */
|
|
12
|
-
export const PLAY_DEPTH = 3.6;
|
|
13
|
-
|
|
14
|
-
export const makeView = (width: number, height: number): View3D =>
|
|
15
|
-
meadowView(width, height, { eyeHeight: 1.6, horizon: 0.62, playDepth: PLAY_DEPTH });
|
|
16
|
-
|
|
17
|
-
export const spawnWorld = (world: World, v: View3D, theme: GameTheme): Entity[] => spawnMeadow(world, v, theme);
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
// 2048's screen, on the Nayan engine: the board and its tiles are one 3D scene (an orthographic camera
|
|
2
|
-
// leaning back over the board), under Playtura's scoreboard, controls and modals. The play is in
|
|
3
|
-
// Game2048Game.ts (the grid's rules in Game2048Rules.ts), what it draws in Game2048Scene.ts.
|
|
4
|
-
//
|
|
5
|
-
// One world serves the whole visit: Start, Stop and Play Again reset it in place and a theme change
|
|
6
|
-
// rebuilds just the board, so the GPU view is never rebuilt. Tiles glide, merge and pop in the engine's
|
|
7
|
-
// Rust core; JS reads the swipe and steps the clock and the world once a frame.
|
|
8
|
-
import { HapticType } from '../../services/HapticsService';
|
|
9
|
-
import { GAME_SOUNDS } from '../../services/SoundsService';
|
|
10
|
-
import { GAME_IDS, isTablet } from '../../services/UtilsService';
|
|
11
|
-
import { engineGame, EngineGameScreen } from '../shared/EngineGameScreen';
|
|
12
|
-
import { timerColumn } from '../shared/EngineHud';
|
|
13
|
-
import { useEngineGame } from '../shared/useEngineGame';
|
|
14
|
-
import { useLiveState } from '../shared/useLiveState';
|
|
15
|
-
import { GAME_TIME, getLayout, LIGHT } from './Game2048Constants';
|
|
16
|
-
import { createGame, dispose, drag, type GameEvent, reset, type Result, setLayout, setTheme, start, tick } from './Game2048Game';
|
|
17
|
-
|
|
18
|
-
const SOUNDS = GAME_SOUNDS.GAME_2048;
|
|
19
|
-
|
|
20
|
-
/** Each event's sound and haptic, as the original store played them. */
|
|
21
|
-
const FEEDBACK: Record<GameEvent, { sound: (typeof SOUNDS)[keyof typeof SOUNDS]; haptic: HapticType }> = {
|
|
22
|
-
move: { sound: SOUNDS.TILE_MOVE, haptic: HapticType.LIGHT },
|
|
23
|
-
merge: { sound: SOUNDS.TILE_MERGE, haptic: HapticType.MEDIUM },
|
|
24
|
-
invalid: { sound: SOUNDS.INVALID_MOVE, haptic: HapticType.WARNING },
|
|
25
|
-
win: { sound: SOUNDS.WIN, haptic: HapticType.SUCCESS },
|
|
26
|
-
stuck: { sound: SOUNDS.GAME_OVER, haptic: HapticType.ERROR }
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
/** The game-over card for each ending: title, message, score label, button. */
|
|
30
|
-
const CARDS: Record<Result, { title: string; message: string; label: string; button: string }> = {
|
|
31
|
-
win: { title: 'YOU WON!', message: 'You reached 1024!', label: 'Score', button: 'Continue Playing!' },
|
|
32
|
-
timeout: { title: 'TIME UP!', message: 'You ran out of time!', label: "Time's Up!", button: 'Play Again!' },
|
|
33
|
-
stuck: { title: 'NO MOVES LEFT!', message: 'The board is full!', label: 'Board Full!', button: 'Play Again!' }
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export const Game2048 = engineGame(GAME_IDS.GAME_2048, (props) => {
|
|
37
|
-
const [time, setTime] = useLiveState(GAME_TIME);
|
|
38
|
-
|
|
39
|
-
// A win (scored by the time left) or a loss as it ends
|
|
40
|
-
const { game, theme, status, screen, gameOver } = useEngineGame(props, {
|
|
41
|
-
gameId: GAME_IDS.GAME_2048,
|
|
42
|
-
create: createGame,
|
|
43
|
-
start,
|
|
44
|
-
reset,
|
|
45
|
-
dispose,
|
|
46
|
-
tick,
|
|
47
|
-
setTheme,
|
|
48
|
-
resize: (g, width, height, offset) => {
|
|
49
|
-
const l = getLayout(width, height, offset, isTablet);
|
|
50
|
-
setLayout(g, l);
|
|
51
|
-
return l.size + l.pad * 2;
|
|
52
|
-
},
|
|
53
|
-
drag,
|
|
54
|
-
outcome: (g) => (g.result === 'win' ? 'win' : 'lose'),
|
|
55
|
-
sounds: SOUNDS,
|
|
56
|
-
onStart: (fx) => fx(SOUNDS.START, HapticType.SELECTION),
|
|
57
|
-
onStop: (fx) => fx(null, HapticType.SELECTION),
|
|
58
|
-
onOver: (fx, _status, g) => {
|
|
59
|
-
if (g.result === 'timeout') fx(SOUNDS.TIME_UP, HapticType.ERROR);
|
|
60
|
-
},
|
|
61
|
-
wire: (g, fx) => {
|
|
62
|
-
g.onTime = setTime;
|
|
63
|
-
g.onEvent = (event) => fx(FEEDBACK[event].sound, FEEDBACK[event].haptic);
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
const card = CARDS[game.result ?? 'timeout'];
|
|
68
|
-
|
|
69
|
-
return (
|
|
70
|
-
<EngineGameScreen
|
|
71
|
-
{...screen}
|
|
72
|
-
light={LIGHT}
|
|
73
|
-
columns={[timerColumn(time, theme, 0)]}
|
|
74
|
-
subtext="Swipe to play"
|
|
75
|
-
gameOver={gameOver({
|
|
76
|
-
title: card.title,
|
|
77
|
-
message: card.message,
|
|
78
|
-
scoreLabel: card.label,
|
|
79
|
-
score: status === 'win' ? game.score : 0,
|
|
80
|
-
buttonText: card.button
|
|
81
|
-
})}
|
|
82
|
-
/>
|
|
83
|
-
);
|
|
84
|
-
});
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
// 2048's timings, colors and layout. The rules (in Game2048Rules.ts), the clock and the score match the
|
|
2
|
-
// original version (games/game-2048), 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_TIME = 900; // seconds: 15 minutes
|
|
10
|
-
export const MIN_SWIPE = 50; // points a finger must travel, as the original swipe
|
|
11
|
-
export const SLIDE_TIME = 0.11; // tiles gliding to their cells, as the original slide
|
|
12
|
-
export const MERGE_POP = 1.18;
|
|
13
|
-
|
|
14
|
-
// ── Colors ────────────────────────────────────────────────────────────
|
|
15
|
-
|
|
16
|
-
/** Each value's tile and number colors, as the original tiles (8192 and up share the dark one). */
|
|
17
|
-
const TILES: Record<number, [string, string]> = {
|
|
18
|
-
2: ['#eee4da', '#776e65'],
|
|
19
|
-
4: ['#ede0c8', '#776e65'],
|
|
20
|
-
8: ['#f2b179', '#f9f6f2'],
|
|
21
|
-
16: ['#f59563', '#f9f6f2'],
|
|
22
|
-
32: ['#f67c5f', '#f9f6f2'],
|
|
23
|
-
64: ['#f65e3b', '#f9f6f2'],
|
|
24
|
-
128: ['#edcf72', '#f9f6f2'],
|
|
25
|
-
256: ['#edcc61', '#f9f6f2'],
|
|
26
|
-
512: ['#edc850', '#f9f6f2'],
|
|
27
|
-
1024: ['#edc53f', '#f9f6f2'],
|
|
28
|
-
2048: ['#edc22e', '#f9f6f2'],
|
|
29
|
-
4096: ['#3c3a32', '#f9f6f2']
|
|
30
|
-
};
|
|
31
|
-
export const tileColors = (value: number): [string, string] => TILES[value] ?? TILES[4096]!;
|
|
32
|
-
|
|
33
|
-
export const COLORS = {
|
|
34
|
-
// The wooden board (classic), as the original board
|
|
35
|
-
FRAME: '#5c4033',
|
|
36
|
-
SLOT: '#3d2a1f'
|
|
37
|
-
} as const;
|
|
38
|
-
|
|
39
|
-
// ── The scene ─────────────────────────────────────────────────────────
|
|
40
|
-
|
|
41
|
-
/** The camera looks straight down at the board. */
|
|
42
|
-
export const TILT = 0;
|
|
43
|
-
/** Evenly lit, straight from the camera and all ambient: every face keeps its exact color, with no shading or shadow anywhere. */
|
|
44
|
-
export const LIGHT = frontLight([0, 0, 1], 1);
|
|
45
|
-
/** A tile's height, of its width. */
|
|
46
|
-
export const TILE_HEIGHT = 0.4;
|
|
47
|
-
|
|
48
|
-
// ── Layout (view points) ──────────────────────────────────────────────
|
|
49
|
-
|
|
50
|
-
const SCOREBOARD_HEIGHT = 82;
|
|
51
|
-
const CONTROLS_HEIGHT = 120;
|
|
52
|
-
|
|
53
|
-
export type Layout = TiltView & { tile: number; gap: number; pitch: number; pad: number; size: number };
|
|
54
|
-
|
|
55
|
-
/** The grid as wide as the game area (30 narrower than the screen, at most 500), smaller if the screen is short. */
|
|
56
|
-
export function getLayout(width: number, height: number, offset: number, tablet: boolean): Layout {
|
|
57
|
-
const gap = 3;
|
|
58
|
-
const pad = tablet ? 10 : 8;
|
|
59
|
-
const top = getScoreBoardTop(offset) + SCOREBOARD_HEIGHT;
|
|
60
|
-
const room = Math.max(180, height - top - CONTROLS_HEIGHT);
|
|
61
|
-
const board = Math.max(180, Math.min(gameWidthFor(width), room / Math.cos(TILT) - 30));
|
|
62
|
-
const tile = Math.floor((board - pad * 2 - gap * 6) / 5);
|
|
63
|
-
const size = tile * 5 + gap * 6;
|
|
64
|
-
return { width, height, tilt: TILT, centerY: top + room / 2, tile, gap, pitch: tile + gap, pad, size };
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** A cell's centre on the board (row 0 along the top), in world units. */
|
|
68
|
-
export const cellCentre = (l: Layout, row: number, col: number): [number, number] => [(col - 2) * l.pitch, (2 - row) * l.pitch];
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
// 2048's play, with no React: build a game with `createGame`, give it a layout, `start` it and `tick` it
|
|
2
|
-
// every frame. Swipe to slide every tile one way: equal tiles that meet merge. A new tile lands after
|
|
3
|
-
// every slide that moves something. Reach 1024 inside fifteen minutes to win; running out of time, or
|
|
4
|
-
// of moves, ends the game.
|
|
5
|
-
//
|
|
6
|
-
// The grid's rules are the original service's (Game2048Rules.ts); the store's scoring, sounds and timer
|
|
7
|
-
// are kept: a win scores by the time left, the clock runs on the game's own clock.
|
|
8
|
-
import { type Camera, type DragEvent, World } from '@nayan-ui/engine';
|
|
9
|
-
import { calculateTimeBasedScore } from '../../services/ScoringService';
|
|
10
|
-
import type { GameTheme } from '../../services/ThemeService';
|
|
11
|
-
import { aimTilted } from '../shared/EngineTilt';
|
|
12
|
-
import { GAME_TIME, type Layout, MIN_SWIPE } from './Game2048Constants';
|
|
13
|
-
import { addRandomTile, type Direction, emptyGrid, type Grid, moveTiles, reached, stuck, tilesOf } from './Game2048Rules';
|
|
14
|
-
import { buildScene, bump, celebrate, dim, removeScene, resetTiles, type Scene, setSceneTheme, slideTiles } from './Game2048Scene';
|
|
15
|
-
|
|
16
|
-
export type Phase = 'ready' | 'playing' | 'over';
|
|
17
|
-
/** How a game ended. */
|
|
18
|
-
export type Result = 'win' | 'timeout' | 'stuck';
|
|
19
|
-
/** move / merge: a slide (and whether it merged); invalid: a swipe that moved nothing; win / stuck: how a slide ended it. */
|
|
20
|
-
export type GameEvent = 'move' | 'merge' | 'invalid' | 'win' | 'stuck';
|
|
21
|
-
|
|
22
|
-
const WORLD_CAPACITY = 400; // the board and 25 slots, up to 25 tiles with their digits and as many sliding out, and the confetti
|
|
23
|
-
|
|
24
|
-
/** A fresh board with its two starting tiles (ids 1 and 2). */
|
|
25
|
-
function freshGrid(): { grid: Grid; nextId: number } {
|
|
26
|
-
const grid = emptyGrid();
|
|
27
|
-
addRandomTile(grid, 1);
|
|
28
|
-
addRandomTile(grid, 2);
|
|
29
|
-
return { grid, nextId: 3 };
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function createGame(theme: GameTheme) {
|
|
33
|
-
const world = new World(WORLD_CAPACITY);
|
|
34
|
-
const camera: Camera = { eye: [0, 0, 240], target: [0, 0, 0], fov: 1, ortho: 1 };
|
|
35
|
-
const { grid, nextId } = freshGrid();
|
|
36
|
-
const g = {
|
|
37
|
-
world,
|
|
38
|
-
camera,
|
|
39
|
-
theme,
|
|
40
|
-
layout: null as Layout | null,
|
|
41
|
-
scene: null as Scene | null,
|
|
42
|
-
phase: 'ready' as Phase,
|
|
43
|
-
grid,
|
|
44
|
-
nextId,
|
|
45
|
-
result: null as Result | null,
|
|
46
|
-
/** Score and the countdown live in the engine (Rust), advanced by world.update. */
|
|
47
|
-
get score() {
|
|
48
|
-
return world.scoreboard.score;
|
|
49
|
-
},
|
|
50
|
-
get timeLeft() {
|
|
51
|
-
return world.scoreboard.shownSeconds;
|
|
52
|
-
},
|
|
53
|
-
/** A finger down, and whether its swipe has been taken. */
|
|
54
|
-
press: null as { swiped: boolean } | null,
|
|
55
|
-
// UI hooks, set by the screen.
|
|
56
|
-
onPhase: (_p: Phase) => {},
|
|
57
|
-
onTime: (_t: number) => {},
|
|
58
|
-
onEvent: (_e: GameEvent) => {}
|
|
59
|
-
};
|
|
60
|
-
world.scoreboard.reset(0, GAME_TIME);
|
|
61
|
-
world.scoreboard.handlers = {
|
|
62
|
-
onSecond: (t) => g.onTime(t),
|
|
63
|
-
onTimeUp: () => g.phase === 'playing' && end(g, 'timeout')
|
|
64
|
-
};
|
|
65
|
-
return g;
|
|
66
|
-
}
|
|
67
|
-
export type Game = ReturnType<typeof createGame>;
|
|
68
|
-
|
|
69
|
-
// ── Scene ─────────────────────────────────────────────────────────────
|
|
70
|
-
|
|
71
|
-
/** Lays the board out for the view (first layout, header height, rotation): rebuilt where things stand. */
|
|
72
|
-
export function setLayout(g: Game, l: Layout) {
|
|
73
|
-
if (g.scene) removeScene(g.world, g.scene);
|
|
74
|
-
g.layout = l;
|
|
75
|
-
aimTilted(g.camera, l);
|
|
76
|
-
g.scene = buildScene(g.world, l, g.theme, tilesOf(g.grid));
|
|
77
|
-
if (g.phase === 'over' && g.result !== 'win') dim(g.world, g.scene);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function setTheme(g: Game, theme: GameTheme) {
|
|
81
|
-
g.theme = theme;
|
|
82
|
-
if (g.layout && g.scene) setSceneTheme(g.world, g.layout, g.scene, theme);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// ── Run ───────────────────────────────────────────────────────────────
|
|
86
|
-
|
|
87
|
-
/** Starts on the board already shown, with fifteen minutes on the clock. */
|
|
88
|
-
export function start(g: Game) {
|
|
89
|
-
if (g.phase !== 'ready') return;
|
|
90
|
-
g.world.scoreboard.reset();
|
|
91
|
-
g.world.scoreboard.startCountdown(GAME_TIME);
|
|
92
|
-
g.result = null;
|
|
93
|
-
g.phase = 'playing';
|
|
94
|
-
g.onTime(GAME_TIME);
|
|
95
|
-
g.onPhase('playing');
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/** A fresh board, not started (Stop, Play Again, as the original game re-dealt both). */
|
|
99
|
-
export function reset(g: Game) {
|
|
100
|
-
const { grid, nextId } = freshGrid();
|
|
101
|
-
g.grid = grid;
|
|
102
|
-
g.nextId = nextId;
|
|
103
|
-
g.result = null;
|
|
104
|
-
g.world.scoreboard.reset(0, GAME_TIME);
|
|
105
|
-
g.press = null;
|
|
106
|
-
g.phase = 'ready';
|
|
107
|
-
if (g.layout && g.scene) resetTiles(g.world, g.layout, g.scene, tilesOf(grid));
|
|
108
|
-
g.onTime(GAME_TIME);
|
|
109
|
-
g.onPhase('ready');
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export function dispose(g: Game) {
|
|
113
|
-
g.world.dispose();
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export function tick(g: Game, dt: number) {
|
|
117
|
-
if (g.world.isDisposed) return;
|
|
118
|
-
g.world.update(dt);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function end(g: Game, result: Result) {
|
|
122
|
-
g.world.scoreboard.stop();
|
|
123
|
-
g.result = result;
|
|
124
|
-
g.phase = 'over';
|
|
125
|
-
g.press = null;
|
|
126
|
-
if (g.layout && g.scene) {
|
|
127
|
-
if (result === 'win') celebrate(g.world, g.layout, g.scene);
|
|
128
|
-
else dim(g.world, g.scene);
|
|
129
|
-
}
|
|
130
|
-
g.onPhase('over');
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// ── Moves ─────────────────────────────────────────────────────────────
|
|
134
|
-
|
|
135
|
-
/** A slide one way, as the original store made it: a new tile if anything moved, then the win and stuck checks. */
|
|
136
|
-
export function move(g: Game, direction: Direction) {
|
|
137
|
-
if (g.phase !== 'playing') return;
|
|
138
|
-
const { moved, score, ghosts } = moveTiles(g.grid, direction);
|
|
139
|
-
const { layout: l, scene: s } = g;
|
|
140
|
-
if (!moved) {
|
|
141
|
-
if (l && s) bump(g.world, l, s);
|
|
142
|
-
g.onEvent('invalid');
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
addRandomTile(g.grid, g.nextId++);
|
|
146
|
-
const won = reached(g.grid);
|
|
147
|
-
const over = stuck(g.grid);
|
|
148
|
-
if (l && s) slideTiles(g.world, l, s, tilesOf(g.grid), ghosts);
|
|
149
|
-
g.onEvent('move');
|
|
150
|
-
if (score > 0) g.onEvent('merge');
|
|
151
|
-
if (won) {
|
|
152
|
-
// The time left against the fifteen minutes (on a base of 0)
|
|
153
|
-
g.world.scoreboard.set(calculateTimeBasedScore(g.timeLeft, GAME_TIME, 0));
|
|
154
|
-
g.onEvent('win');
|
|
155
|
-
end(g, 'win');
|
|
156
|
-
} else if (over) {
|
|
157
|
-
g.onEvent('stuck');
|
|
158
|
-
end(g, 'stuck');
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// ── The finger ────────────────────────────────────────────────────────
|
|
163
|
-
|
|
164
|
-
/** A swipe anywhere: taken the moment it's gone far enough (or on the lift), its longer way. */
|
|
165
|
-
export function drag(g: Game, { phase, dx, dy }: DragEvent) {
|
|
166
|
-
if (phase === 'start') {
|
|
167
|
-
g.press = { swiped: false };
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
const p = g.press;
|
|
171
|
-
if (!p || p.swiped) return;
|
|
172
|
-
const ax = Math.abs(dx);
|
|
173
|
-
const ay = Math.abs(dy);
|
|
174
|
-
let dir: Direction | null = null;
|
|
175
|
-
if (ax > ay && ax > MIN_SWIPE) dir = dx > 0 ? 'right' : 'left';
|
|
176
|
-
else if (ay > MIN_SWIPE) dir = dy > 0 ? 'down' : 'up';
|
|
177
|
-
if (phase === 'end') g.press = null;
|
|
178
|
-
if (!dir) return;
|
|
179
|
-
p.swiped = true;
|
|
180
|
-
move(g, dir);
|
|
181
|
-
}
|