부트캠프를 수료 후 학원이라는 장소를 벗어나 팀원들을 모으고 처음으로 시작한 프로젝트로 캐치마인드의 기능을 클론한 웹용 드로잉 퀴즈게임을 주제로 선정했다.
처음 시작은 학원에서는 어느 정도의 가이드를 부여하고 그 가이드에 부합하는 사이트나 어플리케이션을 찾아 클론하는 정도의 프로젝트를 하도록 되어있었는데 팀원들과의 공통적인 의견은 학원에서처럼 주어진 가이드가 있는것이 아닌 우리가 관심이 가고 평소에 해보고 싶었던 것을 만들어보자는 의견이었다.
의견을 종합하고 계획하는 부분에 있어서도 많은 시간을 필요로 했다.
웹으로 동작하는 음악 플레이어 , 실시간 채팅앱 , 주접 생성기(?) , 그 중 내가 의견을 제시한것은 이력서 작성기였지만 아무래도 다른 주제들에 비해 흥미가 좀 떨어진다는 의견들이 있어 기각되고 실시간 기능들을 집합시킨 캐치마인드 같은 게임을 할 수 있는 웹을 만드는것이 어떻겠냐는 의견이 채택됐다.
프로젝트 이름을 팀원들과 투표로 정하고 MVP를 위한 기본기능들을 회의 때마다 작성했다.
물론 본격적으로 프로젝트가 시작된 이후에 수정된 부분이 존재한다.
프로젝트가 진행되는 동안은 zira를 통해 프로젝트 진행상황을 팀원들과 공유했다.
AWS S3와 AWS RDS를 연결해 스와이프 할때마다 색상변경
플레이어 인원 수 , 드로잉 타임 , 라운드 설정
들어온 순서대로 플레이어 정렬
연필 마크있는 플레이어에게만 보이는 정답
연필 마크 없으면 캔버스에 드로잉 불가
라운드 넘어가는 순간부터 타이머 작동
채팅 스크롤 가능
정해진 라운드 종료시 통합 스코어와 우승자 닉네임 보여주기
// socket 그림 그리기 권한
socket.on("pencil", async ({ isRound, roomId }) => {
// socket.on으로 인한 데이터 확인용
console.log(`라운드 & 룸 아이디 : ${isRound} , ${roomId} `);
const updatePencilAdmin = await gameRoomDao.updatePencilAdminForRound(
isRound,
roomId
);
console.log(`함수 호출결과 : ${updatePencilAdmin}`);
const gameroomInfo = await gameRoomDao.getGameroomInfo(roomId);
const updateRound = await gameRoomDao.updateRoundNumberToDB(
isRound,
roomId
);
const finalRoundNumber = await gameRoomDao.getRoundNumberFromDB(roomId);
io.emit("pencilUpdate", gameroomInfo);
io.emit("pencil", finalRoundNumber);
});
// 라운드 변경 시 pencilAdmin 업데이트
const updatePencilAdminForRound = async (roundNumber, roomId) => {
try {
const userIdsInRoom = await getUserIdsInRoom(roomId);
const totalUsers = userIdsInRoom.length;
const pencilAdminIndex = (roundNumber - 1) % totalUsers;
console.log(
`유저 수 : ${totalUsers} , 라운드 넘버 : ${roundNumber} , 펜슬 인덱스 : ${pencilAdminIndex}`
);
// pencilAdmin 값을 업데이트
await updatePencilAdmin(roomId, userIdsInRoom, pencilAdminIndex);
// 업데이트된 방 정보를 반환
const updatedGameroomInfo = await getGameroomInfo(roomId);
return updatedGameroomInfo;
} catch (error) {
console.error(
"현재 라운드에 대한 연필권한 업데이트 중 오류가 발생했습니다.",
error
);
throw error;
}
};
// updatePencilAdmin 함수 정의
const updatePencilAdmin = async (roomId, userIdsInRoom, pencilAdminIndex) => {
try {
console.log("펜슬 어드민 인덱스 : ", pencilAdminIndex);
for (let i = 0; i < userIdsInRoom.length; i++) {
const userId = userIdsInRoom[i];
let pencilAdmin = pencilAdminIndex === i ? 1 : 0;
console.log("pencilAdmin : ", pencilAdmin);
// 데이터베이스에 연필 권한을 업데이트하는 SQL 쿼리
await appDataSource.query(
`
UPDATE users
SET pencilAdmin = ?
WHERE id = ? AND id IN (
SELECT users_id FROM enrolled_players WHERE users_id = ? AND rooms_id = ?
);
`,
[pencilAdmin, userId, userId, roomId]
);
}
} catch (error) {
console.error("pencilAdmin 업데이트 중 오류가 발생했습니다.", error);
throw error;
}
};
const pencilAdminIndex = roundNumber % totalUsers;
// 유저 수가 5명이고 라운드 설정을 6라운드로 설정했을 당시 계산 오류때문에 진행되지 않음.
// pencilAdminIndex를 잘못 계산해 라운드 번호가 유저수를 초과하는 경우에 잘못된 인덱스가 계산되는 것을 인지
const pencilAdminIndex = (roundNumber - 1) % totalUsers;
// 인덱스는 0부터 시작한다는것을 더 이상 까먹지 않게 된 이유
프로젝트를 진행하면서 어려웠던 점은 socket.io의 배경지식이 너무나 부족하다는 것을 느껴 실시간 기능의 2/3 이상을 맡은 나로써는 진행 중간에 팀원들의 눈치를 볼 수 밖에 없었다.
그럴때 일수록 더욱 불타는 감정을 느낀것도 있다. 물론 진행기간이 늘어지는 경우는 없었지만,
내가 이것을 정확하게 알고 팀원들에게 전달해 프로젝트를 원활하게 진행해야 한다는 생각이 들었고
스택오버플로우와 공식문서를 더욱 들여보게 되었다. 이미 비슷한 프로젝트를 진행한 개발자 분들의 깃허브도 참고했지만 나에게는 스택오버플로우처럼 어떤 문제에 있어서 해결한 히스토리가 보이는 부분이 공부에 도움이 된다고 느껴졌다. 그 중 제일 곤욕을 치룬 부분은 권한에 대한 부분이었다.
실시간으로 권한을 이동시켰어야 했고 그 부분을 처리하기 위해서 DB에서 그리기권한에 대한 부분을 만들어야했고 그 권한을 UPDATE 시켰어야 했다.
라운드 별로 게임룸에 들어와있는 유저들의 인덱스를 확인해서 다음 인덱스로 권한을 넘기는 과정을 작성하는데 어려움을 느꼈다. 인덱스 계산방법을 바꾼 후 처리할 수 있었고 팀원들과의 도움을 주고받는 과정에서 많은 오류와 해결책을 찾을 수 있었는데 그 방식을 통해 팀원들과 소통이 얼마나 중요한지 또 한번 깨닫게되고 성장할 수 있는 계기가 된것 같다.