const INITIAL_SNAKE = [{ x: 10 , y: 10 }];
const INITIAL_DIRECTION = { x: 1 , y: 0 } ;
function useSnakeGame () {
const [ snake , setSnake ] = useState ( INITIAL_SNAKE );
const [ food , setFood ] = useState ( generateFood ( INITIAL_SNAKE ));
const [ direction , setDirection ] = useState ( INITIAL_DIRECTION );
const [ gameOver , setGameOver ] = useState ( false );
const [ score , setScore ] = useState ( 0 );
const directionRef = useRef ( direction ); // ref dla aktualnego kierunku w setInterval
useEffect ( () => { directionRef . current = direction ; } , [ direction ]);
const interval = setInterval ( () => {
x: prev [ 0 ] . x + directionRef . current . x ,
y: prev [ 0 ] . y + directionRef . current . y ,
if ( newHead . x < 0 || newHead . x >= GRID_SIZE || newHead . y < 0 || newHead . y >= GRID_SIZE ) {
if ( prev . some ( ( seg ) => seg . x === newHead . x && seg . y === newHead . y )) {
const ateFood = newHead . x === food . x && newHead . y === food . y ;
setFood ( generateFood ([ newHead , ... prev ])) ;
return [ newHead , ... prev ] ;
return [ newHead , ...prev . slice ( 0 , - 1 )] ;
return () => clearInterval ( interval );
ArrowUp: { x: 0 , y: - 1 } ,
ArrowDown: { x: 0 , y: 1 } ,
ArrowLeft: { x: - 1 , y: 0 } ,
ArrowRight: { x: 1 , y: 0 } ,
setDirection ( keys [ e . key ]);
return { snake , food , score , gameOver , handleKey };
function generateFood ( snake ) {
pos = { x: Math . floor ( Math . random () * GRID_SIZE ) , y: Math . floor ( Math . random () * GRID_SIZE ) };
} while ( snake . some ( ( s ) => s . x === pos . x && s . y === pos . y ));