-
스파르타) Ch.5 팀 프로젝트 - 타워 디펜스 온라인 (D-3)TIL-sparta 2024. 7. 16. 00:12
> 과제 진행 간 완료한 사항 및 문제점과 해결 과정을 정리해보았다.학습 키워드: Node.js, javascript, Redis, context
1. 완료한 과제 진행 사항
1) Redis 코드 수정, 핸들러 구현 등:
export const userRedisFields = { UUID: 'uuid', TOKEN: 'token', }; const userRedisFieldsArray = Object.values(userRedisFields); export const isUserRedisField = (fieldName) => { return userRedisFieldsArray.includes(fieldName); }; // -------- setUserData: async function (userId, obj) { try { for (const [key, value] of Object.entries(obj)) { const snakeKey = transformCase(key, caseTypes.SNAKE_CASE); if (isUserRedisField(snakeKey)) { const redisKey = `${USER_PREFIX}${userId}:${snakeKey}`; await redisClient.set(redisKey, JSON.stringify(value)); } } } catch (err) { console.error('setUserData failed:', err); } },
Redis util 함수에 몇 가지 부가 기능을 추가하고 field 이름(여기서는 key의 맨 뒷 부분을 말함)들을 별도의 constants 파일로 매핑하여 사용하도록 수정했다. setUserData 함수의 경우 두 번째 인자로 객체를 받아서 key가 매핑되어있는 정보와 일치하는지 확인하고 값을 추가하는 방식으로 세팅하여 추가적인 함수 구현이 필요없도록 만들었다.
몬스터가 기지를 공격하는 이벤트에 대한 핸들러를 생성했다. Redis에 정보를 저장하는 과정에서 userId 키 사용에 혼선이 있어 undefined 키를 사용하게되어 결과가 나오지는 않았으나 기본적인 틀은 갖춰놨기 때문에 추후에 정확한 key 이름을 전달받으면 수정할 예정이다.
2. 과제 진행 간 문제점
1) TypeError가 발생하는 문제 (해결):
gameLoop() { this.ctx.drawImage(this.backgroundImage, 0, 0, this.canvas.width, this.canvas.height); // 에러 this.drawPath(this.monsterPath, this.ctx); this.ctx.font = '25px Times New Roman'; this.ctx.fillStyle = 'skyblue'; this.ctx.fillText(`최고 기록: ${this.highScore}`, 100, 50); this.ctx.fillStyle = 'white'; ... requestAnimationFrame(this.gameLoop); }
게임이 매칭되어 실행됐을 때 game 객체의 ctx에 접근이 불가능한 현상이 있었다. 처음에는 원인을 파악 못하고 나름대로 추리하여 게임 인스턴스 생성 시점도 수정해봤는데 변화가 없었다. 그러다가 에러 메세지를 다시 한 번 읽어보니 ctx가 undefined로 부터 호출된다는 걸 상기하고 this가 없는 이유, 즉 context를 상실하는 이유를 찾게 되었다.
gameloop가 requestAnimationFrame의 인자로 들어가면서 context를 잃은 단순한 문제였다. 함수를 넘겨줄 때 this를 bind 하는 것으로 해결했다.
2) 적 기지가 그려지지 않던 문제 (해결):
// public/src/game.js ... placeBase(position, isPlayer) { if (isPlayer) { this.base = new Base(position.x, position.y, this.baseHp); this.base.draw(this.ctx, this.baseImage); } else { this.opponentBase = new Base(position.x, position.y, this.baseHp); this.opponentBase.draw(this.opponentCtx, this.baseImage, true); } } ... gameLoop() { this.ctx.drawImage(this.backgroundImage, 0, 0, this.canvas.width, this.canvas.height); ... this.base.draw(this.ctx, this.baseImage); this.opponentBase.draw(this.opponentCtx, this.baseImage); ... // 상대방 게임 화면 업데이트 this.opponentCtx.drawImage(this.backgroundImage, 0, 0, this.opponentCanvas.width, this.opponentCanvas.height); this.drawPath(this.opponentMonsterPath, this.opponentCtx); requestAnimationFrame(this.gameLoop.bind(this)); } ...
적 기지의 값이 모두 설정되어있는데 기지 이미지가 화면에 나타나지 않는 문제가 있었다. 로그를 확인해가며 조사해봤지만 값이 모두 정상이어서 어리둥절하고 있다가 팀원과 다 같이 상의하던 중 '값이 모두 정상이라면 이미지는 실제로 이미 그려진 것이 아닌가?' 라는 의문을 가짐과 동시에 그려지는 순서가 원인임을 깨닫게 되었다. 기존 gameloop에서 첫 번째 줄에 자신의 canvas에 배경 이미지를 우선 그린 뒤 나머지 이미지를 그리고 있었는데, 새로 추가한 적 기지 코드의 경우 기지 이미지를 배경 이미지보다 먼저 그리고 있어서 화면 전체를 덮는 배경 이미지가 먼저 그려졌던 기지 이미지를 가리게 되는 것이었다. 아래와 같이 순서를 변경하여 해결했다.
... gameLoop() { this.ctx.drawImage(this.backgroundImage, 0, 0, this.canvas.width, this.canvas.height); ... this.base.draw(this.ctx, this.baseImage); // this.opponentBase.draw(this.opponentCtx, this.baseImage); // 기존 위치 ... // 상대방 게임 화면 업데이트 this.opponentCtx.drawImage(this.backgroundImage, 0, 0, this.opponentCanvas.width, this.opponentCanvas.height); this.drawPath(this.opponentMonsterPath, this.opponentCtx); this.opponentBase.draw(this.opponentCtx, this.baseImage); // 새 위치 requestAnimationFrame(this.gameLoop.bind(this)); } ...
--
REFERENCES:> 과제 spec
> 과제 repo
728x90'TIL-sparta' 카테고리의 다른 글
스파르타) Ch.5 팀 프로젝트 - 타워 디펜스 온라인 (D-1) (0) 2024.07.18 스파르타) Ch.5 팀 프로젝트 - 타워 디펜스 온라인 (D-2) (0) 2024.07.17 스파르타) Ch.5 팀 프로젝트 - 타워 디펜스 온라인 (D-4) (0) 2024.07.14 스파르타) Ch.5 팀 프로젝트 - 타워 디펜스 온라인 (D-5) (2) 2024.07.14 스파르타) Ch.5 팀 프로젝트 - 타워 디펜스 온라인 (D-6) (0) 2024.07.12