From 1fdb8c070b5e5a559f5a1f048938addd70df3871 Mon Sep 17 00:00:00 2001 From: DevAlissu Date: Sun, 19 Apr 2026 14:52:19 -0400 Subject: [PATCH 1/3] exibe badge de melhor pontuacao apenas no modo competitivo --- src/features/snake-game/SnakeGame.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/snake-game/SnakeGame.tsx b/src/features/snake-game/SnakeGame.tsx index 049c9b5..28ee0ac 100644 --- a/src/features/snake-game/SnakeGame.tsx +++ b/src/features/snake-game/SnakeGame.tsx @@ -80,7 +80,7 @@ export function SnakeGame({ className = '' }: SnakeGameProps) { onDifficulty={actions.setDifficulty} onMode={actions.setMode} /> - {highScore > 0 && } + {mode === 'competitive' && highScore > 0 && }
From f5f57ffd5553e10a419585b590e22b65c693490a Mon Sep 17 00:00:00 2001 From: DevAlissu Date: Sun, 19 Apr 2026 14:52:23 -0400 Subject: [PATCH 2/3] reduz latencia de input no snake game - limita fila de direcoes em 2 itens para evitar input buildup em spams - descarta novos inputs quando fila saturada em vez de acumular - migra game loop de setInterval para setTimeout recursivo para cancelamento - ajusta velocidades das dificuldades para 170 140 80 ms por tick --- src/features/snake-game/constants/index.ts | 8 +-- src/features/snake-game/hooks/useSnakeGame.ts | 49 ++++++++++++++----- src/features/snake-game/store/useGameStore.ts | 12 +++-- 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/features/snake-game/constants/index.ts b/src/features/snake-game/constants/index.ts index 47b97ce..ca42959 100644 --- a/src/features/snake-game/constants/index.ts +++ b/src/features/snake-game/constants/index.ts @@ -8,11 +8,13 @@ export const MAX_LEADERBOARD_ENTRIES = 10; export const COUNTDOWN_SECONDS = 3; export const COMBO_WINDOW_MS = 3000; export const PARTICLE_LIFETIME_MS = 600; +export const MAX_DIRECTION_QUEUE = 2; +export const FAST_FORWARD_THRESHOLD = 0.35; export const DIFFICULTY_SPEEDS: Record = { - easy: 200, - normal: 150, - hard: 100, + easy: 170, + normal: 140, + hard: 80, }; export const DIFFICULTY_LABELS: Record = { diff --git a/src/features/snake-game/hooks/useSnakeGame.ts b/src/features/snake-game/hooks/useSnakeGame.ts index 45b21d1..d3ce76d 100644 --- a/src/features/snake-game/hooks/useSnakeGame.ts +++ b/src/features/snake-game/hooks/useSnakeGame.ts @@ -21,7 +21,7 @@ export function useSnakeGame() { const pauseGame = useGameStore((s) => s.pauseGame); const resumeGame = useGameStore((s) => s.resumeGame); const resetGame = useGameStore((s) => s.resetGame); - const setDirection = useGameStore((s) => s.setDirection); + const storeSetDirection = useGameStore((s) => s.setDirection); const setDifficulty = useGameStore((s) => s.setDifficulty); const setMode = useGameStore((s) => s.setMode); const saveToLeaderboard = useGameStore((s) => s.saveToLeaderboard); @@ -29,6 +29,28 @@ export function useSnakeGame() { const statusRef = useRef(status); statusRef.current = status; + const speed = DIFFICULTY_SPEEDS[difficulty]; + const speedRef = useRef(speed); + speedRef.current = speed; + + const timerRef = useRef | null>(null); + + const runTick = useCallback(() => { + if (statusRef.current === 'playing') { + useGameStore.getState().moveSnake(); + } + }, []); + + const scheduleTick = useCallback(() => { + if (timerRef.current) clearTimeout(timerRef.current); + timerRef.current = setTimeout(() => { + runTick(); + if (statusRef.current === 'playing') scheduleTick(); + }, speedRef.current); + }, [runTick]); + + const setDirection = storeSetDirection; + const handleKeyPress = useCallback( (event: KeyboardEvent) => { const key = event.key.toLowerCase(); @@ -67,17 +89,22 @@ export function useSnakeGame() { return () => window.removeEventListener('keydown', handleKeyPress); }, [handleKeyPress]); - const speed = DIFFICULTY_SPEEDS[difficulty]; - useEffect(() => { - if (status !== 'playing') return; - - const gameInterval = setInterval(() => { - useGameStore.getState().moveSnake(); - }, speed); - - return () => clearInterval(gameInterval); - }, [status, speed]); + if (status !== 'playing') { + if (timerRef.current) { + clearTimeout(timerRef.current); + timerRef.current = null; + } + return; + } + scheduleTick(); + return () => { + if (timerRef.current) { + clearTimeout(timerRef.current); + timerRef.current = null; + } + }; + }, [status, scheduleTick]); const remainingFood = mode === 'casual' ? Math.max(0, FOOD_TO_WIN_CASUAL - score) : null; diff --git a/src/features/snake-game/store/useGameStore.ts b/src/features/snake-game/store/useGameStore.ts index 557291e..450e4b5 100644 --- a/src/features/snake-game/store/useGameStore.ts +++ b/src/features/snake-game/store/useGameStore.ts @@ -20,6 +20,7 @@ import { FOOD_TYPES, COMBO_WINDOW_MS, PARTICLE_LIFETIME_MS, + MAX_DIRECTION_QUEUE, } from '../constants'; function pickFoodType(): FoodType { @@ -207,14 +208,19 @@ export const useGameStore = create((set, get) => ({ const { direction: currentDirection, directionQueue, status } = get(); if (status !== 'playing') return; + // drop inputs when queue is saturated — prevents input lag from spam + if (directionQueue.length >= MAX_DIRECTION_QUEUE) return; + const lastDirection = directionQueue.length > 0 ? directionQueue[directionQueue.length - 1] : currentDirection; - if (OPPOSITE_DIRECTIONS[direction] !== lastDirection && direction !== lastDirection) { - set({ directionQueue: [...directionQueue, direction] }); - } + // reject duplicates (same as pending last) and opposite (180 turn) + if (direction === lastDirection) return; + if (OPPOSITE_DIRECTIONS[direction] === lastDirection) return; + + set({ directionQueue: [...directionQueue, direction] }); }, clearParticle: (id: number) => { From fcb9b63e9b7f9107bd7b340ce332765ff56ccf8d Mon Sep 17 00:00:00 2001 From: DevAlissu Date: Sun, 19 Apr 2026 14:52:26 -0400 Subject: [PATCH 3/3] torna botoes direcionais mais responsivos em touch - troca onClick por onPointerDown com preventDefault para disparar no toque - adiciona touch-action manipulation para eliminar delay de tap double - adiciona user-select none e webkit tap highlight transparente --- src/features/snake-game/components/GameControls.tsx | 10 ++++++++-- src/features/snake-game/styles/snake-game.css | 3 +++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/features/snake-game/components/GameControls.tsx b/src/features/snake-game/components/GameControls.tsx index acd2bd4..c56cf41 100644 --- a/src/features/snake-game/components/GameControls.tsx +++ b/src/features/snake-game/components/GameControls.tsx @@ -28,7 +28,10 @@ export const GameControls = memo(function GameControls({ status, onDirection }: