-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Module #2 (Nowshin Owishi) #29
base: module-2
Are you sure you want to change the base?
Changes from 2 commits
bee70f2
cf27ed2
ec21c5a
9721681
66aec44
5c03c11
2b4d230
8e93356
48ca4d2
4ba03c3
b5a4648
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,10 @@ | ||
import dynamic from "next/dynamic"; | ||
import { useEffect, useState, useRef } from "react"; | ||
import { useEffect, useState, useRef, useCallback, useMemo } from "react"; | ||
import styles from "../styles/Snake.module.css"; | ||
|
||
const Config = { | ||
height: 25, | ||
width: 25, | ||
height: 15, | ||
width: 15, | ||
cellSize: 32, | ||
}; | ||
|
||
|
@@ -61,9 +61,12 @@ const Cell = ({ x, y, type }) => { | |
const getRandomCell = () => ({ | ||
x: Math.floor(Math.random() * Config.width), | ||
y: Math.floor(Math.random() * Config.width), | ||
start: Date.now(), | ||
}); | ||
|
||
const Snake = () => { | ||
//custom hook | ||
//controller | ||
const UseSnake = () => { | ||
const getDefaultSnake = () => [ | ||
{ x: 8, y: 12 }, | ||
{ x: 7, y: 12 }, | ||
|
@@ -75,67 +78,118 @@ const Snake = () => { | |
const [snake, setSnake] = useState(getDefaultSnake()); | ||
const [direction, setDirection] = useState(Direction.Right); | ||
|
||
const [food, setFood] = useState({ x: 4, y: 10 }); | ||
const [score, setScore] = useState(0); | ||
|
||
// move the snake | ||
useEffect(() => { | ||
const runSingleStep = () => { | ||
setSnake((snake) => { | ||
const head = snake[0]; | ||
const newHead = { x: head.x + direction.x, y: head.y + direction.y }; | ||
const [foods, setFoods] = useState([]); | ||
const score = snake.length - 3; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as snake state is different from objects state,it makes sense to have a different function for checking snake.And it also makes the code more readable const isSnake = useCallback(
({ x, y }) =>
snake.find((position) => position.x === x && position.y === y),
[snake]
); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah I give an upvote to this. @owishiboo your function can work with all three types but loses simplicity. poison and food are similiar and we put them to one object state, but snake is different so we can keep it seperate fully. |
||
// make a new snake by extending head | ||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax | ||
const newSnake = [newHead, ...snake]; | ||
// ?. is called optional chaining | ||
const isFood = useCallback( | ||
({ x, y }) => | ||
foods.find((position) => position.x === x && position.y === y), | ||
[foods] | ||
); | ||
|
||
// remove tail | ||
const isSnake = useCallback( | ||
({ x, y }) => | ||
snake.find((position) => position.x === x && position.y === y), | ||
[snake] | ||
); | ||
//restart the game | ||
const resetGame = useCallback(() => { | ||
setSnake(getDefaultSnake()); | ||
setDirection(Direction.Right); | ||
setFoods([]); | ||
}, []); | ||
//moving the snake | ||
const runSingleStep = useCallback(() => { | ||
setSnake((snake) => { | ||
const head = snake[0]; | ||
const newHead = { | ||
x: (head.x + direction.x + Config.width) % Config.width, | ||
y: (head.y + direction.y + Config.height) % Config.height, | ||
}; | ||
|
||
// make a new snake by extending head | ||
const newSnake = [newHead, ...snake]; | ||
|
||
// remove tail when head doesnt eat food | ||
if (!isFood(newHead)) { | ||
newSnake.pop(); | ||
} | ||
if (isSnake(newHead)) { | ||
resetGame(); | ||
} | ||
|
||
return newSnake; | ||
}); | ||
}; | ||
|
||
runSingleStep(); | ||
const timer = setInterval(runSingleStep, 500); | ||
|
||
return () => clearInterval(timer); | ||
}, [direction, food]); | ||
return newSnake; | ||
}); | ||
}, [direction.x, direction.y, isFood, isSnake, resetGame]); | ||
|
||
//add new food | ||
const addFood = () => { | ||
let newFood = getRandomCell(); | ||
while (isSnake(newFood) || isFood(newFood)) { | ||
newFood = getRandomCell(); | ||
} | ||
setFoods((currentFoods) => [...currentFoods, newFood]); | ||
}; | ||
//remove food | ||
const removeFood = useCallback(()=>{ | ||
setFoods((currentFoods)=> { | ||
currentFoods.filter((food) => Date.now() - food.start <10000) | ||
}) | ||
},[setFoods]) | ||
// update score whenever head touches a food | ||
useEffect(() => { | ||
const head = snake[0]; | ||
if (isFood(head)) { | ||
setScore((score) => { | ||
return score + 1; | ||
}); | ||
|
||
let newFood = getRandomCell(); | ||
while (isSnake(newFood)) { | ||
newFood = getRandomCell(); | ||
setFoods((currentFoods) => | ||
currentFoods.filter((food) => food.x !== head.x && food.y !== head.y) | ||
); | ||
} | ||
}, [isFood, snake]); | ||
|
||
const UseInterval = (func, dir) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. move this outside of useSnake |
||
const timer = useRef(Date.now()); | ||
const createCallback = useCallback(() => { | ||
if (Date.now() - timer.current > dir) { | ||
timer.current = Date.now(); | ||
func(); | ||
} | ||
}, [dir, func]); | ||
|
||
setFood(newFood); | ||
} | ||
}, [snake]); | ||
useEffect(() => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Corei13 why does removefood() doesn't work? it says 'Cannot read properties of undefined (reading 'find')' There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @owishiboo because on line 136-138, you are setting setFoods(undefined). Why? Because you are calling |
||
const interval = setInterval(createCallback, 1000 / 60); | ||
return () => clearInterval(interval); | ||
}, [createCallback]); | ||
}; | ||
|
||
UseInterval(addFood, 3000); | ||
UseInterval(runSingleStep, 300); | ||
UseInterval(removeFood,5000); | ||
|
||
const changeDir = (checkDir, newDir) => { | ||
setDirection((direction) => { | ||
if (direction != checkDir) return newDir; | ||
return direction; | ||
}); | ||
}; | ||
|
||
useEffect(() => { | ||
const handleNavigation = (event) => { | ||
switch (event.key) { | ||
case "ArrowUp": | ||
setDirection(Direction.Top); | ||
changeDir(Direction.Bottom, Direction.Top); | ||
break; | ||
|
||
case "ArrowDown": | ||
setDirection(Direction.Bottom); | ||
changeDir(Direction.Top, Direction.Bottom); | ||
break; | ||
|
||
case "ArrowLeft": | ||
setDirection(Direction.Left); | ||
changeDir(Direction.Right, Direction.Left); | ||
break; | ||
|
||
case "ArrowRight": | ||
setDirection(Direction.Right); | ||
changeDir(Direction.Left, Direction.Right); | ||
break; | ||
} | ||
}; | ||
|
@@ -144,13 +198,12 @@ const Snake = () => { | |
return () => window.removeEventListener("keydown", handleNavigation); | ||
}, []); | ||
|
||
// ?. is called optional chaining | ||
// see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining | ||
const isFood = ({ x, y }) => food?.x === x && food?.y === y; | ||
|
||
const isSnake = ({ x, y }) => | ||
snake.find((position) => position.x === x && position.y === y); | ||
return { score, isFood, isSnake }; | ||
}; | ||
|
||
//view | ||
const Snake = () => { | ||
const { score, isFood, isSnake } = UseSnake(); | ||
const cells = []; | ||
for (let x = 0; x < Config.width; x++) { | ||
for (let y = 0; y < Config.height; y++) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fix naming convention
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UseSnake is not a hook here. I'm not sure, should I remove the term 'Use'?