feat : add sounds

This commit is contained in:
GuillaumeSD
2024-03-20 04:57:37 +01:00
parent 32fc196e74
commit 9e497cb24b
15 changed files with 74 additions and 26 deletions

BIN
public/sounds/capture.webm Normal file

Binary file not shown.

BIN
public/sounds/castle.webm Normal file

Binary file not shown.

BIN
public/sounds/game-end.webm Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/sounds/move.webm Normal file

Binary file not shown.

BIN
public/sounds/promote.webm Normal file

Binary file not shown.

View File

@@ -1,4 +1,5 @@
import { setGameHeaders } from "@/lib/chess"; import { setGameHeaders } from "@/lib/chess";
import { playIllegalMoveSound, playSoundFromMove } from "@/lib/sounds";
import { Chess, Move } from "chess.js"; import { Chess, Move } from "chess.js";
import { PrimitiveAtom, useAtom } from "jotai"; import { PrimitiveAtom, useAtom } from "jotai";
import { useCallback } from "react"; import { useCallback } from "react";
@@ -39,17 +40,23 @@ export const useChessActions = (chessAtom: PrimitiveAtom<Chess>) => {
const makeMove = useCallback( const makeMove = useCallback(
(move: { from: string; to: string; promotion?: string }): Move | null => { (move: { from: string; to: string; promotion?: string }): Move | null => {
const newGame = copyGame(); const newGame = copyGame();
const result = newGame.move(move); try {
setGame(newGame); const result = newGame.move(move);
setGame(newGame);
return result; playSoundFromMove(result);
return result;
} catch {
playIllegalMoveSound();
return null;
}
}, },
[copyGame, setGame] [copyGame, setGame]
); );
const undoMove = useCallback(() => { const undoMove = useCallback(() => {
const newGame = copyGame(); const newGame = copyGame();
newGame.undo(); const move = newGame.undo();
if (move) playSoundFromMove(move);
setGame(newGame); setGame(newGame);
}, [copyGame, setGame]); }, [copyGame, setGame]);

View File

@@ -247,3 +247,8 @@ export const getStartingFen = (
return history[0].before; return history[0].before;
}; };
export const isCheck = (fen: string): boolean => {
const game = new Chess(fen);
return game.inCheck();
};

35
src/lib/sounds.ts Normal file
View File

@@ -0,0 +1,35 @@
import { Move } from "chess.js";
import { getWhoIsCheckmated, isCheck } from "./chess";
const playSound = async (url: string) => {
const audio = new Audio(url);
await audio.play();
};
export const playCaptureSound = () => playSound("/sounds/capture.webm");
export const playCastleSound = () => playSound("/sounds/castle.webm");
export const playGameEndSound = () => playSound("/sounds/game-end.webm");
export const playGameStartSound = () => playSound("/sounds/game-start.webm");
export const playIllegalMoveSound = () =>
playSound("/sounds/illegal-move.webm");
export const playMoveCheckSound = () => playSound("/sounds/move-check.webm");
export const playMoveSound = () => playSound("/sounds/move.webm");
export const playPromoteSound = () => playSound("/sounds/promote.webm");
export const playSoundFromMove = async (move: Move | null) => {
if (!move) {
playIllegalMoveSound();
} else if (getWhoIsCheckmated(move.after)) {
playGameEndSound();
} else if (isCheck(move.after)) {
playMoveCheckSound();
} else if (move.promotion) {
playPromoteSound();
} else if (move.captured) {
playCaptureSound();
} else if (move.flags.includes("k") || move.flags.includes("q")) {
playCastleSound();
} else {
playMoveSound();
}
};

View File

@@ -40,17 +40,13 @@ export default function Board() {
target: Square, target: Square,
piece: string piece: string
): boolean => { ): boolean => {
try { const result = makeBoardMove({
const result = makeBoardMove({ from: source,
from: source, to: target,
to: target, promotion: piece[1]?.toLowerCase() ?? "q",
promotion: piece[1]?.toLowerCase() ?? "q", });
});
return !!result; return !!result;
} catch {
return false;
}
}; };
const handleSquareLeftClick = () => { const handleSquareLeftClick = () => {

View File

@@ -70,17 +70,14 @@ export default function Board() {
piece: string piece: string
): boolean => { ): boolean => {
if (!piece || piece[0] !== playerColor || !isGameInProgress) return false; if (!piece || piece[0] !== playerColor || !isGameInProgress) return false;
try {
const result = makeGameMove({
from: source,
to: target,
promotion: piece[1]?.toLowerCase() ?? "q",
});
return !!result; const result = makeGameMove({
} catch { from: source,
return false; to: target,
} promotion: piece[1]?.toLowerCase() ?? "q",
});
return !!result;
}; };
const isPieceDraggable = ({ piece }: { piece: string }): boolean => { const isPieceDraggable = ({ piece }: { piece: string }): boolean => {

View File

@@ -2,6 +2,7 @@ import { Button, CircularProgress, Grid, Typography } from "@mui/material";
import { useAtom, useAtomValue } from "jotai"; import { useAtom, useAtomValue } from "jotai";
import { gameAtom, isGameInProgressAtom } from "./states"; import { gameAtom, isGameInProgressAtom } from "./states";
import { useEffect } from "react"; import { useEffect } from "react";
import { playGameEndSound } from "@/lib/sounds";
export default function GameInProgress() { export default function GameInProgress() {
const game = useAtomValue(gameAtom); const game = useAtomValue(gameAtom);
@@ -11,6 +12,11 @@ export default function GameInProgress() {
if (game.isGameOver()) setIsGameInProgress(false); if (game.isGameOver()) setIsGameInProgress(false);
}, [game, setIsGameInProgress]); }, [game, setIsGameInProgress]);
const handleResign = () => {
playGameEndSound();
setIsGameInProgress(false);
};
if (!isGameInProgress) return null; if (!isGameInProgress) return null;
return ( return (
@@ -42,7 +48,7 @@ export default function GameInProgress() {
xs={12} xs={12}
gap={2} gap={2}
> >
<Button variant="outlined" onClick={() => setIsGameInProgress(false)}> <Button variant="outlined" onClick={handleResign}>
Resign Resign
</Button> </Button>
</Grid> </Grid>

View File

@@ -26,6 +26,7 @@ import {
gameAtom, gameAtom,
} from "../states"; } from "../states";
import { useChessActions } from "@/hooks/useChessActions"; import { useChessActions } from "@/hooks/useChessActions";
import { playGameStartSound } from "@/lib/sounds";
interface Props { interface Props {
open: boolean; open: boolean;
@@ -49,6 +50,7 @@ export default function GameSettingsDialog({ open, onClose }: Props) {
blackName: blackName:
playerColor === Color.Black ? "You" : `Stockfish level ${skillLevel}`, playerColor === Color.Black ? "You" : `Stockfish level ${skillLevel}`,
}); });
playGameStartSound();
setIsGameInProgress(true); setIsGameInProgress(true);
}; };