✨ Ability to loose game
This commit is contained in:
@@ -13,13 +13,14 @@ import { gameStateAtom } from '../../contexts/gameState';
|
||||
|
||||
// ------------------------------------------------------ Utils --------------------------------------------------------
|
||||
import { Difficulty } from '../../types/game';
|
||||
import { discoverAroundCell, genGrid, startGame } from '../../utils/game';
|
||||
import { discoverAroundCell, genGrid, revealAllGrid, startGame } from '../../utils/game';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// ----------------------------------------------------- Assets --------------------------------------------------------
|
||||
import Bomb from '../../assets/bomb.png';
|
||||
import Flag from '../../assets/flag.png';
|
||||
import './styles.scss';
|
||||
import Podium from '../../assets/podium';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
const Grid = () => {
|
||||
@@ -47,6 +48,14 @@ const Grid = () => {
|
||||
}));
|
||||
}
|
||||
|
||||
if (prev[rowIndex][colIndex].value === 'bomb') {
|
||||
setGameState((prev) => ({
|
||||
...prev,
|
||||
endType: 'loose',
|
||||
}));
|
||||
return revealAllGrid(grid, true);
|
||||
}
|
||||
|
||||
return discoverAroundCell(prev, rowIndex, colIndex);
|
||||
});
|
||||
forceUpdate();
|
||||
@@ -138,6 +147,25 @@ const Grid = () => {
|
||||
})}
|
||||
</div>
|
||||
))}
|
||||
{gameState.endType !== '' && (
|
||||
<div
|
||||
className='overlay'
|
||||
style={
|
||||
{
|
||||
'--overlayColor': gameState.endType === 'win' ? '#5f8e59' : '#ca5940',
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
<p className='overlayTitle'>{gameState.endType === 'win' ? 'Gagné !' : 'Perdu !'}</p>
|
||||
<button
|
||||
className='overlayButton'
|
||||
onClick={() => setGameState((prev) => ({ ...prev, status: 'board' }))}
|
||||
>
|
||||
<Podium />
|
||||
Leaderboard
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
.grid {
|
||||
--size: 30px;
|
||||
position: relative;
|
||||
display: grid;
|
||||
gap: 2px;
|
||||
padding: 2px;
|
||||
@@ -73,4 +74,39 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& > .overlay {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 30px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba($color: #000000, $alpha: 0.3);
|
||||
backdrop-filter: blur(1px);
|
||||
|
||||
& > .overlayTitle {
|
||||
font-size: 2.5em;
|
||||
color: var(--overlayColor);
|
||||
}
|
||||
|
||||
& > .overlayButton {
|
||||
display: grid;
|
||||
grid-template-columns: 1.1em auto;
|
||||
place-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 25px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
background-color: var(--overlayColor);
|
||||
font-size: 1em;
|
||||
color: #ffff;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,13 +39,9 @@ const Home = () => {
|
||||
<select
|
||||
ref={sizeRef}
|
||||
className='select'
|
||||
defaultValue={'12'}
|
||||
>
|
||||
<option
|
||||
value='12'
|
||||
selected
|
||||
>
|
||||
Petit
|
||||
</option>
|
||||
<option value='12'>Petit</option>
|
||||
<option value='16'>Moyen</option>
|
||||
<option value='20'>Grand</option>
|
||||
</select>
|
||||
@@ -56,13 +52,9 @@ const Home = () => {
|
||||
<select
|
||||
ref={difficultyRef}
|
||||
className='select'
|
||||
defaultValue={'beginner'}
|
||||
>
|
||||
<option
|
||||
value='beginner'
|
||||
selected
|
||||
>
|
||||
Facile
|
||||
</option>
|
||||
<option value='beginner'>Facile</option>
|
||||
<option value='intermediate'>Moyen</option>
|
||||
<option value='expert'>Difficile</option>
|
||||
</select>
|
||||
|
||||
@@ -47,7 +47,7 @@ const LeaderBoard = () => {
|
||||
if (data.length === 0) {
|
||||
getData();
|
||||
}
|
||||
}, []);
|
||||
}, [data.length]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -93,7 +93,7 @@ const LeaderBoard = () => {
|
||||
|
||||
<button
|
||||
className='controlButton replay'
|
||||
onClick={() => setGameState((prev) => ({ ...prev, status: 'idle', endType: '', placedFlags: 0, bombs: 0, gameTime: 0 }))}
|
||||
onClick={() => setGameState((prev) => ({ ...prev, status: 'idle', endType: '', placedFlags: 0, bombs: 0, gameTime: '' }))}
|
||||
>
|
||||
<Replay />
|
||||
Rejouer
|
||||
|
||||
@@ -14,23 +14,25 @@ import { gameStateAtom } from '../../../contexts/gameState';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
const Timer = () => {
|
||||
const [{ status }] = useRecoilState(gameStateAtom);
|
||||
const [gameState, setGameState] = useRecoilState(gameStateAtom);
|
||||
|
||||
const [intervalId, setIntervalId] = useState<NodeJS.Timeout | null>(null);
|
||||
const [startedTime, setStartedTime] = useState<number | null>(null);
|
||||
const [displayedTime, setDisplayedTime] = useState<string>('00:00');
|
||||
|
||||
useEffect(() => {
|
||||
if (status === 'playing') {
|
||||
setStartedTime(Date.now());
|
||||
} else if (status === 'win' || status === 'loose') {
|
||||
if (gameState.status === 'win' || gameState.status === 'loose') {
|
||||
setStartedTime(null);
|
||||
}
|
||||
}, [status]);
|
||||
}, [gameState.status]);
|
||||
|
||||
useEffect(() => {
|
||||
if (startedTime) {
|
||||
if (!startedTime && gameState.endType === '' && gameState.status === 'playing') {
|
||||
const now = Date.now();
|
||||
setStartedTime(now);
|
||||
|
||||
const interval = setInterval(() => {
|
||||
const elapsedTime = (Date.now() - startedTime) / 1000;
|
||||
const elapsedTime = (Date.now() - now) / 1000;
|
||||
|
||||
const seconds = Math.floor(elapsedTime % 60);
|
||||
const strSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`;
|
||||
@@ -41,9 +43,19 @@ const Timer = () => {
|
||||
setDisplayedTime(`${strMinute}:${strSeconds}`);
|
||||
}, 500);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
setIntervalId(interval);
|
||||
}
|
||||
}, [startedTime]);
|
||||
}, [startedTime, gameState.endType, gameState.status]);
|
||||
|
||||
useEffect(() => {
|
||||
if (intervalId && gameState.endType !== '') {
|
||||
setGameState((prev) => ({
|
||||
...prev,
|
||||
gameTime: displayedTime,
|
||||
}));
|
||||
clearInterval(intervalId);
|
||||
}
|
||||
}, [intervalId, gameState.endType, setGameState, displayedTime]);
|
||||
|
||||
return (
|
||||
<div className='statContainer'>
|
||||
|
||||
Reference in New Issue
Block a user