@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,83 +0,0 @@
|
|
|
1
|
-
// Dots and Boxes' screen, on the Nayan engine: the board, studs, lines and claimed boxes are one 3D scene
|
|
2
|
-
// (an orthographic camera leaning back over the board), under Playtura's scoreboard, controls and
|
|
3
|
-
// modals. The rules and the AI are in DotsAndBoxesGame.ts, what it draws in DotsAndBoxesScene.ts.
|
|
4
|
-
//
|
|
5
|
-
// One world serves the whole visit: Start, Stop and Play Again reset it in place and a theme change
|
|
6
|
-
// repaints the board, so the GPU view is never rebuilt. Lines and boxes animate in the engine's Rust
|
|
7
|
-
// core; JS hit-tests taps and steps the AI's clock and the world once a frame.
|
|
8
|
-
import { HapticType } from '../../services/HapticsService';
|
|
9
|
-
import { GAME_SOUNDS } from '../../services/SoundsService';
|
|
10
|
-
import { GAME_IDS } from '../../services/UtilsService';
|
|
11
|
-
import { engineGame, EngineGameScreen } from '../shared/EngineGameScreen';
|
|
12
|
-
import { type HudColumn, textColumn } from '../shared/EngineHud';
|
|
13
|
-
import { useEngineGame } from '../shared/useEngineGame';
|
|
14
|
-
import { useLiveState } from '../shared/useLiveState';
|
|
15
|
-
import { getLayout, LIGHT, OPPONENT_COLOR, PLAYER_COLOR } from './DotsAndBoxesConstants';
|
|
16
|
-
import { createGame, dispose, reset, setLayout, setTheme, start, tap, tick, type Turn } from './DotsAndBoxesGame';
|
|
17
|
-
|
|
18
|
-
const SOUNDS = GAME_SOUNDS.DOTS_AND_BOXES;
|
|
19
|
-
|
|
20
|
-
const playerColumn = (label: string, color: string, score: number, active: boolean): HudColumn => ({
|
|
21
|
-
label,
|
|
22
|
-
value: score.toLocaleString(),
|
|
23
|
-
color: active ? color : undefined,
|
|
24
|
-
valueColor: color
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
export const DotsAndBoxes = engineGame(GAME_IDS.DOTS_AND_BOXES, (props) => {
|
|
28
|
-
const [scores, setScores] = useLiveState<[number, number]>([0, 0]);
|
|
29
|
-
const [turn, setTurn] = useLiveState<Turn>('player');
|
|
30
|
-
|
|
31
|
-
// Win or lose when the last line is drawn
|
|
32
|
-
const { status, screen, gameOver } = useEngineGame(props, {
|
|
33
|
-
gameId: GAME_IDS.DOTS_AND_BOXES,
|
|
34
|
-
create: createGame,
|
|
35
|
-
start,
|
|
36
|
-
reset,
|
|
37
|
-
dispose,
|
|
38
|
-
tick,
|
|
39
|
-
setTheme,
|
|
40
|
-
resize: (g, width, height, offset) => {
|
|
41
|
-
const l = getLayout(width, height, offset);
|
|
42
|
-
setLayout(g, l);
|
|
43
|
-
return l.boardSize;
|
|
44
|
-
},
|
|
45
|
-
tap,
|
|
46
|
-
reportScore: (g) => g.playerScore,
|
|
47
|
-
sounds: SOUNDS,
|
|
48
|
-
onStart: (fx) => fx(SOUNDS.START, HapticType.MEDIUM),
|
|
49
|
-
onOver: (fx, s) =>
|
|
50
|
-
fx(s === 'draw' ? GAME_SOUNDS.DRAW : s === 'win' ? SOUNDS.WIN : SOUNDS.LOSE, s === 'win' ? HapticType.SUCCESS : HapticType.HEAVY),
|
|
51
|
-
wire: (g, fx) => {
|
|
52
|
-
g.onScores = (player, opponent) => setScores([player, opponent]);
|
|
53
|
-
g.onTurn = setTurn;
|
|
54
|
-
g.onEvent = (event, who) => {
|
|
55
|
-
const mine = who === 'player';
|
|
56
|
-
if (event === 'box') fx(mine ? SOUNDS.BOX_CLAIMED : SOUNDS.OPPONENT_BOX, mine ? HapticType.MEDIUM : HapticType.WARNING);
|
|
57
|
-
else fx(mine ? SOUNDS.PLAYER_LINE : SOUNDS.OPPONENT_LINE, HapticType.LIGHT);
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
const yours = turn === 'player';
|
|
63
|
-
|
|
64
|
-
return (
|
|
65
|
-
<EngineGameScreen
|
|
66
|
-
{...screen}
|
|
67
|
-
light={LIGHT}
|
|
68
|
-
columns={[
|
|
69
|
-
playerColumn('YOU', PLAYER_COLOR, scores[0], yours),
|
|
70
|
-
textColumn('TURN', yours ? 'Your Turn' : 'AI Thinking...', yours ? PLAYER_COLOR : OPPONENT_COLOR),
|
|
71
|
-
playerColumn('AI', OPPONENT_COLOR, scores[1], !yours)
|
|
72
|
-
]}
|
|
73
|
-
subtext="Complete boxes to win!"
|
|
74
|
-
gameOver={gameOver({
|
|
75
|
-
title: status === 'win' ? 'YOU WON!' : 'YOU LOST!',
|
|
76
|
-
message: `Final score: ${scores[0]} - ${scores[1]}`,
|
|
77
|
-
scoreLabel: status === 'win' ? 'You Won!' : 'You Lost',
|
|
78
|
-
score: scores[0],
|
|
79
|
-
buttonText: status === 'win' ? 'Play Again!' : 'Try Again!'
|
|
80
|
-
})}
|
|
81
|
-
/>
|
|
82
|
-
);
|
|
83
|
-
});
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
// Dots and Boxes' rules, colors, timings and layout. The grid, rules, AI and scoring match the original
|
|
2
|
-
// version (games/dots-and-boxes), 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 ─────────────────────────────────────────────────────────────
|
|
8
|
-
|
|
9
|
-
export const GRID_SIZE = 6; // boxes a side (7 x 7 dots)
|
|
10
|
-
export const BOX_POINTS = 2000;
|
|
11
|
-
|
|
12
|
-
// ── Colors ────────────────────────────────────────────────────────────
|
|
13
|
-
|
|
14
|
-
export const PLAYER_COLOR = '#34D399';
|
|
15
|
-
export const OPPONENT_COLOR = '#F87171';
|
|
16
|
-
export const DOT_COLOR = '#D5DCE6'; // brushed steel studs
|
|
17
|
-
export const CLASSIC_BOARD = 'rgba(255, 255, 255, 0.25)';
|
|
18
|
-
export const CLASSIC_RIM = 'rgba(255, 255, 255, 0.3)';
|
|
19
|
-
export const CLASSIC_SLOT = 'rgba(255, 255, 255, 0.3)';
|
|
20
|
-
|
|
21
|
-
// ── Timings (seconds) ─────────────────────────────────────────────────
|
|
22
|
-
|
|
23
|
-
export const AI_FIRST_DELAY = 1; // after your move, before the AI's first line
|
|
24
|
-
export const AI_CHAIN_DELAY = 0.8; // between the AI's lines while it keeps closing boxes
|
|
25
|
-
export const LINE_TIME = 0.22; // a line rises and grows out from its middle
|
|
26
|
-
export const BOX_TIME = 0.32; // a claimed box rises out of the board
|
|
27
|
-
|
|
28
|
-
// ── The scene ─────────────────────────────────────────────────────────
|
|
29
|
-
|
|
30
|
-
/** The camera leans back this far from straight down, so the studs, rods and tiles read as 3D. */
|
|
31
|
-
export const TILT = 0.3;
|
|
32
|
-
/** Lit from the upper left; surfaces facing up off the board (+z) keep their exact color. */
|
|
33
|
-
export const LIGHT = frontLight([-0.4, 0.35, 1], 0.5);
|
|
34
|
-
|
|
35
|
-
// ── Layout (view points) ──────────────────────────────────────────────
|
|
36
|
-
|
|
37
|
-
const SCOREBOARD_HEIGHT = 82;
|
|
38
|
-
const CONTROLS_HEIGHT = 110;
|
|
39
|
-
const PADDING = 22; // from the board's edge to the outer dots, as the original board
|
|
40
|
-
|
|
41
|
-
export type Layout = TiltView & {
|
|
42
|
-
boardSize: number;
|
|
43
|
-
/** From the board's edge to the outer dots' centres. */
|
|
44
|
-
padding: number;
|
|
45
|
-
/** Between neighbouring dots. */
|
|
46
|
-
cell: number;
|
|
47
|
-
dotRadius: number;
|
|
48
|
-
lineWidth: number;
|
|
49
|
-
/** Height of the board's top face. */
|
|
50
|
-
boardTop: number;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
/** The board as wide as the game area, centred between the scoreboard and the controls. */
|
|
54
|
-
export function getLayout(width: number, height: number, offset: number): Layout {
|
|
55
|
-
const top = getScoreBoardTop(offset) + SCOREBOARD_HEIGHT;
|
|
56
|
-
const room = Math.max(200, height - top - CONTROLS_HEIGHT);
|
|
57
|
-
const boardSize = Math.min(gameWidthFor(width), room / Math.cos(TILT));
|
|
58
|
-
const cell = (boardSize - PADDING * 2) / GRID_SIZE;
|
|
59
|
-
return {
|
|
60
|
-
width,
|
|
61
|
-
height,
|
|
62
|
-
tilt: TILT,
|
|
63
|
-
centerY: top + room / 2,
|
|
64
|
-
boardSize,
|
|
65
|
-
padding: PADDING,
|
|
66
|
-
cell,
|
|
67
|
-
dotRadius: Math.max(6, cell * 0.12),
|
|
68
|
-
lineWidth: Math.max(6, cell * 0.12),
|
|
69
|
-
boardTop: 0
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/** A dot's centre on the board (row 0 along the top), in world units. */
|
|
74
|
-
export function dotPoint(l: Layout, row: number, col: number): [number, number] {
|
|
75
|
-
const half = l.boardSize / 2;
|
|
76
|
-
return [-half + l.padding + col * l.cell, half - l.padding - row * l.cell];
|
|
77
|
-
}
|
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
// Dots and Boxes' rules, with no React: build a game with `createGame`, give it a layout, `start` it and
|
|
2
|
-
// `tick` it every frame. You (green) and the AI (red) take turns drawing a line between two neighbouring
|
|
3
|
-
// dots; closing a box's fourth side claims it (2,000 points) and earns another line. When every line is
|
|
4
|
-
// drawn, you win with more boxes than the AI (a tie is a loss, as in the original version).
|
|
5
|
-
//
|
|
6
|
-
// The AI completes a box when it can, otherwise draws a line that doesn't hand you one, otherwise any
|
|
7
|
-
// line. Its moves wait on the game's own clock, advanced by `tick`: a reset drops what's pending, so
|
|
8
|
-
// nothing can land in the next game, and it all pauses with the view.
|
|
9
|
-
import { type Camera, type Entity, World } from '@nayan-ui/engine';
|
|
10
|
-
import type { GameTheme } from '../../services/ThemeService';
|
|
11
|
-
import { aimTilted, unproject } from '../shared/EngineTilt';
|
|
12
|
-
import { AI_CHAIN_DELAY, AI_FIRST_DELAY, BOX_POINTS, dotPoint, GRID_SIZE, type Layout } from './DotsAndBoxesConstants';
|
|
13
|
-
import {
|
|
14
|
-
type Board,
|
|
15
|
-
buildBoard,
|
|
16
|
-
celebrate,
|
|
17
|
-
type LineKind,
|
|
18
|
-
type Owner,
|
|
19
|
-
removeBoard,
|
|
20
|
-
setBoardTheme,
|
|
21
|
-
showSlot,
|
|
22
|
-
spawnRod,
|
|
23
|
-
spawnTile
|
|
24
|
-
} from './DotsAndBoxesScene';
|
|
25
|
-
|
|
26
|
-
export type Phase = 'ready' | 'playing' | 'over';
|
|
27
|
-
export type Turn = 'player' | 'opponent';
|
|
28
|
-
export type GameEvent = 'line' | 'box';
|
|
29
|
-
|
|
30
|
-
const G = GRID_SIZE;
|
|
31
|
-
const H_COUNT = (G + 1) * G; // horizontal lines: G + 1 rows of G
|
|
32
|
-
const LINE_COUNT = H_COUNT * 2; // and as many vertical: G rows of G + 1
|
|
33
|
-
const WORLD_CAPACITY = 800; // studs (49), grooves and rods (84 each), tiles (36), the board, and bursts
|
|
34
|
-
const MAX_STEP = 0.1;
|
|
35
|
-
const HIT_REACH = 0.4; // of a cell: how far from a line a tap still picks it
|
|
36
|
-
|
|
37
|
-
type Line = { kind: LineKind; row: number; col: number };
|
|
38
|
-
/** Every line, horizontal ones first (row by row), then vertical. */
|
|
39
|
-
const LINES: readonly Line[] = Array.from({ length: LINE_COUNT }, (_, i) =>
|
|
40
|
-
i < H_COUNT
|
|
41
|
-
? { kind: 'h', row: Math.floor(i / G), col: i % G }
|
|
42
|
-
: { kind: 'v', row: Math.floor((i - H_COUNT) / (G + 1)), col: (i - H_COUNT) % (G + 1) }
|
|
43
|
-
);
|
|
44
|
-
const hIndex = (row: number, col: number) => row * G + col;
|
|
45
|
-
const vIndex = (row: number, col: number) => H_COUNT + row * (G + 1) + col;
|
|
46
|
-
/** The (one or two) boxes each line borders. */
|
|
47
|
-
const BORDERS: readonly number[][] = LINES.map(({ kind, row, col }) => {
|
|
48
|
-
const boxes: number[] = [];
|
|
49
|
-
if (kind === 'h') {
|
|
50
|
-
if (row > 0) boxes.push((row - 1) * G + col);
|
|
51
|
-
if (row < G) boxes.push(row * G + col);
|
|
52
|
-
} else {
|
|
53
|
-
if (col > 0) boxes.push(row * G + col - 1);
|
|
54
|
-
if (col < G) boxes.push(row * G + col);
|
|
55
|
-
}
|
|
56
|
-
return boxes;
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
export function createGame(theme: GameTheme) {
|
|
60
|
-
const world = new World(WORLD_CAPACITY);
|
|
61
|
-
const camera: Camera = { eye: [0, 0, 240], target: [0, 0, 0], fov: 1, ortho: 1 };
|
|
62
|
-
return {
|
|
63
|
-
world,
|
|
64
|
-
camera,
|
|
65
|
-
theme,
|
|
66
|
-
layout: null as Layout | null,
|
|
67
|
-
board: null as Board | null,
|
|
68
|
-
phase: 'ready' as Phase,
|
|
69
|
-
turn: 'player' as Turn,
|
|
70
|
-
/** Who drew each line (0 = nobody yet). */
|
|
71
|
-
lines: new Uint8Array(LINE_COUNT),
|
|
72
|
-
/** Who claimed each box (0 = nobody yet). */
|
|
73
|
-
boxes: new Uint8Array(G * G),
|
|
74
|
-
sideCounts: new Uint8Array(G * G),
|
|
75
|
-
drawn: 0,
|
|
76
|
-
rods: [] as Entity[],
|
|
77
|
-
tiles: [] as Entity[],
|
|
78
|
-
playerScore: 0,
|
|
79
|
-
opponentScore: 0,
|
|
80
|
-
won: false,
|
|
81
|
-
// UI hooks, set by the screen.
|
|
82
|
-
onPhase: (_p: Phase) => {},
|
|
83
|
-
onScores: (_player: number, _opponent: number) => {},
|
|
84
|
-
onTurn: (_t: Turn) => {},
|
|
85
|
-
onEvent: (_e: GameEvent, _who: Turn) => {}
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
export type Game = ReturnType<typeof createGame>;
|
|
89
|
-
|
|
90
|
-
const after = (g: Game, seconds: number, run: () => void) => g.world.after(seconds, run);
|
|
91
|
-
const sidesDrawn = (g: Game, box: number) => g.sideCounts[box]!;
|
|
92
|
-
|
|
93
|
-
// ── Scene ─────────────────────────────────────────────────────────────
|
|
94
|
-
|
|
95
|
-
/** Lays the scene out for the view (first layout, header height, rotation): rebuilt from the game's state. */
|
|
96
|
-
export function setLayout(g: Game, l: Layout) {
|
|
97
|
-
clearPieces(g);
|
|
98
|
-
if (g.board) removeBoard(g.world, g.board);
|
|
99
|
-
g.layout = l;
|
|
100
|
-
aimTilted(g.camera, l);
|
|
101
|
-
g.board = buildBoard(g.world, l, g.theme, LINES);
|
|
102
|
-
// What's been played so far, without the animations
|
|
103
|
-
g.lines.forEach((owner, i) => owner && drawLine(g, i, owner as Owner, false));
|
|
104
|
-
g.boxes.forEach((owner, b) => owner && drawTile(g, b, owner as Owner, false));
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export function setTheme(g: Game, theme: GameTheme) {
|
|
108
|
-
g.theme = theme;
|
|
109
|
-
if (g.layout && g.board) setBoardTheme(g.world, g.layout, g.board, theme);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function clearPieces(g: Game) {
|
|
113
|
-
for (const e of [...g.rods, ...g.tiles]) g.world.despawn(e);
|
|
114
|
-
g.rods = [];
|
|
115
|
-
g.tiles = [];
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function drawLine(g: Game, i: number, owner: Owner, animate: boolean) {
|
|
119
|
-
const { layout: l, board: b } = g;
|
|
120
|
-
if (!l || !b) return;
|
|
121
|
-
const { kind, row, col } = LINES[i]!;
|
|
122
|
-
showSlot(g.world, b, i, false);
|
|
123
|
-
g.rods.push(spawnRod(g.world, l, kind, row, col, owner, animate));
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function drawTile(g: Game, box: number, owner: Owner, animate: boolean) {
|
|
127
|
-
if (!g.layout) return;
|
|
128
|
-
g.tiles.push(spawnTile(g.world, g.layout, Math.floor(box / G), box % G, owner, animate));
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// ── Run ───────────────────────────────────────────────────────────────
|
|
132
|
-
|
|
133
|
-
export function start(g: Game) {
|
|
134
|
-
if (g.phase !== 'ready') return;
|
|
135
|
-
g.phase = 'playing';
|
|
136
|
-
g.onPhase('playing');
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/** A fresh board (Stop, Play Again). The world, and the GPU view drawing it, are kept. */
|
|
140
|
-
export function reset(g: Game) {
|
|
141
|
-
g.world.cancelTimers();
|
|
142
|
-
clearPieces(g);
|
|
143
|
-
if (g.board) for (let i = 0; i < LINE_COUNT; i++) showSlot(g.world, g.board, i, true);
|
|
144
|
-
g.lines.fill(0);
|
|
145
|
-
g.sideCounts.fill(0);
|
|
146
|
-
g.boxes.fill(0);
|
|
147
|
-
g.drawn = 0;
|
|
148
|
-
g.turn = 'player';
|
|
149
|
-
g.playerScore = 0;
|
|
150
|
-
g.opponentScore = 0;
|
|
151
|
-
g.won = false;
|
|
152
|
-
g.phase = 'ready';
|
|
153
|
-
g.onScores(0, 0);
|
|
154
|
-
g.onTurn('player');
|
|
155
|
-
g.onPhase('ready');
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export function dispose(g: Game) {
|
|
159
|
-
g.world.dispose();
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export function tick(g: Game, dt: number) {
|
|
163
|
-
if (g.world.isDisposed) return;
|
|
164
|
-
g.world.update(Math.min(dt, MAX_STEP));
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// ── Moves ─────────────────────────────────────────────────────────────
|
|
168
|
-
|
|
169
|
-
/** The open line nearest a view point, if the point is close enough to it. */
|
|
170
|
-
export function lineAt(g: Game, x: number, y: number): number | null {
|
|
171
|
-
const l = g.layout;
|
|
172
|
-
if (!l) return null;
|
|
173
|
-
const [wx, wy] = unproject(l, x, y, 0);
|
|
174
|
-
const [ox, oy] = dotPoint(l, 0, 0);
|
|
175
|
-
// In cells from the top-left dot: c across, r down
|
|
176
|
-
const c = (wx - ox) / l.cell;
|
|
177
|
-
const r = (oy - wy) / l.cell;
|
|
178
|
-
let best: number | null = null;
|
|
179
|
-
let bestDistance = HIT_REACH;
|
|
180
|
-
const consider = (index: number, distance: number) => {
|
|
181
|
-
if (!g.lines[index] && distance < bestDistance) {
|
|
182
|
-
best = index;
|
|
183
|
-
bestDistance = distance;
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
const hr = Math.round(r);
|
|
187
|
-
const hc = Math.floor(c);
|
|
188
|
-
if (hr >= 0 && hr <= G && hc >= 0 && hc < G) consider(hIndex(hr, hc), Math.abs(r - hr));
|
|
189
|
-
const vr = Math.floor(r);
|
|
190
|
-
const vc = Math.round(c);
|
|
191
|
-
if (vr >= 0 && vr < G && vc >= 0 && vc <= G) consider(vIndex(vr, vc), Math.abs(c - vc));
|
|
192
|
-
return best;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/** A tap: draws the line under it on your turn. */
|
|
196
|
-
export function tap(g: Game, x: number, y: number) {
|
|
197
|
-
if (g.phase !== 'playing' || g.turn !== 'player') return;
|
|
198
|
-
const line = lineAt(g, x, y);
|
|
199
|
-
if (line == null) return;
|
|
200
|
-
const claimed = play(g, line, 'player');
|
|
201
|
-
if (g.phase !== 'playing' || claimed > 0) return;
|
|
202
|
-
setTurn(g, 'opponent');
|
|
203
|
-
after(g, AI_FIRST_DELAY, () => aiMove(g));
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/** Draws a line, claims any box it closes and scores it. Returns the boxes claimed. */
|
|
207
|
-
function play(g: Game, line: number, who: Turn): number {
|
|
208
|
-
const owner: Owner = who === 'player' ? 1 : 2;
|
|
209
|
-
g.lines[line] = owner;
|
|
210
|
-
g.drawn++;
|
|
211
|
-
drawLine(g, line, owner, true);
|
|
212
|
-
let claimed = 0;
|
|
213
|
-
for (const box of BORDERS[line]!) {
|
|
214
|
-
g.sideCounts[box]!++;
|
|
215
|
-
if (!g.boxes[box] && sidesDrawn(g, box) === 4) {
|
|
216
|
-
g.boxes[box] = owner;
|
|
217
|
-
drawTile(g, box, owner, true);
|
|
218
|
-
claimed++;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
if (who === 'player') g.playerScore += claimed * BOX_POINTS;
|
|
222
|
-
else g.opponentScore += claimed * BOX_POINTS;
|
|
223
|
-
if (claimed) g.onScores(g.playerScore, g.opponentScore);
|
|
224
|
-
g.onEvent(claimed ? 'box' : 'line', who);
|
|
225
|
-
if (g.drawn === LINE_COUNT) end(g);
|
|
226
|
-
return claimed;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
function aiMove(g: Game) {
|
|
230
|
-
if (g.phase !== 'playing' || g.turn !== 'opponent') return;
|
|
231
|
-
const line = chooseLine(g);
|
|
232
|
-
if (line == null) {
|
|
233
|
-
setTurn(g, 'player');
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
const claimed = play(g, line, 'opponent');
|
|
237
|
-
if (g.phase !== 'playing') return;
|
|
238
|
-
if (claimed > 0) after(g, AI_CHAIN_DELAY, () => aiMove(g));
|
|
239
|
-
else setTurn(g, 'player');
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/** Close a box if it can; otherwise a line that leaves no box on three sides; otherwise any line. */
|
|
243
|
-
function chooseLine(g: Game): number | null {
|
|
244
|
-
const open: number[] = [];
|
|
245
|
-
for (let i = 0; i < LINE_COUNT; i++) if (!g.lines[i]) open.push(i);
|
|
246
|
-
if (!open.length) return null;
|
|
247
|
-
const closing = open.find((i) => BORDERS[i]!.some((b) => sidesDrawn(g, b) === 3));
|
|
248
|
-
if (closing !== undefined) return closing;
|
|
249
|
-
const safe = open.filter((i) => BORDERS[i]!.every((b) => sidesDrawn(g, b) !== 2));
|
|
250
|
-
const pool = safe.length ? safe : open;
|
|
251
|
-
return pool[Math.floor(Math.random() * pool.length)]!;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
function setTurn(g: Game, turn: Turn) {
|
|
255
|
-
g.turn = turn;
|
|
256
|
-
g.onTurn(turn);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
function end(g: Game) {
|
|
260
|
-
g.world.cancelTimers();
|
|
261
|
-
let mine = 0;
|
|
262
|
-
let theirs = 0;
|
|
263
|
-
for (const owner of g.boxes) {
|
|
264
|
-
if (owner === 1) mine++;
|
|
265
|
-
else if (owner === 2) theirs++;
|
|
266
|
-
}
|
|
267
|
-
g.won = mine > theirs;
|
|
268
|
-
g.phase = 'over';
|
|
269
|
-
if (g.won && g.layout) celebrate(g.world, g.layout);
|
|
270
|
-
g.onPhase('over');
|
|
271
|
-
}
|
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
// Everything Dots and Boxes draws: a board panel (themed, as the original board) lying in the world's XY
|
|
2
|
-
// plane under a camera leaning back from straight down (shared/EngineTilt), one world unit per view
|
|
3
|
-
// point. Steel studs mark the dots; each open line is a faint groove between two studs; a played line
|
|
4
|
-
// is a glossy rod in its player's color that rises and grows out from its middle; a claimed box is a
|
|
5
|
-
// glossy tile rising out of the board. Studs, grooves, rods and tiles each share one mesh, so every kind
|
|
6
|
-
// is one instanced draw. Meshes are built once per size: mesh ids are app-wide and limited.
|
|
7
|
-
import { type Color, effects, type Entity, extrude, lathe, merge, type Model, Path, quat, shapeGeometry, tube, type World } from '@nayan-ui/engine';
|
|
8
|
-
import type { GameTheme } from '../../services/ThemeService';
|
|
9
|
-
import { setBackdropTheme, spawnBackdrop } from '../shared/EngineBackdrop';
|
|
10
|
-
import { cacheGameAsset, createGameMesh as createShape } from '../shared/EngineMeshes';
|
|
11
|
-
import { placeTiltedBackdrop } from '../shared/EngineTilt';
|
|
12
|
-
import { toColor } from '../shared/EngineUtils';
|
|
13
|
-
import {
|
|
14
|
-
BOX_TIME,
|
|
15
|
-
CLASSIC_BOARD,
|
|
16
|
-
CLASSIC_RIM,
|
|
17
|
-
CLASSIC_SLOT,
|
|
18
|
-
DOT_COLOR,
|
|
19
|
-
dotPoint,
|
|
20
|
-
GRID_SIZE,
|
|
21
|
-
type Layout,
|
|
22
|
-
LINE_TIME,
|
|
23
|
-
OPPONENT_COLOR,
|
|
24
|
-
PLAYER_COLOR
|
|
25
|
-
} from './DotsAndBoxesConstants';
|
|
26
|
-
|
|
27
|
-
export type Owner = 1 | 2; // you, the AI
|
|
28
|
-
export type LineKind = 'h' | 'v';
|
|
29
|
-
|
|
30
|
-
const meshes = new Map<string, Model>();
|
|
31
|
-
const cached = (key: string, build: () => Model) => {
|
|
32
|
-
let m = meshes.get(key);
|
|
33
|
-
if (!m) {
|
|
34
|
-
m = cacheGameAsset('dots-and-boxes/DotsAndBoxesScene:' + key, build);
|
|
35
|
-
meshes.set(key, m);
|
|
36
|
-
}
|
|
37
|
-
return m;
|
|
38
|
-
};
|
|
39
|
-
const STAND_UP = quat.x(Math.PI / 2);
|
|
40
|
-
const ACROSS = quat.z(0);
|
|
41
|
-
const DOWN = quat.z(Math.PI / 2);
|
|
42
|
-
const BOARD_DEPTH = 10;
|
|
43
|
-
const BACKDROP_DEPTH = 25;
|
|
44
|
-
const ownerColor = (o: Owner) => toColor(o === 1 ? PLAYER_COLOR : OPPONENT_COLOR);
|
|
45
|
-
const glow = (c: Color, k: number): Color => [c[0] * k, c[1] * k, c[2] * k, 1];
|
|
46
|
-
|
|
47
|
-
// ── Meshes ────────────────────────────────────────────────────────────
|
|
48
|
-
|
|
49
|
-
/** The board: a slab with rounded corners, its top face at z = 0. */
|
|
50
|
-
const panelMesh = (size: number, radius: number) =>
|
|
51
|
-
cached(`dab-panel:${size.toFixed(1)}:${radius}`, () =>
|
|
52
|
-
createShape(extrude(new Path().addRoundedRect(-size / 2, -size / 2, size, size, radius), { depth: BOARD_DEPTH }), { shine: 0.25 })
|
|
53
|
-
);
|
|
54
|
-
const rimMesh = (size: number, radius: number) =>
|
|
55
|
-
cached(`dab-rim:${size.toFixed(1)}:${radius}`, () =>
|
|
56
|
-
createShape(
|
|
57
|
-
extrude(
|
|
58
|
-
new Path()
|
|
59
|
-
.addRoundedRect(-size / 2, -size / 2, size, size, radius)
|
|
60
|
-
.addRoundedRect(-size / 2 + 1.5, -size / 2 + 1.5, size - 3, size - 3, radius - 1.5),
|
|
61
|
-
{ depth: 0, fillRule: 'evenodd' }
|
|
62
|
-
)
|
|
63
|
-
)
|
|
64
|
-
);
|
|
65
|
-
/** An open line: a flat rounded groove `length` long, along x. */
|
|
66
|
-
const slotMesh = (length: number, width: number) =>
|
|
67
|
-
cached(`dab-slot:${length.toFixed(1)}:${width.toFixed(1)}`, () =>
|
|
68
|
-
createShape(extrude(new Path().addRoundedRect(-length / 2, -width / 2, length, width, width / 2), { depth: 0 }))
|
|
69
|
-
);
|
|
70
|
-
/** A steel stud, one unit across, standing on the origin. */
|
|
71
|
-
const studMesh = () =>
|
|
72
|
-
cached('dab-stud', () =>
|
|
73
|
-
createShape(
|
|
74
|
-
lathe(
|
|
75
|
-
[
|
|
76
|
-
[0.001, 0],
|
|
77
|
-
[0.5, 0],
|
|
78
|
-
[0.5, 0.22],
|
|
79
|
-
[0.46, 0.38],
|
|
80
|
-
[0.34, 0.52],
|
|
81
|
-
[0.16, 0.6],
|
|
82
|
-
[0.001, 0.62]
|
|
83
|
-
],
|
|
84
|
-
{ segments: 24 }
|
|
85
|
-
),
|
|
86
|
-
{ center: false, shine: 0.85 }
|
|
87
|
-
)
|
|
88
|
-
);
|
|
89
|
-
/** A played line: a rod one unit long and across, along x. */
|
|
90
|
-
const rodMesh = () =>
|
|
91
|
-
cached('dab-rod', () =>
|
|
92
|
-
createShape(
|
|
93
|
-
tube(
|
|
94
|
-
[
|
|
95
|
-
[-0.5, 0, 0],
|
|
96
|
-
[0.5, 0, 0]
|
|
97
|
-
],
|
|
98
|
-
{ radius: 0.5, sides: 16, smoothness: 1 }
|
|
99
|
-
),
|
|
100
|
-
{ shine: 0.7 }
|
|
101
|
-
)
|
|
102
|
-
);
|
|
103
|
-
/** A claimed box: a rounded tile one unit across and tall, a raised face on a darker base. */
|
|
104
|
-
const tileMesh = () =>
|
|
105
|
-
cached('dab-tile', () =>
|
|
106
|
-
createShape(
|
|
107
|
-
merge([
|
|
108
|
-
{ geometry: shapeGeometry('roundedBox', { color: [0.78, 0.78, 0.78] }), position: [0, 0, 0.5] },
|
|
109
|
-
{ geometry: shapeGeometry('roundedBox'), position: [0, 0, 0.62], scale: [0.72, 0.72, 0.9] }
|
|
110
|
-
]),
|
|
111
|
-
{ center: false, shine: 0.55 }
|
|
112
|
-
)
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
// ── Lines and boxes ───────────────────────────────────────────────────
|
|
116
|
-
|
|
117
|
-
/** A line's middle on the board, and its length. */
|
|
118
|
-
function linePlace(l: Layout, kind: LineKind, row: number, col: number) {
|
|
119
|
-
const [ax, ay] = dotPoint(l, row, col);
|
|
120
|
-
const [bx, by] = kind === 'h' ? dotPoint(l, row, col + 1) : dotPoint(l, row + 1, col);
|
|
121
|
-
return { x: (ax + bx) / 2, y: (ay + by) / 2 };
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export function boxCentre(l: Layout, row: number, col: number): [number, number] {
|
|
125
|
-
const [x, y] = dotPoint(l, row, col);
|
|
126
|
-
return [x + l.cell / 2, y - l.cell / 2];
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const tileSize = (l: Layout): [number, number, number] => [l.cell * 0.76, l.cell * 0.76, l.cell * 0.14];
|
|
130
|
-
|
|
131
|
-
// ── Spawning ──────────────────────────────────────────────────────────
|
|
132
|
-
|
|
133
|
-
export type Board = {
|
|
134
|
-
backdrop: Entity;
|
|
135
|
-
panel: Entity;
|
|
136
|
-
rim: Entity | null;
|
|
137
|
-
studs: Entity[];
|
|
138
|
-
/** One per line, in the game's line order. */
|
|
139
|
-
slots: Entity[];
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
const slotColor = (theme: GameTheme) => toColor(theme.mode === 'classic' ? CLASSIC_SLOT : theme.BOARD.CELL_HIGHLIGHT);
|
|
143
|
-
|
|
144
|
-
/** The backdrop, the board and its rim, the studs and every line's groove. `lines` lists them in the game's order. */
|
|
145
|
-
export function buildBoard(world: World, l: Layout, theme: GameTheme, lines: readonly { kind: LineKind; row: number; col: number }[]): Board {
|
|
146
|
-
const classic = theme.mode === 'classic';
|
|
147
|
-
const radius = classic ? 16 : 8;
|
|
148
|
-
const backdrop = spawnBackdrop(world, l.width, l.height, -BACKDROP_DEPTH, theme);
|
|
149
|
-
placeTiltedBackdrop(world, backdrop, l, BACKDROP_DEPTH);
|
|
150
|
-
const panel = world.spawn({
|
|
151
|
-
mesh: panelMesh(l.boardSize, radius),
|
|
152
|
-
position: [0, 0, -BOARD_DEPTH / 2],
|
|
153
|
-
color: toColor(classic ? CLASSIC_BOARD : theme.BOARD.SURFACE),
|
|
154
|
-
pickable: false
|
|
155
|
-
});
|
|
156
|
-
const rimColor = toColor(classic ? CLASSIC_RIM : theme.BOARD.BORDER);
|
|
157
|
-
const rim = rimColor[3]! > 0 ? world.spawn({ mesh: rimMesh(l.boardSize, radius), position: [0, 0, 0.2], color: rimColor, pickable: false }) : null;
|
|
158
|
-
const studs: Entity[] = [];
|
|
159
|
-
const steel = toColor(DOT_COLOR);
|
|
160
|
-
for (let row = 0; row <= GRID_SIZE; row++)
|
|
161
|
-
for (let col = 0; col <= GRID_SIZE; col++) {
|
|
162
|
-
const [x, y] = dotPoint(l, row, col);
|
|
163
|
-
studs.push(world.spawn({ mesh: studMesh(), position: [x, y, 0], rotation: STAND_UP, scale: l.dotRadius * 2, color: steel, pickable: false }));
|
|
164
|
-
}
|
|
165
|
-
const slot = slotMesh(l.cell - l.dotRadius * 2.4, l.lineWidth * 0.75);
|
|
166
|
-
const color = slotColor(theme);
|
|
167
|
-
const slots = lines.map(({ kind, row, col }) => {
|
|
168
|
-
const { x, y } = linePlace(l, kind, row, col);
|
|
169
|
-
return world.spawn({ mesh: slot, position: [x, y, 0.3], rotation: kind === 'h' ? ACROSS : DOWN, color, pickable: false });
|
|
170
|
-
});
|
|
171
|
-
return { backdrop, panel, rim, studs, slots };
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export function removeBoard(world: World, b: Board) {
|
|
175
|
-
for (const e of [b.backdrop, b.panel, ...(b.rim != null ? [b.rim] : []), ...b.studs, ...b.slots]) world.despawn(e);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/** A new theme: backdrop, board, rim and grooves repainted; the studs, rods and tiles keep their colors. */
|
|
179
|
-
export function setBoardTheme(world: World, l: Layout, b: Board, theme: GameTheme) {
|
|
180
|
-
const classic = theme.mode === 'classic';
|
|
181
|
-
const radius = classic ? 16 : 8;
|
|
182
|
-
setBackdropTheme(world, b.backdrop, theme);
|
|
183
|
-
world.set(b.panel, { mesh: panelMesh(l.boardSize, radius), color: toColor(classic ? CLASSIC_BOARD : theme.BOARD.SURFACE) });
|
|
184
|
-
if (b.rim != null) world.despawn(b.rim);
|
|
185
|
-
const rimColor = toColor(classic ? CLASSIC_RIM : theme.BOARD.BORDER);
|
|
186
|
-
b.rim = rimColor[3]! > 0 ? world.spawn({ mesh: rimMesh(l.boardSize, radius), position: [0, 0, 0.2], color: rimColor, pickable: false }) : null;
|
|
187
|
-
const color = slotColor(theme);
|
|
188
|
-
for (const s of b.slots) world.set(s, { color });
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/** A played line's rod; with `animate`, it drops in and grows out from its middle with a bright flash. */
|
|
192
|
-
export function spawnRod(world: World, l: Layout, kind: LineKind, row: number, col: number, owner: Owner, animate: boolean): Entity {
|
|
193
|
-
const { x, y } = linePlace(l, kind, row, col);
|
|
194
|
-
const w = l.lineWidth;
|
|
195
|
-
const color = ownerColor(owner);
|
|
196
|
-
const rest: [number, number, number] = [x, y, w / 2];
|
|
197
|
-
const rod = world.spawn({
|
|
198
|
-
mesh: rodMesh(),
|
|
199
|
-
position: animate ? [x, y, w * 2.5] : rest,
|
|
200
|
-
rotation: kind === 'h' ? ACROSS : DOWN,
|
|
201
|
-
scale: [animate ? w : l.cell, w, w],
|
|
202
|
-
color: animate ? glow(color, 1.6) : color,
|
|
203
|
-
pickable: false
|
|
204
|
-
});
|
|
205
|
-
if (animate) {
|
|
206
|
-
world.animate(rod, { scale: [l.cell, w, w] }, { duration: LINE_TIME, easing: 'back' });
|
|
207
|
-
world.animate(rod, { position: rest }, { duration: LINE_TIME, easing: 'bounce' });
|
|
208
|
-
world.animate(rod, { color }, { duration: LINE_TIME * 2 });
|
|
209
|
-
}
|
|
210
|
-
return rod;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/** A claimed box's tile; with `animate`, it springs up out of the board and throws a little confetti. */
|
|
214
|
-
export function spawnTile(world: World, l: Layout, row: number, col: number, owner: Owner, animate: boolean): Entity {
|
|
215
|
-
const [x, y] = boxCentre(l, row, col);
|
|
216
|
-
const color = ownerColor(owner);
|
|
217
|
-
const tile = world.spawn({ mesh: tileMesh(), position: [x, y, 0], scale: animate ? [0.01, 0.01, 0.01] : tileSize(l), color, pickable: false });
|
|
218
|
-
if (animate) {
|
|
219
|
-
world.animate(tile, { scale: tileSize(l) }, { duration: BOX_TIME, easing: 'back' });
|
|
220
|
-
effects.sparkle(world, {
|
|
221
|
-
position: [x, y, l.cell * 0.2],
|
|
222
|
-
count: 12,
|
|
223
|
-
size: l.cell * 0.08,
|
|
224
|
-
speed: l.cell * 3,
|
|
225
|
-
lifetime: 0.5,
|
|
226
|
-
gravity: -l.cell * 6,
|
|
227
|
-
colors: [color, glow(color, 1.3), [1, 1, 1, 1]]
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
return tile;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
/** Confetti over the board when you win. */
|
|
234
|
-
export function celebrate(world: World, l: Layout) {
|
|
235
|
-
effects.confetti(world, {
|
|
236
|
-
position: [0, 0, l.cell],
|
|
237
|
-
count: 60,
|
|
238
|
-
size: l.cell * 0.12,
|
|
239
|
-
speed: l.boardSize * 1.4,
|
|
240
|
-
lifetime: 1.4,
|
|
241
|
-
gravity: -l.boardSize * 2.4,
|
|
242
|
-
colors: ['#34D399', '#FFD740', '#448AFF', '#FF5252'].map((c) => toColor(c))
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/** Hides a line's groove under its rod (or shows it again on a reset). */
|
|
247
|
-
export function showSlot(world: World, b: Board, index: number, on: boolean) {
|
|
248
|
-
world.set(b.slots[index]!, { scale: on ? 1 : 0 });
|
|
249
|
-
}
|