8.5 KiB
8.5 KiB
Context: Arena Picker 개발 가이드
1. 모듈별 상세 역할
[Core Engine]
src/main.js: Phaser 게임의 전역 설정(Physics, Scale, Canvas Parent)을 담당하며,ArenaScene을 인스턴스화합니다.- 앱 로드 시
trackVisitor()를 호출해 방문자 체크 API와 연동합니다.
- 앱 로드 시
src/constants.js: 게임 내 모든 튜닝 수치를 관리합니다.ATTACK_DAMAGE_MIN,ATTACK_DAMAGE_MAX: 일반 공격 1회 적중 시 적용되는 랜덤 피해량 범위.FIGHTER_HITBOX_*: 100x100 캐릭터 프레임 안에서 실제 충돌 판정이 놓이는 위치와 크기.KILL_HEALTH_RECOVERY_RATIO,KILL_GROWTH_MULTIPLIER: 처치 후 회복량과 크기/공격속도/이동속도 성장 배율.SELECTED_FIGHTER_OUTLINE_GAP,SELECTED_FIGHTER_OUTLINE_WIDTH,SELECTED_FIGHTER_OUTLINE_ALPHA: 선택 실루엣의 캐릭터 이격 거리, 두께, 투명도.SPECTATOR_CAMERA_LERP: 카메라 추적의 부드러움 정도.MINIMAP_VIEWPORT_SIZE: 미니맵의 고정 픽셀 크기.ARENA_SIZE: 경기장 전체 크기 (GRID * TILE).
[Server/API - server/]
server/index.js:- Fastify 서버 진입점입니다.
- 개발 모드에서는
@fastify/middie로 Vite 미들웨어를 붙이고,/api/*요청은 Vite SPA fallback이 가로채지 않도록 Fastify 라우트로 통과시킵니다. - 운영 모드(
npm start)에서는@fastify/static으로dist/를 서빙하고, HTML 요청은index.html로 fallback합니다.
server/config.js:config.json을 읽어 서버 포트, MongoDB host/port/db/user/pass, 쿠키 보안 옵션을 정규화합니다.MONGODB_URI가 직접 있으면 우선 사용하고, 없으면MONGODB_HOST/MONGODB_PORT기반으로 URI를 조립합니다.
server/db.js:MongoClient를 한 번 생성한 뒤 재사용하여 MongoDB 커넥션 풀을 유지합니다.- 종료 시
closeMongoConnection()으로 커넥션을 닫습니다.
server/visitors.js:POST /api/visitors/check:arena_visitor_idHttpOnly쿠키를 확인하고 없으면 UUID를 발급합니다.- MongoDB
visitors컬렉션에_id = visitorId로 upsert해 방문자 1명당 1개 문서를 유지합니다. GET /api/visitors/stats: 전체 유니크 방문자 수를 반환합니다.
[Game Logic - src/game/]
ArenaScene.js:update(): 매 프레임 생존 팀을 체크하고 스코어보드를 갱신합니다.observeCombat(): 캐릭터가 공격할 때 카메라가 주목할 "관전 대상"을 설정합니다.selectFighter(),focusSelectedFighter(): 캐릭터 클릭 시 선택 상태를 설정하고 해당 캐릭터의 히트박스 중심으로 카메라를 고정합니다.updateMinimapViewportFrame(): 주 카메라의 이동에 맞춰 미니맵 가이드 사각형을 렌더링합니다.
matchSetup.js:- 입력된 닉네임을 순회하여
team객체를 생성하고, 요청된 인원만큼 캐릭터 데이터를 복제 배치합니다.
- 입력된 닉네임을 순회하여
combat.js:updateFighter(): 가장 가까운 적을 찾아 이동하거나 공격하는 유닛 AI의 핵심입니다.applyHit(): 일반 공격 피해량은ATTACK_DAMAGE_MIN/MAX범위에서 계산합니다.applyKillReward(): 처치한 캐릭터의 체력 회복, 크기 증가, 공격속도/이동속도 배율 증가를 처리합니다.projectilePathHitsDefender(): 투사체가 대상을 스쳐 지나가지 않도록 궤적 검사를 수행합니다.
[Assets & UI]
fighterAssets.js: 원본 캐릭터 스프라이트의 alpha 값을 읽어 선택용 노란 실루엣 spritesheet를 런타임에 생성합니다. 원본 주변 1px은 비워두고 그 바깥 1px만 칠해 선택 윤곽이 캐릭터에 붙어 보이지 않도록 합니다.fighterFactory.js: 캐릭터 히트박스, 이름표, 체력바, 선택 실루엣 sprite를 생성하고 매 프레임 위치/스케일/방향을 동기화합니다. 이름표는 스프라이트 중심이 아니라 실제 히트박스 하단에 고정됩니다.fighterManifest.js: 20여 종의 캐릭터 스킨 정보가 담긴 딕셔너리입니다.type(melee/projectile/instant-spell)에 따라 전투 메커니즘이 결정됩니다.matchForm.js:index.html의 입력을 읽어ArenaScene에 매치 구성을 전달합니다.visitorCounter.js:POST /api/visitors/check를 호출하고, 응답의uniqueVisitors값을#visitor-count에 표시합니다.
2. 주요 로직 구현 세부 사항
지능형 카메라 추적 (Lerp & Jittering 방지)
카메라가 소수점 단위의 평균 좌표를 즉시 따라가면 화면이 떨려 보일 수 있습니다. 이를 방지하기 위해:
- 목표 좌표(
targetX, targetY)를Math.round()로 정수화합니다. - 현재 카메라 위치에서 목표 지점까지 매 프레임
0.1의 배율로 거리를 좁혀나가는Lerp연산을 수행합니다.
this.cameras.main.scrollX += (targetX - this.cameras.main.midPoint.x) * SPECTATOR_CAMERA_LERP;
미니맵 가이드라인
미니맵은 전장 전체를 축소하여 보여주는 독립된 카메라입니다. 주 카메라가 비추는 영역을 계산하여 미니맵 위에 사각형(graphics)을 그려줍니다.
camera.displayWidth / zoom등을 이용하여 현재 월드에서 보이는 실제 영역 크기를 계산합니다.
캐릭터 선택 실루엣
선택 표시는 히트박스 사각형이 아니라 캐릭터 모양을 따라가는 별도 spritesheet입니다.
fighterAssets.js가 로드된 원본 스프라이트시트의 alpha 데이터를 캔버스에서 읽습니다.- 원본 alpha 픽셀 주변
SELECTED_FIGHTER_OUTLINE_GAP범위는 공백 마스크로 남깁니다. - 그 바깥
SELECTED_FIGHTER_OUTLINE_WIDTH범위에만 노란색 outline을 칠합니다. fighterFactory.js가 선택된 캐릭터 뒤에 outline sprite를 배치하고, 현재 texture frame, flip 방향, scale, 위치를 원본 캐릭터와 동기화합니다.
이 방식은 별도 에셋 없이도 캐릭터 모양에 맞춘 선택 윤곽을 만들 수 있으며, 캐릭터가 처치 보상으로 커져도 윤곽이 같은 배율로 따라갑니다.
유니크 방문자 체크
브라우저가 직접 MongoDB에 연결하지 않고, Fastify API가 MongoDB 커넥션 풀을 유지합니다.
- 프론트엔드가 앱 로드 시
POST /api/visitors/check를 호출합니다. - 서버가
arena_visitor_id쿠키를 검사합니다. - 쿠키가 없거나 유효하지 않으면
crypto.randomUUID()로 새 방문자 ID를 만들고HttpOnly쿠키로 내려줍니다. - MongoDB에는
_id,firstSeenAt,lastSeenAt,visits,firstUserAgent,lastUserAgent를 저장합니다. countDocuments()로 전체 유니크 방문자 수를 계산해 반환합니다.
방문자 체크는 인증 기능이 아니며, 브라우저/쿠키 단위의 단순 유니크 카운트입니다.
3. 개발 및 유지보수 규칙
- 신규 캐릭터 추가:
public/assets/characters/에 에셋 배치 후fighterManifest.js에 정의를 추가하면 즉시 게임에 반영됩니다. - 물리 수치 조정: 캐릭터의 속도나 사거리 등은
src/constants.js또는fighterManifest.js내 개별 설정을 통해 변경하십시오. - 공격력 조정: 기본 피해량은
src/constants.js의ATTACK_DAMAGE_MIN,ATTACK_DAMAGE_MAX를 수정합니다. 캐릭터별 특수 공격 방식은fighterManifest.js의combat설정을 우선 확인합니다. - DOM 접근: 성능을 위해
ArenaScene은 상단 스코어보드 등 필요한 시점에만 최소한으로 DOM에 접근합니다. - 서버 설정:
.env대신config.json을 사용합니다.config.json은 로컬 전용 파일이며, 저장소에는config.json.sample만 공유합니다. - 패키지 락 파일: 이 프로젝트는
package-lock.json을 저장소에서 제외합니다. 의존성 변경 시package.json을 기준으로 관리합니다. - 기본 포트:
SERVER_PORT기본값은9736입니다. - MongoDB 연결: DB 접속 정보는
config.json의MONGODB_HOST,MONGODB_PORT,MONGODB_DB, 선택적MONGODB_USER,MONGODB_PASS로 관리합니다. - API 변경:
/api/*경로는 Fastify 라우트가 담당합니다. 개발 모드에서 Vite 미들웨어가 API 요청을 SPA HTML로 처리하지 않도록 서버 라우팅 순서를 유지해야 합니다.