Showing
3 changed files
with
111 additions
and
17 deletions
... | @@ -3,7 +3,11 @@ import { Vector } from './types'; | ... | @@ -3,7 +3,11 @@ import { Vector } from './types'; |
3 | 3 | ||
4 | // 참고 : https://basketdeveloper.tistory.com/79 | 4 | // 참고 : https://basketdeveloper.tistory.com/79 |
5 | 5 | ||
6 | -export const Canvas: React.FC = () => { | 6 | +interface CanvasProps { |
7 | + isDrawer: boolean; | ||
8 | +} | ||
9 | + | ||
10 | +export const Canvas: React.FC<CanvasProps> = ({ isDrawer }) => { | ||
7 | const canvasRef = useRef<HTMLCanvasElement>(null); | 11 | const canvasRef = useRef<HTMLCanvasElement>(null); |
8 | 12 | ||
9 | const [mousePosition, setMousePosition] = useState<Vector>({ x:0, y:0 }); | 13 | const [mousePosition, setMousePosition] = useState<Vector>({ x:0, y:0 }); |
... | @@ -77,7 +81,7 @@ export const Canvas: React.FC = () => { | ... | @@ -77,7 +81,7 @@ export const Canvas: React.FC = () => { |
77 | }, []); | 81 | }, []); |
78 | 82 | ||
79 | useEffect(() => { | 83 | useEffect(() => { |
80 | - if (canvasRef.current) { | 84 | + if (canvasRef.current && isDrawer) { |
81 | const canvas: HTMLCanvasElement = canvasRef.current; | 85 | const canvas: HTMLCanvasElement = canvasRef.current; |
82 | 86 | ||
83 | canvas.addEventListener('mousedown', startPaint); | 87 | canvas.addEventListener('mousedown', startPaint); |
... | @@ -91,8 +95,10 @@ export const Canvas: React.FC = () => { | ... | @@ -91,8 +95,10 @@ export const Canvas: React.FC = () => { |
91 | canvas.removeEventListener('mouseup', exitPaint); | 95 | canvas.removeEventListener('mouseup', exitPaint); |
92 | canvas.removeEventListener('mouseleave', exitPaint); | 96 | canvas.removeEventListener('mouseleave', exitPaint); |
93 | }; | 97 | }; |
98 | + } else { | ||
99 | + // 받아서 그리기 | ||
94 | } | 100 | } |
95 | - }, [startPaint, paint, exitPaint]); | 101 | + }, [isDrawer, startPaint, paint, exitPaint]); |
96 | 102 | ||
97 | return ( | 103 | return ( |
98 | <div className='mx-3 px-2 py-1 rounded shadow'> | 104 | <div className='mx-3 px-2 py-1 rounded shadow'> | ... | ... |
web/src/components/room/GameBoard.tsx
0 → 100644
1 | +import React, { useCallback, useContext, useEffect, useState } from 'react'; | ||
2 | +import { useLocation } from 'react-router'; | ||
3 | +import SocketContext from '../../contexts/SocketContext'; | ||
4 | +import { MessageType, RawMessage } from '../common/types'; | ||
5 | +import { Canvas } from './Canvas'; | ||
6 | +import { Role, RoundData } from './types'; | ||
7 | +import { Word } from './Word'; | ||
8 | + | ||
9 | +interface GameBoardLocation { | ||
10 | + state: { username: string } | ||
11 | +} | ||
12 | + | ||
13 | +interface GameBoardProps { | ||
14 | + isInGame: boolean | ||
15 | +} | ||
16 | + | ||
17 | +export const GameBoard: React.FC<GameBoardProps> = ({ isInGame }) => { | ||
18 | + const socket = useContext(SocketContext); | ||
19 | + const location: GameBoardLocation = useLocation(); | ||
20 | + | ||
21 | + const [ isDrawer, setIsDrawer ] = useState(false); | ||
22 | + const [ words, setWords ] = useState<string[]>([]); | ||
23 | + const [ wordChosen, setWordChosen ] = useState(''); | ||
24 | + | ||
25 | + const handleWordSet = useCallback((rawMessage: RawMessage) => { | ||
26 | + if (rawMessage.type === MessageType.GAME_WORDSET) { | ||
27 | + console.log('단어 도착'); | ||
28 | + const { words } = rawMessage.message as { words: string[] }; | ||
29 | + setWords(words); | ||
30 | + } | ||
31 | + }, []); | ||
32 | + | ||
33 | + const handleStart = useCallback((rawMessage: RawMessage) => { | ||
34 | + if (rawMessage.type === MessageType.GAME_START) { | ||
35 | + setWords([]); | ||
36 | + | ||
37 | + const data = rawMessage.message as RoundData; | ||
38 | + console.log('테스트 location ', location.state.username); | ||
39 | + console.log('테스트 rolse ', data.roles); | ||
40 | + const index = data.roles.findIndex(x => x.username === location.state.username); | ||
41 | + setIsDrawer(data.roles[index].role === 'drawer'); | ||
42 | + setWordChosen(''); | ||
43 | + } | ||
44 | + }, []); | ||
45 | + | ||
46 | + const handleGetWordLength = useCallback((rawMessage: RawMessage) => { | ||
47 | + if (rawMessage.type === MessageType.GAME_WORD) { | ||
48 | + if (wordChosen !== '') { | ||
49 | + const { length } = rawMessage.message as { length: number }; | ||
50 | + setWordChosen('_'.repeat(length)); | ||
51 | + } | ||
52 | + } | ||
53 | + }, [wordChosen]); | ||
54 | + | ||
55 | + useEffect(() => { | ||
56 | + socket.on('msg', handleStart); | ||
57 | + socket.on('msg', handleGetWordLength); | ||
58 | + socket.on('msg', handleWordSet); | ||
59 | + | ||
60 | + return () => { | ||
61 | + socket.off('msg', handleStart); | ||
62 | + socket.off('msg', handleGetWordLength); | ||
63 | + socket.off('msg', handleWordSet); | ||
64 | + } | ||
65 | + }, []); | ||
66 | + | ||
67 | + return ( | ||
68 | + <div className={`w-auto ${isInGame ? '' : 'hidden'}`}> | ||
69 | + <div className='w-full flex flex-col justify-center items-center'> | ||
70 | + {words.map((word, i) => (<Word key={word} index={i} word={word} setWordChosen={setWordChosen} setWords={setWords} />))} | ||
71 | + </div> | ||
72 | + <Canvas isDrawer={isDrawer && wordChosen !== ''}/> | ||
73 | + </div> | ||
74 | + ); | ||
75 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -4,6 +4,7 @@ import { Main } from '../components/common/Main'; | ... | @@ -4,6 +4,7 @@ import { Main } from '../components/common/Main'; |
4 | import { MessageResponse, MessageType, RawMessage } from '../components/common/types'; | 4 | import { MessageResponse, MessageType, RawMessage } from '../components/common/types'; |
5 | import { Canvas } from '../components/room/Canvas'; | 5 | import { Canvas } from '../components/room/Canvas'; |
6 | import { Chat } from '../components/room/Chat'; | 6 | import { Chat } from '../components/room/Chat'; |
7 | +import { GameBoard } from '../components/room/GameBoard'; | ||
7 | import { Ready } from '../components/room/Ready'; | 8 | import { Ready } from '../components/room/Ready'; |
8 | import { RoomInfo } from '../components/room/RoomInfo'; | 9 | import { RoomInfo } from '../components/room/RoomInfo'; |
9 | import { RoomData, UpdateRoomUser } from '../components/room/types'; | 10 | import { RoomData, UpdateRoomUser } from '../components/room/types'; |
... | @@ -29,6 +30,14 @@ export const Room: React.FC = () => { | ... | @@ -29,6 +30,14 @@ export const Room: React.FC = () => { |
29 | }); | 30 | }); |
30 | const [ isInGame, setIsInGame ] = useState(false); | 31 | const [ isInGame, setIsInGame ] = useState(false); |
31 | 32 | ||
33 | + const handleInGame = useCallback((rawMessage: RawMessage) => { | ||
34 | + if (rawMessage.type === MessageType.GAME_START) { | ||
35 | + setIsInGame(true); | ||
36 | + } else if (rawMessage.type === MessageType.GAME_FINISH_GAME) { | ||
37 | + setIsInGame(false); | ||
38 | + } | ||
39 | + }, []); | ||
40 | + | ||
32 | const handleUpdateRoomUser = useCallback((rawMessage: RawMessage) => { | 41 | const handleUpdateRoomUser = useCallback((rawMessage: RawMessage) => { |
33 | if (rawMessage.type == MessageType.ROOM_USER_UPDATE) { | 42 | if (rawMessage.type == MessageType.ROOM_USER_UPDATE) { |
34 | const data = rawMessage.message as UpdateRoomUser; | 43 | const data = rawMessage.message as UpdateRoomUser; |
... | @@ -81,8 +90,11 @@ export const Room: React.FC = () => { | ... | @@ -81,8 +90,11 @@ export const Room: React.FC = () => { |
81 | } | 90 | } |
82 | 91 | ||
83 | setRoomData(location.state.roomData); | 92 | setRoomData(location.state.roomData); |
93 | + socket.on('msg', handleInGame); | ||
84 | 94 | ||
85 | return () => { | 95 | return () => { |
96 | + socket.off('msg', handleInGame); | ||
97 | + | ||
86 | const rawMessage: RawMessage = { | 98 | const rawMessage: RawMessage = { |
87 | type: MessageType.ROOM_LEAVE, | 99 | type: MessageType.ROOM_LEAVE, |
88 | message: '' | 100 | message: '' |
... | @@ -94,20 +106,21 @@ export const Room: React.FC = () => { | ... | @@ -94,20 +106,21 @@ export const Room: React.FC = () => { |
94 | return ( | 106 | return ( |
95 | <Main> | 107 | <Main> |
96 | <RoomInfo roomData={roomData}/> | 108 | <RoomInfo roomData={roomData}/> |
97 | - { | 109 | + <div className='w-full flex'> |
98 | - isInGame ? ( | 110 | + {/* 게임보드를 계속 살려둬서 리스너를 항상 열어놓도록 하자 */} |
99 | - <div className='w-full flex'> | 111 | + <GameBoard isInGame={isInGame} /> |
100 | - <Canvas /> | 112 | + { |
101 | - <Chat w='w-4/12' h='h-80' /> | 113 | + isInGame ? ( |
102 | - </div> | 114 | + <Chat w='w-4/12' h='h-80' /> |
103 | - ) : ( | 115 | + ) : ( |
104 | - <div className='w-full flex flex-col justify-center items-center'> | 116 | + <div className='w-full flex flex-col justify-center items-center'> |
105 | - <UserInfo users={roomData.users}/> | 117 | + <UserInfo users={roomData.users}/> |
106 | - <Ready users={roomData.users} /> | 118 | + <Ready users={roomData.users} /> |
107 | - <Chat w='w-7/12' h='h-96' /> | 119 | + <Chat w='w-7/12' h='h-96' /> |
108 | - </div> | 120 | + </div> |
109 | - ) | 121 | + ) |
110 | - } | 122 | + } |
123 | + </div> | ||
111 | </Main> | 124 | </Main> |
112 | ); | 125 | ); |
113 | } | 126 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
-
Please register or login to post a comment