Showing
6 changed files
with
360 additions
and
316 deletions
... | @@ -8,6 +8,7 @@ import { | ... | @@ -8,6 +8,7 @@ import { |
8 | Record, | 8 | Record, |
9 | Union, | 9 | Union, |
10 | Static, | 10 | Static, |
11 | + Optional, | ||
11 | } from "runtypes"; | 12 | } from "runtypes"; |
12 | import { | 13 | import { |
13 | Role, | 14 | Role, |
... | @@ -48,7 +49,12 @@ export class ServerInboundMessageRecordMap { | ... | @@ -48,7 +49,12 @@ export class ServerInboundMessageRecordMap { |
48 | }); | 49 | }); |
49 | 50 | ||
50 | // 방장이 게임을 시작합니다. | 51 | // 방장이 게임을 시작합니다. |
51 | - startGame = Record({}); | 52 | + // TODO: 주의! 아래 필드는 디버그 용도로만 사용됩니다. 추후에 준비 화면에서 공개적으로 설정하는 것으로 구현해야 합니다. |
53 | + startGame = Record({ | ||
54 | + maxRound: Optional(Number), | ||
55 | + roundDuration: Optional(Number), | ||
56 | + roundTerm: Optional(Number), | ||
57 | + }); | ||
52 | 58 | ||
53 | // drawer가 단어를 선택합니다. | 59 | // drawer가 단어를 선택합니다. |
54 | chooseWord = Record({ | 60 | chooseWord = Record({ | ... | ... |
... | @@ -54,6 +54,14 @@ export class Connection { | ... | @@ -54,6 +54,14 @@ export class Connection { |
54 | } | 54 | } |
55 | 55 | ||
56 | // Game > Room > User 순으로 전달 | 56 | // Game > Room > User 순으로 전달 |
57 | + if (this.user?.room?.game) { | ||
58 | + const response = this.user.room.game.handler.handle( | ||
59 | + type, | ||
60 | + this.user, | ||
61 | + message | ||
62 | + ); | ||
63 | + if (response) return response; | ||
64 | + } | ||
57 | if (this.user?.room) { | 65 | if (this.user?.room) { |
58 | const response = this.user.room.handler.handle(type, this.user, message); | 66 | const response = this.user.room.handler.handle(type, this.user, message); |
59 | if (response) return response; | 67 | if (response) return response; | ... | ... |
1 | +import { Role } from "../../common/dataType"; | ||
2 | +import { MessageHandler } from "../message/MessageHandler"; | ||
3 | +import { Room } from "../room/Room"; | ||
1 | import { User } from "../user/User"; | 4 | import { User } from "../user/User"; |
2 | 5 | ||
3 | -export interface Game { | 6 | +export class Game { |
4 | - join(user: User): void; | 7 | + room: Room; |
5 | - leave(user: User): void; | 8 | + maxRound: number; |
9 | + round: number = 0; | ||
10 | + roundState: "choosing" | "running" | "done" = "choosing"; | ||
11 | + roundDuration: number; | ||
12 | + readonly roundTerm: number = 5; // 다음 라운드 시작까지 기다리는 시간 | ||
13 | + wordCandidates: string[] = []; | ||
14 | + word: string = ""; | ||
15 | + timer: { | ||
16 | + startTimeMillis: number; | ||
17 | + timeLeftMillis: number; | ||
18 | + running: boolean; | ||
19 | + } = { startTimeMillis: 0, timeLeftMillis: 0, running: false }; | ||
20 | + timeoutTimerId?: NodeJS.Timeout; | ||
21 | + nextRoundTimerId?: NodeJS.Timeout; | ||
22 | + | ||
23 | + brush: { | ||
24 | + size: number; | ||
25 | + color: string; | ||
26 | + drawing: boolean; | ||
27 | + x: number; | ||
28 | + y: number; | ||
29 | + } = { | ||
30 | + size: 24, | ||
31 | + color: "000000", | ||
32 | + drawing: false, | ||
33 | + x: 0, | ||
34 | + y: 0, | ||
35 | + }; | ||
36 | + | ||
37 | + handler: MessageHandler; | ||
38 | + roles: Map<User, Role>; | ||
39 | + drawer?: User; | ||
40 | + | ||
41 | + constructor( | ||
42 | + room: Room, | ||
43 | + maxRound: number, | ||
44 | + roundDuration: number, | ||
45 | + roundTerm: number | ||
46 | + ) { | ||
47 | + this.room = room; | ||
48 | + | ||
49 | + // TODO: 방장이 설정 | ||
50 | + this.maxRound = maxRound; | ||
51 | + this.roundDuration = roundDuration; | ||
52 | + this.roundTerm = roundTerm; | ||
53 | + | ||
54 | + this.handler = new MessageHandler({ | ||
55 | + chooseWord: (user, message) => { | ||
56 | + if (user !== this.drawer || this.roundState !== "choosing") { | ||
57 | + return { ok: false }; | ||
58 | + } | ||
59 | + | ||
60 | + const chosen = message.word; | ||
61 | + if (this.wordCandidates.includes(chosen)) { | ||
62 | + this.wordSelected(chosen); | ||
63 | + return { ok: true }; | ||
64 | + } | ||
65 | + return { ok: false }; | ||
66 | + }, | ||
67 | + chat: (user, message) => { | ||
68 | + const text = message.message.trim(); | ||
69 | + if (this.roles.get(user) === "guesser" && text === this.word) { | ||
70 | + this.acceptAnswer(user); | ||
71 | + } else { | ||
72 | + this.room.sendChat(user, text); | ||
73 | + } | ||
74 | + return { ok: true }; | ||
75 | + }, | ||
76 | + setBrush: (user, message) => { | ||
77 | + if (user !== this.drawer || !/^[0-9a-f]{6}$/.test(message.color)) { | ||
78 | + return { ok: false }; | ||
79 | + } | ||
80 | + | ||
81 | + this.brush.size = Math.max(Math.min(message.size, 64), 1); | ||
82 | + this.brush.color = message.color; | ||
83 | + this.brush.drawing = message.drawing; | ||
84 | + | ||
85 | + this.room.broadcast( | ||
86 | + "setBrush", | ||
87 | + { | ||
88 | + size: this.brush.size, | ||
89 | + color: this.brush.color, | ||
90 | + drawing: this.brush.drawing, | ||
91 | + }, | ||
92 | + user | ||
93 | + ); | ||
94 | + | ||
95 | + return { ok: true }; | ||
96 | + }, | ||
97 | + moveBrush: (user, message) => { | ||
98 | + if (user !== this.drawer) { | ||
99 | + return { ok: false }; | ||
100 | + } | ||
101 | + | ||
102 | + this.brush.x = Math.max(Math.min(message.x, 1), 0); | ||
103 | + this.brush.y = Math.max(Math.min(message.y, 1), 0); | ||
104 | + | ||
105 | + this.room.broadcast( | ||
106 | + "moveBrush", | ||
107 | + { | ||
108 | + x: this.brush.x, | ||
109 | + y: this.brush.y, | ||
110 | + }, | ||
111 | + user | ||
112 | + ); | ||
113 | + | ||
114 | + return { ok: true }; | ||
115 | + }, | ||
116 | + }); | ||
117 | + | ||
118 | + this.roles = new Map<User, Role>(); | ||
119 | + | ||
120 | + this.startNextRound(); | ||
121 | + } | ||
122 | + | ||
123 | + private startNextRound(): void { | ||
124 | + this.roundState = "choosing"; | ||
125 | + this.round++; | ||
126 | + | ||
127 | + this.roles.clear(); | ||
128 | + | ||
129 | + this.drawer = this.pickDrawer(); | ||
130 | + this.room.users.forEach((user) => this.roles.set(user, "guesser")); | ||
131 | + this.roles.set(this.drawer, "drawer"); | ||
132 | + | ||
133 | + this.room.broadcast("startRound", { | ||
134 | + round: this.round, | ||
135 | + duration: this.roundDuration, | ||
136 | + roles: this.makeRoleArray(), | ||
137 | + }); | ||
138 | + | ||
139 | + this.wordCandidates = this.pickWords(); | ||
140 | + this.drawer.connection.send("wordSet", { words: this.wordCandidates }); | ||
141 | + } | ||
142 | + | ||
143 | + private wordSelected(word: string): void { | ||
144 | + this.word = word; | ||
145 | + this.roundState = "running"; | ||
146 | + | ||
147 | + this.room.broadcast("wordChosen", { length: word.length }); | ||
148 | + | ||
149 | + this.startTimer(this.roundDuration * 1000); | ||
150 | + | ||
151 | + this.timeoutTimerId = setTimeout( | ||
152 | + () => this.finishRound(), | ||
153 | + this.roundDuration * 1000 | ||
154 | + ); | ||
155 | + } | ||
156 | + | ||
157 | + public finishRound(): void { | ||
158 | + if (this.timeoutTimerId) { | ||
159 | + clearTimeout(this.timeoutTimerId); | ||
160 | + this.timeoutTimerId = undefined; | ||
161 | + } | ||
162 | + | ||
163 | + this.roundState = "done"; | ||
164 | + | ||
165 | + this.stopTimer(); | ||
166 | + | ||
167 | + this.room.broadcast("finishRound", { answer: this.word }); | ||
168 | + | ||
169 | + this.prepareNextRound(); | ||
170 | + } | ||
171 | + | ||
172 | + private prepareNextRound(): void { | ||
173 | + this.nextRoundTimerId = setTimeout(() => { | ||
174 | + if (this.round == this.maxRound) { | ||
175 | + this.finishGame(); | ||
176 | + } else { | ||
177 | + this.startNextRound(); | ||
178 | + } | ||
179 | + }, this.roundTerm * 1000); | ||
180 | + } | ||
181 | + | ||
182 | + private finishGame(): void { | ||
183 | + this.room.broadcast("finishGame", {}); | ||
184 | + | ||
185 | + this.room.finishGame(); | ||
186 | + } | ||
187 | + | ||
188 | + private forceFinishGame() { | ||
189 | + if (this.timeoutTimerId) { | ||
190 | + clearTimeout(this.timeoutTimerId); | ||
191 | + } | ||
192 | + if (this.nextRoundTimerId) { | ||
193 | + clearTimeout(this.nextRoundTimerId); | ||
194 | + } | ||
195 | + this.room.broadcast("finishRound", { answer: this.word }); | ||
196 | + this.finishGame(); | ||
197 | + } | ||
198 | + | ||
199 | + private acceptAnswer(user: User): void { | ||
200 | + user.connection.send("answerAccepted", { answer: this.word }); | ||
201 | + this.changeRole(user, "winner"); | ||
202 | + | ||
203 | + let noGuesser = true; | ||
204 | + this.roles.forEach((role, user) => { | ||
205 | + if (role === "guesser") { | ||
206 | + noGuesser = false; | ||
207 | + } | ||
208 | + }); | ||
209 | + | ||
210 | + if (noGuesser) { | ||
211 | + this.finishRound(); | ||
212 | + } | ||
213 | + } | ||
214 | + | ||
215 | + private pickDrawer(): User { | ||
216 | + const candidates = this.room.users.filter((user) => user !== this.drawer); | ||
217 | + return candidates[Math.floor(Math.random() * candidates.length)]; | ||
218 | + } | ||
219 | + | ||
220 | + private pickWords(): string[] { | ||
221 | + return ["장난감", "백화점", "파티"]; | ||
222 | + } | ||
223 | + | ||
224 | + private startTimer(timeLeftMillis: number): void { | ||
225 | + this.timer = { | ||
226 | + startTimeMillis: Date.now(), | ||
227 | + timeLeftMillis, | ||
228 | + running: true, | ||
229 | + }; | ||
230 | + this.room.users.forEach((user) => this.sendTimer(user)); | ||
231 | + } | ||
232 | + | ||
233 | + private stopTimer(): void { | ||
234 | + this.timer = { | ||
235 | + ...this.timer, | ||
236 | + running: false, | ||
237 | + }; | ||
238 | + this.room.users.forEach((user) => this.sendTimer(user)); | ||
239 | + } | ||
240 | + | ||
241 | + private sendTimer(user: User): void { | ||
242 | + user.connection.send("timer", { | ||
243 | + state: this.timer.running ? "started" : "stopped", | ||
244 | + time: Math.max( | ||
245 | + (this.timer.startTimeMillis + this.timer.timeLeftMillis - Date.now()) / | ||
246 | + 1000, | ||
247 | + 0 | ||
248 | + ), | ||
249 | + }); | ||
250 | + } | ||
251 | + | ||
252 | + private makeRoleArray(): { username: string; role: Role }[] { | ||
253 | + let roleArray: { | ||
254 | + username: string; | ||
255 | + role: Role; | ||
256 | + }[] = []; | ||
257 | + this.roles.forEach((role, user) => | ||
258 | + roleArray.push({ username: user.username, role: role }) | ||
259 | + ); | ||
260 | + return roleArray; | ||
261 | + } | ||
262 | + | ||
263 | + private changeRole(user: User, role: Role) { | ||
264 | + this.roles.set(user, role); | ||
265 | + this.room.broadcast("role", { username: user.username, role }); | ||
266 | + } | ||
267 | + | ||
268 | + join(user: User): void { | ||
269 | + this.changeRole(user, "spectator"); | ||
270 | + this.sendTimer(user); | ||
271 | + user.connection.send("startRound", { | ||
272 | + round: this.round, | ||
273 | + duration: this.roundDuration, | ||
274 | + roles: this.makeRoleArray(), | ||
275 | + }); | ||
276 | + if (this.roundState === "done") { | ||
277 | + user.connection.send("finishRound", { | ||
278 | + answer: this.word, | ||
279 | + }); | ||
280 | + } | ||
281 | + user.connection.send("setBrush", { | ||
282 | + size: this.brush.size, | ||
283 | + color: this.brush.color, | ||
284 | + drawing: this.brush.drawing, | ||
285 | + }); | ||
286 | + user.connection.send("moveBrush", { | ||
287 | + x: this.brush.x, | ||
288 | + y: this.brush.y, | ||
289 | + }); | ||
290 | + } | ||
291 | + | ||
292 | + leave(user: User): void { | ||
293 | + if (this.room.users.length < 2) { | ||
294 | + this.forceFinishGame(); | ||
295 | + return; | ||
296 | + } | ||
297 | + | ||
298 | + this.roles.delete(user); | ||
299 | + | ||
300 | + if (user === this.drawer) { | ||
301 | + if (this.roundState === "choosing") { | ||
302 | + this.round--; // 이번 라운드를 다시 시작 | ||
303 | + this.startNextRound(); | ||
304 | + } else if (this.roundState === "running") { | ||
305 | + this.finishRound(); | ||
306 | + } | ||
307 | + } else { | ||
308 | + let guesserCount = 0; | ||
309 | + this.roles.forEach((role, user) => { | ||
310 | + if (role === "guesser") { | ||
311 | + guesserCount++; | ||
312 | + } | ||
313 | + }); | ||
314 | + if (guesserCount < 1) { | ||
315 | + if (this.roundState === "choosing") { | ||
316 | + this.round--; | ||
317 | + this.startNextRound(); | ||
318 | + } else if (this.roundState === "running") { | ||
319 | + this.finishRound(); | ||
320 | + } | ||
321 | + } | ||
322 | + } | ||
323 | + } | ||
6 | } | 324 | } | ... | ... |
server/game/WordGuessingGame.ts
deleted
100644 → 0
1 | -import { Role } from "../../common/dataType"; | ||
2 | -import { MessageHandler } from "../message/MessageHandler"; | ||
3 | -import { Room } from "../room/Room"; | ||
4 | -import { User } from "../user/User"; | ||
5 | -import { Game } from "./Game"; | ||
6 | - | ||
7 | -export class WorldGuessingGame implements Game { | ||
8 | - room: Room; | ||
9 | - maxRound: number; | ||
10 | - round: number = 0; | ||
11 | - roundState: "choosing" | "running" | "done" = "choosing"; | ||
12 | - roundDuration: number; | ||
13 | - readonly roundTerm: number = 5; // 다음 라운드 시작까지 기다리는 시간 | ||
14 | - wordCandidates: string[] = []; | ||
15 | - word: string = ""; | ||
16 | - timer: { | ||
17 | - startTimeMillis: number; | ||
18 | - timeLeftMillis: number; | ||
19 | - running: boolean; | ||
20 | - } = { startTimeMillis: 0, timeLeftMillis: 0, running: false }; | ||
21 | - timeoutTimerId?: NodeJS.Timeout; | ||
22 | - nextRoundTimerId?: NodeJS.Timeout; | ||
23 | - | ||
24 | - brush: { | ||
25 | - size: number; | ||
26 | - color: string; | ||
27 | - drawing: boolean; | ||
28 | - x: number; | ||
29 | - y: number; | ||
30 | - } = { | ||
31 | - size: 24, | ||
32 | - color: "000000", | ||
33 | - drawing: false, | ||
34 | - x: 0, | ||
35 | - y: 0, | ||
36 | - }; | ||
37 | - | ||
38 | - handler: MessageHandler; | ||
39 | - roles: Map<User, Role>; | ||
40 | - drawer?: User; | ||
41 | - | ||
42 | - constructor(room: Room) { | ||
43 | - this.room = room; | ||
44 | - | ||
45 | - // TODO: 방장이 설정 | ||
46 | - this.maxRound = 5; | ||
47 | - this.roundDuration = 60; | ||
48 | - | ||
49 | - this.handler = new MessageHandler({ | ||
50 | - chooseWord: (user, message) => { | ||
51 | - if (user !== this.drawer || this.roundState === "choosing") { | ||
52 | - return { ok: false }; | ||
53 | - } | ||
54 | - | ||
55 | - const chosen = message.word; | ||
56 | - if (this.wordCandidates.includes(chosen)) { | ||
57 | - this.wordSelected(chosen); | ||
58 | - return { ok: true }; | ||
59 | - } | ||
60 | - return { ok: false }; | ||
61 | - }, | ||
62 | - chat: (user, message) => { | ||
63 | - const text = message.message.trim(); | ||
64 | - if (this.roles.get(user) === "guesser" && text === this.word) { | ||
65 | - this.acceptAnswer(user); | ||
66 | - } else { | ||
67 | - this.room.sendChat(user, text); | ||
68 | - } | ||
69 | - return { ok: true }; | ||
70 | - }, | ||
71 | - setBrush: (user, message) => { | ||
72 | - if (user !== this.drawer || !/^[0-9a-f]{6}$/.test(message.color)) { | ||
73 | - return { ok: false }; | ||
74 | - } | ||
75 | - | ||
76 | - this.brush.size = Math.max(Math.min(message.size, 64), 1); | ||
77 | - this.brush.color = message.color; | ||
78 | - this.brush.drawing = message.drawing; | ||
79 | - | ||
80 | - this.room.broadcast( | ||
81 | - "setBrush", | ||
82 | - { | ||
83 | - size: this.brush.size, | ||
84 | - color: this.brush.color, | ||
85 | - drawing: this.brush.drawing, | ||
86 | - }, | ||
87 | - user | ||
88 | - ); | ||
89 | - | ||
90 | - return { ok: true }; | ||
91 | - }, | ||
92 | - moveBrush: (user, message) => { | ||
93 | - if (user !== this.drawer) { | ||
94 | - return { ok: false }; | ||
95 | - } | ||
96 | - | ||
97 | - this.brush.x = Math.max(Math.min(message.x, 1), 0); | ||
98 | - this.brush.y = Math.max(Math.min(message.y, 1), 0); | ||
99 | - | ||
100 | - this.room.broadcast( | ||
101 | - "moveBrush", | ||
102 | - { | ||
103 | - x: this.brush.x, | ||
104 | - y: this.brush.y, | ||
105 | - }, | ||
106 | - user | ||
107 | - ); | ||
108 | - | ||
109 | - return { ok: true }; | ||
110 | - }, | ||
111 | - }); | ||
112 | - | ||
113 | - this.roles = new Map<User, Role>(); | ||
114 | - | ||
115 | - this.startNextRound(); | ||
116 | - } | ||
117 | - | ||
118 | - private startNextRound(): void { | ||
119 | - this.roundState = "choosing"; | ||
120 | - this.round++; | ||
121 | - | ||
122 | - this.roles.clear(); | ||
123 | - | ||
124 | - this.drawer = this.pickDrawer(); | ||
125 | - this.room.users.forEach((user) => this.roles.set(user, "guesser")); | ||
126 | - this.roles.set(this.drawer, "drawer"); | ||
127 | - | ||
128 | - this.room.broadcast("startRound", { | ||
129 | - round: this.round, | ||
130 | - duration: this.roundDuration, | ||
131 | - roles: this.makeRoleArray(), | ||
132 | - }); | ||
133 | - | ||
134 | - this.wordCandidates = this.pickWords(); | ||
135 | - this.drawer.connection.send("wordSet", { words: this.wordCandidates }); | ||
136 | - } | ||
137 | - | ||
138 | - private wordSelected(word: string): void { | ||
139 | - this.word = word; | ||
140 | - this.roundState = "running"; | ||
141 | - | ||
142 | - this.room.broadcast("wordChosen", { length: word.length }); | ||
143 | - | ||
144 | - this.startTimer(this.roundDuration * 1000); | ||
145 | - | ||
146 | - this.timeoutTimerId = setTimeout( | ||
147 | - this.finishRound, | ||
148 | - this.roundDuration * 1000 | ||
149 | - ); | ||
150 | - } | ||
151 | - | ||
152 | - private finishRound(): void { | ||
153 | - if (this.timeoutTimerId) { | ||
154 | - clearTimeout(this.timeoutTimerId); | ||
155 | - this.timeoutTimerId = undefined; | ||
156 | - } | ||
157 | - | ||
158 | - this.roundState = "done"; | ||
159 | - | ||
160 | - this.stopTimer(); | ||
161 | - | ||
162 | - this.room.broadcast("finishRound", { answer: this.word }); | ||
163 | - | ||
164 | - this.prepareNextRound(); | ||
165 | - } | ||
166 | - | ||
167 | - private prepareNextRound(): void { | ||
168 | - this.nextRoundTimerId = setTimeout(() => { | ||
169 | - if (this.round == this.maxRound) { | ||
170 | - this.finishGame(); | ||
171 | - } else { | ||
172 | - this.startNextRound(); | ||
173 | - } | ||
174 | - }, this.roundTerm * 1000); | ||
175 | - } | ||
176 | - | ||
177 | - private finishGame(): void { | ||
178 | - this.room.broadcast("finishGame", {}); | ||
179 | - | ||
180 | - this.room.finishGame(); | ||
181 | - } | ||
182 | - | ||
183 | - private forceFinishGame() { | ||
184 | - if (this.timeoutTimerId) { | ||
185 | - clearTimeout(this.timeoutTimerId); | ||
186 | - } | ||
187 | - if (this.nextRoundTimerId) { | ||
188 | - clearTimeout(this.nextRoundTimerId); | ||
189 | - } | ||
190 | - this.room.broadcast("finishRound", { answer: this.word }); | ||
191 | - this.finishGame(); | ||
192 | - } | ||
193 | - | ||
194 | - private acceptAnswer(user: User): void { | ||
195 | - user.connection.send("answerAccepted", { answer: this.word }); | ||
196 | - this.changeRole(user, "winner"); | ||
197 | - } | ||
198 | - | ||
199 | - private pickDrawer(): User { | ||
200 | - const candidates = this.room.users.filter((user) => user !== this.drawer); | ||
201 | - return candidates[Math.floor(Math.random() * candidates.length)]; | ||
202 | - } | ||
203 | - | ||
204 | - private pickWords(): string[] { | ||
205 | - return ["장난감", "백화점", "파티"]; | ||
206 | - } | ||
207 | - | ||
208 | - private startTimer(timeLeftMillis: number): void { | ||
209 | - this.timer = { | ||
210 | - startTimeMillis: Date.now(), | ||
211 | - timeLeftMillis, | ||
212 | - running: true, | ||
213 | - }; | ||
214 | - } | ||
215 | - | ||
216 | - private stopTimer(): void { | ||
217 | - this.timer = { | ||
218 | - ...this.timer, | ||
219 | - running: false, | ||
220 | - }; | ||
221 | - this.room.users.forEach((user) => this.sendTimer(user)); | ||
222 | - } | ||
223 | - | ||
224 | - private sendTimer(user: User): void { | ||
225 | - user.connection.send("timer", { | ||
226 | - state: this.timer.running ? "started" : "stopped", | ||
227 | - time: Math.max( | ||
228 | - (this.timer.startTimeMillis + this.timer.timeLeftMillis - Date.now()) / | ||
229 | - 1000, | ||
230 | - 0 | ||
231 | - ), | ||
232 | - }); | ||
233 | - } | ||
234 | - | ||
235 | - private makeRoleArray(): { username: string; role: Role }[] { | ||
236 | - let roleArray: { | ||
237 | - username: string; | ||
238 | - role: Role; | ||
239 | - }[] = []; | ||
240 | - this.roles.forEach((role, user) => | ||
241 | - roleArray.push({ username: user.username, role: role }) | ||
242 | - ); | ||
243 | - return roleArray; | ||
244 | - } | ||
245 | - | ||
246 | - private changeRole(user: User, role: Role) { | ||
247 | - this.roles.set(user, role); | ||
248 | - this.room.broadcast("role", { username: user.username, role }); | ||
249 | - } | ||
250 | - | ||
251 | - join(user: User): void { | ||
252 | - this.changeRole(user, "spectator"); | ||
253 | - this.sendTimer(user); | ||
254 | - user.connection.send("startRound", { | ||
255 | - round: this.round, | ||
256 | - duration: this.roundDuration, | ||
257 | - roles: this.makeRoleArray(), | ||
258 | - }); | ||
259 | - if (this.roundState === "done") { | ||
260 | - user.connection.send("finishRound", { | ||
261 | - answer: this.word, | ||
262 | - }); | ||
263 | - } | ||
264 | - user.connection.send("setBrush", { | ||
265 | - size: this.brush.size, | ||
266 | - color: this.brush.color, | ||
267 | - drawing: this.brush.drawing, | ||
268 | - }); | ||
269 | - user.connection.send("moveBrush", { | ||
270 | - x: this.brush.x, | ||
271 | - y: this.brush.y, | ||
272 | - }); | ||
273 | - } | ||
274 | - | ||
275 | - leave(user: User): void { | ||
276 | - if (this.room.users.length < 2) { | ||
277 | - this.forceFinishGame(); | ||
278 | - return; | ||
279 | - } | ||
280 | - | ||
281 | - this.roles.delete(user); | ||
282 | - | ||
283 | - if (user === this.drawer) { | ||
284 | - if (this.roundState === "choosing") { | ||
285 | - this.round--; // 이번 라운드를 다시 시작 | ||
286 | - this.startNextRound(); | ||
287 | - } else if (this.roundState === "running") { | ||
288 | - this.finishRound(); | ||
289 | - } | ||
290 | - } else { | ||
291 | - let guesserCount = 0; | ||
292 | - this.roles.forEach((role, user) => { | ||
293 | - if (role === "guesser") { | ||
294 | - guesserCount++; | ||
295 | - } | ||
296 | - }); | ||
297 | - if (guesserCount < 1) { | ||
298 | - if (this.roundState === "choosing") { | ||
299 | - this.round--; | ||
300 | - this.startNextRound(); | ||
301 | - } else if (this.roundState === "running") { | ||
302 | - this.finishRound(); | ||
303 | - } | ||
304 | - } | ||
305 | - } | ||
306 | - } | ||
307 | -} |
... | @@ -16,7 +16,7 @@ | ... | @@ -16,7 +16,7 @@ |
16 | }, | 16 | }, |
17 | "scripts": { | 17 | "scripts": { |
18 | "start": "nodemon index.ts", | 18 | "start": "nodemon index.ts", |
19 | - "test": "nyc mocha -r ts-node/register ./**/*.test.ts", | 19 | + "test": "nyc mocha -r ts-node/register --timeout 8000 ./**/*.test.ts", |
20 | "build": "tsc -b -v" | 20 | "build": "tsc -b -v" |
21 | }, | 21 | }, |
22 | "devDependencies": { | 22 | "devDependencies": { | ... | ... |
... | @@ -10,7 +10,6 @@ import { | ... | @@ -10,7 +10,6 @@ import { |
10 | import { RoomDescription, RoomInfo, UserData } from "../../common/dataType"; | 10 | import { RoomDescription, RoomInfo, UserData } from "../../common/dataType"; |
11 | import { RoomManager } from "./RoomManager"; | 11 | import { RoomManager } from "./RoomManager"; |
12 | import { Game } from "../game/Game"; | 12 | import { Game } from "../game/Game"; |
13 | -import { WorldGuessingGame } from "../game/WordGuessingGame"; | ||
14 | 13 | ||
15 | export class Room { | 14 | export class Room { |
16 | public readonly uuid: string; | 15 | public readonly uuid: string; |
... | @@ -72,7 +71,23 @@ export class Room { | ... | @@ -72,7 +71,23 @@ export class Room { |
72 | if (!result.ok) { | 71 | if (!result.ok) { |
73 | return result; | 72 | return result; |
74 | } | 73 | } |
75 | - this.startGame(); | 74 | + |
75 | + // TODO: 방장이 따로 메세지를 보내 설정할 수 있도록 수정해주세요. | ||
76 | + const settings = message; | ||
77 | + if (!settings.maxRound) { | ||
78 | + settings.maxRound = 5; | ||
79 | + } | ||
80 | + if (!settings.roundDuration) { | ||
81 | + settings.roundDuration = 60; | ||
82 | + } | ||
83 | + if (!settings.roundTerm) { | ||
84 | + settings.roundTerm = 5; | ||
85 | + } | ||
86 | + this.startGame( | ||
87 | + settings.maxRound, | ||
88 | + settings.roundDuration, | ||
89 | + settings.roundTerm | ||
90 | + ); | ||
76 | return { ok: true }; | 91 | return { ok: true }; |
77 | }, | 92 | }, |
78 | }); | 93 | }); |
... | @@ -179,8 +194,12 @@ export class Room { | ... | @@ -179,8 +194,12 @@ export class Room { |
179 | return { ok: true }; | 194 | return { ok: true }; |
180 | } | 195 | } |
181 | 196 | ||
182 | - private startGame(): void { | 197 | + private startGame( |
183 | - this.game = new WorldGuessingGame(this); | 198 | + maxRound: number, |
199 | + roundDuration: number, | ||
200 | + roundTerm: number | ||
201 | + ): void { | ||
202 | + this.game = new Game(this, maxRound, roundDuration, roundTerm); | ||
184 | } | 203 | } |
185 | 204 | ||
186 | public finishGame(): void { | 205 | public finishGame(): void { | ... | ... |
-
Please register or login to post a comment