@@ -23,6 +23,7 @@ import {
23
23
import {
24
24
useAuthStore ,
25
25
useGameStore ,
26
+ useMuteStore ,
26
27
} from "../../store.js"
27
28
import {
28
29
useLayoutStore ,
@@ -37,6 +38,16 @@ import {
37
38
import {
38
39
GamePanel ,
39
40
} from "./GamePanel.jsx"
41
+ import {
42
+ Howl ,
43
+ } from "howler"
44
+ import {
45
+ FaVolumeMute ,
46
+ FaVolumeUp ,
47
+ } from "react-icons/fa"
48
+ import {
49
+ IconContext ,
50
+ } from "react-icons"
40
51
41
52
export const Game = ( ) => {
42
53
let [ cursor_x , setCursor_x ] = useState ( - 1 )
@@ -65,6 +76,14 @@ export const Game = () => {
65
76
let sidebarWidth = useLayoutStore ( state => state . sidebarWidth . game )
66
77
let vw = useLayoutStore ( state => state . vw )
67
78
let dragging = useLayoutStore ( state => state . dragging )
79
+ let muted = useMuteStore ( state => state . muted )
80
+ let setMuteState = useMuteStore ( ( state ) => state . setMuted )
81
+ let sound = useMemo ( ( ) => new Howl ( {
82
+ src : [ "/app/stone1.wav" ] ,
83
+ onloaderror : function ( id , error ) {
84
+ throw new Error ( id + ": " + error )
85
+ }
86
+ } ) , [ ] )
68
87
69
88
let context = useMemo ( ( ) => {
70
89
let dim = board . length
@@ -184,11 +203,22 @@ export const Game = () => {
184
203
if ( ! isSelfPlay ( ) ) { // myColor is 0 in self play
185
204
addMove ( { ...move , color : myColor } )
186
205
}
206
+ if ( ! muted ) {
207
+ sound . play ( ) ;
208
+ }
187
209
stompClient . publish ( {
188
210
destination : "/app/game/move" ,
189
211
body : JSON . stringify ( move ) ,
190
212
} )
191
- } , [ context , currentPlayer , currentColor , auth , board , stompClient , counting , forbidden_x , forbidden_y , gameHasEnded , movesLength , addMove , isSelfPlay , myColor ] )
213
+ } , [ context , currentPlayer , currentColor , auth , board , stompClient , counting , forbidden_x , forbidden_y , gameHasEnded , movesLength , addMove , isSelfPlay , myColor , muted ] )
214
+
215
+ let onMuteClick = useCallback ( ( ) => {
216
+ if ( muted ) {
217
+ setMuteState ( false )
218
+ } else {
219
+ setMuteState ( true )
220
+ }
221
+ } , [ setMuteState , muted ] )
192
222
193
223
useEffect ( ( ) => {
194
224
if ( ! board . length ) {
@@ -256,22 +286,39 @@ export const Game = () => {
256
286
}
257
287
258
288
return (
259
- < div
260
- style = { { width : ( vw - sidebarWidth ) + "px" } }
261
- className = "h-full" >
262
- < div className = "grid h-full" >
263
- < canvas className = "place-self-center" ref = { canvasRef }
264
- onMouseLeave = { ( ) => {
265
- setCursor_x ( - 1 )
266
- setCursor_y ( - 1 )
267
- } }
268
- onMouseMove = { onMouseMove }
269
- onClick = { onClick }
270
- width = { context . width } height = { context . width } >
271
- </ canvas >
289
+ < div
290
+ style = { { width : ( vw - sidebarWidth ) + "px" } }
291
+ className = "h-full" >
292
+ < div className = "grid h-full" >
293
+ < canvas className = "place-self-center" ref = { canvasRef }
294
+ onMouseLeave = { ( ) => {
295
+ setCursor_x ( - 1 )
296
+ setCursor_y ( - 1 )
297
+ } }
298
+ onMouseMove = { onMouseMove }
299
+ onClick = { onClick }
300
+ width = { context . width } height = { context . width } >
301
+ </ canvas >
302
+ </ div >
303
+ < div
304
+ style = { { right : ( sidebarWidth + 12 ) + "px" } }
305
+ className = "absolute bottom-4" >
306
+ < button onClick = { onMuteClick } >
307
+ < IconContext . Provider value = { {
308
+ size : "1.5em" ,
309
+ className : "pl-[4px]" ,
310
+ } } >
311
+ { muted && (
312
+ < FaVolumeMute />
313
+ ) }
314
+ { ! muted && (
315
+ < FaVolumeUp />
316
+ ) }
317
+ </ IconContext . Provider >
318
+ </ button >
319
+ </ div >
320
+ < GamePanel />
272
321
</ div >
273
- < GamePanel />
274
- </ div >
275
322
)
276
323
}
277
324
0 commit comments