From add7e70b83344df3e6266945808b8979a2496bc8 Mon Sep 17 00:00:00 2001 From: Pihkaal Date: Fri, 30 Jan 2026 00:25:02 +0100 Subject: [PATCH] feat(settings/options/2048): allow faster movements and show restart modal when trying to move on an lost game --- .../BottomScreen/Menus/Options/GbaMode.vue | 95 ++++++++++++------- 1 file changed, 59 insertions(+), 36 deletions(-) diff --git a/app/components/Settings/BottomScreen/Menus/Options/GbaMode.vue b/app/components/Settings/BottomScreen/Menus/Options/GbaMode.vue index be2eb43..ef05510 100644 --- a/app/components/Settings/BottomScreen/Menus/Options/GbaMode.vue +++ b/app/components/Settings/BottomScreen/Menus/Options/GbaMode.vue @@ -28,33 +28,31 @@ const handleActivateA = () => { resetBoard(); } }, - onCancel: () => { - confirmationModal.close(); - }, }); }; +// TODO: one color scheme per app color const TILE_COLORS: Record = { - [0]: { bg: "#ccc0b4", fg: "#776e65" }, - [2]: { bg: "#eee4db", fg: "#776e65" }, - [4]: { bg: "#eee0cb", fg: "#776e65" }, - [8]: { bg: "#f3b27a", fg: "#f9f6f2" }, - [16]: { bg: "#f69664", fg: "#f9f6f2" }, - [32]: { bg: "#f67c5f", fg: "#f9f6f2" }, - [64]: { bg: "#f7603c", fg: "#f9f6f2" }, - [128]: { bg: "#ecd072", fg: "#f9f6f2" }, - [256]: { bg: "#eecc62", fg: "#f9f6f2" }, - [512]: { bg: "#eec950", fg: "#f9f6f2" }, - [1024]: { bg: "#edc53f", fg: "#f9f6f2" }, - [2048]: { bg: "#edc12e", fg: "#f9f6f2" }, - [4046]: { bg: "#3c3a33", fg: "#f9f6f2" }, + [0]: { bg: "#f7f7f7", fg: "#776e65" }, + [2]: { bg: "#ebebf3", fg: "#292929" }, + [4]: { bg: "#d3dbe3", fg: "#292929" }, + [8]: { bg: "#bacbd3", fg: "#292929" }, + [16]: { bg: "#a2bac3", fg: "#f9f6f2" }, + [32]: { bg: "#8aa2b2", fg: "#f9f6f2" }, + [64]: { bg: "#7192a2", fg: "#f9f6f2" }, + [128]: { bg: "#698aa2", fg: "#f9f6f2" }, + [256]: { bg: "#61829a", fg: "#f9f6f2" }, + [512]: { bg: "#5c7b92", fg: "#f9f6f2" }, + [1024]: { bg: "#57758a", fg: "#f9f6f2" }, // -2.5L, -0.8C + [2048]: { bg: "#476277", fg: "#f9f6f2" }, + [4046]: { bg: "#173446", fg: "#f9f6f2" }, }; const LAST_TILE_COLOR = Object.values(TILE_COLORS)[Object.values(TILE_COLORS).length - 1]!; const TILE_SIZE = 28; const ANIM_DURATION = 0.1; -const BORDER_COLOR = "#bbada0"; +const BORDER_COLOR = "#d7d7d7"; const BORDER_SIZE = 3; const BOARD_X = 64; @@ -81,6 +79,21 @@ const cellY = (row: number) => BORDER_SIZE + row * (TILE_SIZE + BORDER_SIZE); let tiles: VisualTile[] = []; let animating = false; +const showRestartModal = () => { + let confirmed = false; + confirmationModal.open({ + text: "Game Over!\nRestart?", + onConfirm: () => { + confirmed = true; + }, + onClosed: () => { + if (confirmed) { + resetBoard(); + } + }, + }); +}; + const buildTilesFromBoard = () => { tiles = []; for (let row = 0; row < BOARD_SIZE; row += 1) { @@ -104,6 +117,8 @@ onRender((ctx) => { ctx.textBaseline = "top"; ctx.translate(BOARD_X, BOARD_Y); + assets.images.settings.bottomScreen.options._2048.frame.draw(ctx, -3, -3); + ctx.fillStyle = BORDER_COLOR; ctx.fillRect( 0, @@ -251,7 +266,16 @@ if (board.every((r) => r.every((c) => c === 0))) { } const slide = (rowDir: number, colDir: number) => { - if (animating) return; + if (isDead() && !confirmationModal.isOpen) { + showRestartModal(); + return; + } + + if (animating) { + gsap.globalTimeline.clear(); + animating = false; + buildTilesFromBoard(); + } const beforeTiles: { row: number; col: number; value: number }[] = []; for (let row = 0; row < BOARD_SIZE; row += 1) { @@ -358,6 +382,12 @@ const slide = (rowDir: number, colDir: number) => { const spawned = spawnTile(); saveBoard(); + if (isDead()) { + buildTilesFromBoard(); + showRestartModal(); + return; + } + tiles = animTiles; animating = true; @@ -365,27 +395,11 @@ const slide = (rowDir: number, colDir: number) => { onComplete: () => { animating = false; buildTilesFromBoard(); - if (isDead()) { - confirmationModal.open({ - text: "Game Over!\nRestart?", - onConfirm: () => { - resetBoard(); - confirmationModal.close(); - }, - onCancel: () => { - confirmationModal.close(); - }, - }); - } }, }); for (const { tile, toX, toY } of tweens) { - tl.to( - tile, - { x: toX, y: toY, duration: ANIM_DURATION, ease: "power1.out" }, - 0, - ); + tl.to(tile, { x: toX, y: toY, duration: ANIM_DURATION, ease: "none" }, 0); } if (mergePairs.length > 0) { @@ -399,7 +413,7 @@ const slide = (rowDir: number, colDir: number) => { tl.fromTo( keep, { scale: 1.1 }, - { scale: 1, duration: ANIM_DURATION, ease: "power1.out" }, + { scale: 1, duration: ANIM_DURATION, ease: "none" }, ); } } @@ -424,6 +438,15 @@ const slide = (rowDir: number, colDir: number) => { useKeyDown((key) => { switch (key) { + // TODO: remove this, testing only + case "n": + savedBoard.value = [ + [0, 0, 2, 4], + [8, 16, 32, 64], + [128, 256, 512, 1024], + [2048, 4096, 8192, 16384], + ]; + break; case "NDS_UP": slide(-1, 0); break;