✨ Ability to loose game
This commit is contained in:
@@ -0,0 +1,20 @@
|
|||||||
|
const Podium = (props: any) => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='0 0 512 512'
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d='M32 160v296a8 8 0 008 8h136V160a16 16 0 00-16-16H48a16 16 0 00-16 16zM320 48H192a16 16 0 00-16 16v400h160V64a16 16 0 00-16-16zM464 208H352a16 16 0 00-16 16v240h136a8 8 0 008-8V224a16 16 0 00-16-16z'
|
||||||
|
fill='none'
|
||||||
|
stroke='currentColor'
|
||||||
|
strokeLinecap='round'
|
||||||
|
strokeLinejoin='round'
|
||||||
|
strokeWidth='32'
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Podium;
|
||||||
@@ -13,13 +13,14 @@ import { gameStateAtom } from '../../contexts/gameState';
|
|||||||
|
|
||||||
// ------------------------------------------------------ Utils --------------------------------------------------------
|
// ------------------------------------------------------ Utils --------------------------------------------------------
|
||||||
import { Difficulty } from '../../types/game';
|
import { Difficulty } from '../../types/game';
|
||||||
import { discoverAroundCell, genGrid, startGame } from '../../utils/game';
|
import { discoverAroundCell, genGrid, revealAllGrid, startGame } from '../../utils/game';
|
||||||
// ---------------------------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// ----------------------------------------------------- Assets --------------------------------------------------------
|
// ----------------------------------------------------- Assets --------------------------------------------------------
|
||||||
import Bomb from '../../assets/bomb.png';
|
import Bomb from '../../assets/bomb.png';
|
||||||
import Flag from '../../assets/flag.png';
|
import Flag from '../../assets/flag.png';
|
||||||
import './styles.scss';
|
import './styles.scss';
|
||||||
|
import Podium from '../../assets/podium';
|
||||||
// ---------------------------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
const Grid = () => {
|
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);
|
return discoverAroundCell(prev, rowIndex, colIndex);
|
||||||
});
|
});
|
||||||
forceUpdate();
|
forceUpdate();
|
||||||
@@ -138,6 +147,25 @@ const Grid = () => {
|
|||||||
})}
|
})}
|
||||||
</div>
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
.grid {
|
.grid {
|
||||||
--size: 30px;
|
--size: 30px;
|
||||||
|
position: relative;
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 2px;
|
gap: 2px;
|
||||||
padding: 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
|
<select
|
||||||
ref={sizeRef}
|
ref={sizeRef}
|
||||||
className='select'
|
className='select'
|
||||||
|
defaultValue={'12'}
|
||||||
>
|
>
|
||||||
<option
|
<option value='12'>Petit</option>
|
||||||
value='12'
|
|
||||||
selected
|
|
||||||
>
|
|
||||||
Petit
|
|
||||||
</option>
|
|
||||||
<option value='16'>Moyen</option>
|
<option value='16'>Moyen</option>
|
||||||
<option value='20'>Grand</option>
|
<option value='20'>Grand</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -56,13 +52,9 @@ const Home = () => {
|
|||||||
<select
|
<select
|
||||||
ref={difficultyRef}
|
ref={difficultyRef}
|
||||||
className='select'
|
className='select'
|
||||||
|
defaultValue={'beginner'}
|
||||||
>
|
>
|
||||||
<option
|
<option value='beginner'>Facile</option>
|
||||||
value='beginner'
|
|
||||||
selected
|
|
||||||
>
|
|
||||||
Facile
|
|
||||||
</option>
|
|
||||||
<option value='intermediate'>Moyen</option>
|
<option value='intermediate'>Moyen</option>
|
||||||
<option value='expert'>Difficile</option>
|
<option value='expert'>Difficile</option>
|
||||||
</select>
|
</select>
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ const LeaderBoard = () => {
|
|||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
getData();
|
getData();
|
||||||
}
|
}
|
||||||
}, []);
|
}, [data.length]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -93,7 +93,7 @@ const LeaderBoard = () => {
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
className='controlButton replay'
|
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 />
|
<Replay />
|
||||||
Rejouer
|
Rejouer
|
||||||
|
|||||||
@@ -14,23 +14,25 @@ import { gameStateAtom } from '../../../contexts/gameState';
|
|||||||
// ---------------------------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
const Timer = () => {
|
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 [startedTime, setStartedTime] = useState<number | null>(null);
|
||||||
const [displayedTime, setDisplayedTime] = useState<string>('00:00');
|
const [displayedTime, setDisplayedTime] = useState<string>('00:00');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (status === 'playing') {
|
if (gameState.status === 'win' || gameState.status === 'loose') {
|
||||||
setStartedTime(Date.now());
|
|
||||||
} else if (status === 'win' || status === 'loose') {
|
|
||||||
setStartedTime(null);
|
setStartedTime(null);
|
||||||
}
|
}
|
||||||
}, [status]);
|
}, [gameState.status]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (startedTime) {
|
if (!startedTime && gameState.endType === '' && gameState.status === 'playing') {
|
||||||
|
const now = Date.now();
|
||||||
|
setStartedTime(now);
|
||||||
|
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
const elapsedTime = (Date.now() - startedTime) / 1000;
|
const elapsedTime = (Date.now() - now) / 1000;
|
||||||
|
|
||||||
const seconds = Math.floor(elapsedTime % 60);
|
const seconds = Math.floor(elapsedTime % 60);
|
||||||
const strSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`;
|
const strSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`;
|
||||||
@@ -41,9 +43,19 @@ const Timer = () => {
|
|||||||
setDisplayedTime(`${strMinute}:${strSeconds}`);
|
setDisplayedTime(`${strMinute}:${strSeconds}`);
|
||||||
}, 500);
|
}, 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 (
|
return (
|
||||||
<div className='statContainer'>
|
<div className='statContainer'>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export const gameStateAtom = atom({
|
|||||||
gridSize: 12,
|
gridSize: 12,
|
||||||
bombs: 0,
|
bombs: 0,
|
||||||
placedFlags: 0,
|
placedFlags: 0,
|
||||||
gameTime: 0,
|
gameTime: '',
|
||||||
endType: '',
|
endType: '',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -31,9 +31,6 @@ export const genBombs = (grid: GridType, difficulty: Difficulty) => {
|
|||||||
bombs = surface * 0.15;
|
bombs = surface * 0.15;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(difficulty);
|
|
||||||
// console.log(surface, surface * 0.05, bombs);
|
|
||||||
|
|
||||||
bombs = Math.floor(bombs);
|
bombs = Math.floor(bombs);
|
||||||
for (let i = 1; i <= bombs; i++) {
|
for (let i = 1; i <= bombs; i++) {
|
||||||
let needRegenerate = false;
|
let needRegenerate = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user