268 lines
23 KiB
Markdown
268 lines
23 KiB
Markdown
# Agent: Arena Picker
|
|
|
|
## 0. 필수
|
|
|
|
- 작업이 완료되면 작업과 관련된 모든 문서를 함께 업데이트한다.
|
|
- 대규모 전투, LOD, 모델/렌더 분리, 전투 워커, 서버 API를 수정할 때는 관련 `context/` 문서를 먼저 확인하고 변경 내용을 문서에 반영한다.
|
|
|
|
## 1. 프로젝트 정의
|
|
|
|
**Arena Picker**는 Phaser 3 게임 엔진과 Vite 번들러를 기반으로 구축된 **대규모 팀 전투 시뮬레이션 웹 애플리케이션**입니다. 사용자가 입력한 여러 참가자 닉네임을 각각 하나의 팀으로 설정하고, `닉네임*N` 형식으로 지정된 인원만큼 캐릭터를 생성해 자동 전투를 시뮬레이션합니다.
|
|
|
|
전장은 3200px 월드 크기를 유지하되 Phaser 내부 렌더 캔버스는 1280px로 낮춰 픽셀 작업량을 줄입니다. 일반 전투는 개별 Phaser Sprite와 Arcade Physics를 사용하고, 3,000명 이상 대규모 전투에서는 `FighterModel` 중심 시뮬레이션, rolling-window LOD, Web Worker 기반 후보 선정/집계 전투, HUD/이펙트 풀링을 결합해 8,000명급 전투를 처리합니다.
|
|
|
|
서버 런타임은 Fastify를 사용하며 MongoDB 커넥션 풀을 유지합니다. 방문자 수, 일일 운영 지표, 전투 사망 통계, About 콘텐츠를 API로 제공합니다.
|
|
|
|
## 2. 현재 아키텍처 핵심
|
|
|
|
### 2.1 FighterModel 기반 상태와 렌더 브리지
|
|
|
|
- `src/game/fighter/fighterModel.js`가 HP, 팀, 스킨, 타깃, 쿨다운, 사망/선택/성장/동결 상태, 모델 좌표를 보관하는 순수 JS 상태 객체를 만듭니다.
|
|
- `fighterFactory.js`는 실제 Phaser Sprite를 생성하고 `fighter.model` 브리지로 기존 `fighter.hp`, `fighter.team` 스타일 접근을 호환합니다.
|
|
- `fighterAdapter.js`는 위치, 거리, 방향, 이동, body enable/disable, 애니메이션, 동결 tint, arena clamp 등 Phaser Sprite 접근의 경계입니다. 전투/카메라/월드 이펙트 코드는 새로 직접 `body`, `setVelocity()`, 애니메이션 API를 만지기보다 adapter를 우선 사용합니다.
|
|
- `ArenaScene`은 `fighterModels`, `fighterByModelId`, `fighterModelById`를 함께 유지합니다. `fighterForModelId()`는 현재 attach된 렌더 Sprite만 반환할 수 있으므로, 전투 로직은 null 가능성을 항상 고려합니다.
|
|
|
|
### 2.2 대규모 전투 렌더 LOD
|
|
|
|
- 대규모 live match는 `PERFORMANCE.LARGE_BATTLE_FIGHTER_THRESHOLD` 이상에서 render LOD를 활성화합니다.
|
|
- full-arena overview는 `PERFORMANCE.LARGE_BATTLE_SPRITE_RENDER_LIMIT`만큼 팀별 대표 Sprite를 유지하고, 나머지 생존자는 팀 색상 dot으로 표시합니다.
|
|
- zoomed, selected, spectator 시점은 rolling camera window 안의 모든 생존자를 detailed Sprite로 승격합니다. 이 경로는 더 이상 별도 zoom cap이나 buffer ratio에 묶이지 않습니다.
|
|
- `src/game/arena/fighterLodWorker.js`는 생존 fighter worker id, position, team key TypedArray를 받아 현재 match/job의 detailed id 목록만 반환합니다. Worker 실패 또는 오류 시 `resolveFighterLodDetailedSet()` 동기 경로로 fallback합니다.
|
|
- LOD 적용은 최초 활성화 때 full sync를 수행한 뒤, 이후에는 이전 detailed set과 다음 set의 차이만 attach/detach합니다.
|
|
- parked fighter는 display/update list에서 빠지고 Arcade World에서도 `world.disable()`로 제거됩니다. 재진입 시 `world.enable()` 후 모델 좌표로 body를 복구합니다.
|
|
- hidden-fighter dot redraw는 zoomed view에서 카메라 viewport와 padding 밖의 dot을 건너뛰어 `Graphics.fillRect()` 비용을 줄입니다.
|
|
|
|
### 2.3 대규모 전투 집계 시뮬레이션
|
|
|
|
- attached/detail fighter는 매 프레임 `updateFighterModel()`로 고정밀 개별 AI를 유지합니다.
|
|
- detached/offscreen fighter는 `team + cell + squad` 단위로 압축되어 coarse movement와 group DPS를 처리합니다. 기본 squad 크기는 `PERFORMANCE.LARGE_BATTLE_AGGREGATE_SQUAD_SIZE`가 제어합니다.
|
|
- `src/game/combat/aggregateCombatWorker.js`는 detached model id, position, HP, team key, 이동속도, DPS, frost flag를 Transferable TypedArray로 받아 집계 전투를 계산합니다.
|
|
- Phaser 상태 변경, death 처리, split-on-death, kill reward, scoreboard, match finish는 여전히 main thread가 소유합니다.
|
|
- Worker 결과는 match id가 일치하고 해당 model이 여전히 detached일 때만 적용합니다. 이미 attach된 fighter, 죽었거나 unregister된 stale id는 무시합니다.
|
|
- Worker 생성 실패 또는 오류 시 기존 동기 집계 전투 경로로 fallback합니다.
|
|
|
|
### 2.4 전투 및 이펙트 최적화
|
|
|
|
- target spatial index는 model 기반으로 구성하되, 대규모 전투에서는 attached/detail model 중심으로 갱신해 8,000명 전체 스캔을 줄입니다.
|
|
- stale `targetModelId`는 null-safe validation으로 정리합니다.
|
|
- instant-spell 공격 시각 효과는 texture별 sprite pool을 재사용합니다. `clearCombatObjects()`는 active pooled effect도 공통 cleanup 경로로 반환합니다.
|
|
- projectile hit detection은 projectile마다 Arcade overlap collider를 만들지 않고 line/rectangle path check와 scratch geometry를 재사용합니다.
|
|
- 대규모 전투에서 critical label, instant-spell sprite, kill-heal sprite, kill-growth tween 같은 보조 효과는 meteor camera focus 중일 때만 노출합니다. damage, heal, 성장 수치 자체는 유지됩니다.
|
|
- world effect는 랜덤 생존자 대신 생존자 밀집도가 가장 높은 tile square를 큰 경고 영역으로 잡고, 내부에 소형 화염/냉기 strike를 분산 투하합니다.
|
|
|
|
### 2.5 카메라, HUD, 서버 지표
|
|
|
|
- 대규모 live match 시작 시 full-arena 최저 줌 대신 평균 생존 위치에 가까운 fighter 주변으로 `CAMERA.LARGE_BATTLE_START_ZOOM`을 적용합니다.
|
|
- scoreboard 팀 버튼을 이미 선택된 팀에 다시 클릭하면 선택을 해제하고 full-arena view로 돌아갑니다.
|
|
- 수동 fighter/team focus와 full-arena return은 `transitionMainCameraTo()`의 Phaser `pan()`/`zoomTo()` tween을 사용합니다.
|
|
- HUD 체력바는 모든 fighter가 영구 소유하지 않고 pool에서 빌려 씁니다. selected fighter와 zoom-visible 후보만 slot을 보유하며, zoom HUD에는 fighter 이름을 표시하지 않습니다.
|
|
- live minimap은 별도 HUD camera와 `Graphics` dot overlay로 렌더링하며 `PERFORMANCE.MINIMAP_REFRESH_MS`로 redraw를 throttle합니다.
|
|
- 서버는 visitor, death stats, daily metrics, About 콘텐츠 API를 제공합니다.
|
|
|
|
## 3. 프로젝트 전체 구조 (Directory Tree)
|
|
|
|
```text
|
|
├── index.html # 메인 HTML 진입점 및 UI 레이아웃
|
|
├── package.json # Phaser, Vite, Fastify, MongoDB 의존성 및 npm scripts
|
|
├── config.json.sample # 공유용 서버/MongoDB 설정 예시
|
|
├── agent.md # 프로젝트 개요 및 에이전트 작업 가이드
|
|
├── todo.md # 작업 내역 및 잔여 이슈 관리
|
|
├── build.sh # 배포/빌드 보조 스크립트
|
|
├── context/ # 상세 개발 가이드
|
|
│ ├── core.md # main.js, constants.js, 렌더/성능 상수, worker entrypoint
|
|
│ ├── arena.md # ArenaScene, camera, minimap, fighter render LOD
|
|
│ ├── combat.md # 전투 AI, model-only combat, aggregate combat, world effects
|
|
│ ├── fighter.md # FighterModel, adapter, factory, HUD pool, team-shadow texture
|
|
│ ├── match-ui.md # 매치 설정, spawn, HUD, kill log, victory UI
|
|
│ ├── server.md # Fastify, MongoDB, visitor/death/daily metrics/About API
|
|
│ ├── style.md # CSS 모듈, 디자인 변수, 반응형/애니메이션 규칙
|
|
│ └── refactor/
|
|
│ └── arena-scene-modularization-work-order.md
|
|
├── server/ # Fastify API 서버 및 MongoDB 연결 관리
|
|
│ ├── index.js # Fastify 진입점, Vite dev middleware, 정적 배포 서빙
|
|
│ ├── config.js # config.json 로드 및 MongoDB URI/컬렉션 설정
|
|
│ ├── db.js # MongoClient 커넥션 풀 생성/재사용/종료
|
|
│ ├── visitorCookie.js # 방문자 UUID 쿠키 읽기/쓰기/검증
|
|
│ ├── visitors.js # 유니크 방문자 체크 및 통계 API
|
|
│ ├── dailyMetrics.js # 일일 방문/전투 시작/전투 종료/후원 클릭 지표 API
|
|
│ ├── deathStats.js # 종족별 전투 사망 통계 API
|
|
│ └── about.js # About 개발자정보/개인정보처리방침 seed 및 조회 API
|
|
├── public/ # 정적 리소스
|
|
│ └── assets/
|
|
│ ├── og-image.png # 공유 미리보기 이미지
|
|
│ ├── effects/
|
|
│ │ ├── heal/ # 처치 회복 연출
|
|
│ │ ├── world_Effect.png
|
|
│ │ └── world_Effect_2.png
|
|
│ └── characters/ # 20종 이상 캐릭터 스킨/투사체/마법 이펙트 에셋
|
|
│ ├── archer/
|
|
│ ├── armored-axeman/
|
|
│ ├── armored-orc/
|
|
│ ├── priest/
|
|
│ ├── wizard/
|
|
│ └── ... # knight, orc, skeleton, slime, wolf, bear 계열 등
|
|
└── src/ # 프론트엔드 소스 root
|
|
├── main.js # Phaser game config, 앱 상태, 옵션 drawer, 방문자 추적
|
|
├── constants.js # 렌더/전장/전투/카메라/성능/월드 이펙트 상수
|
|
├── styles.css # CSS 모듈 통합 엔트리
|
|
├── styles/
|
|
│ ├── base.css # 전역 변수, reset, 기본 레이아웃
|
|
│ ├── intro.css # 대기 화면 및 프리뷰 스타일
|
|
│ ├── game-ui.css # scoreboard, kill log, battle notice, victory layer
|
|
│ ├── overlay.css # option drawer, About dialog, form controls
|
|
│ ├── animations.css # 공통 keyframes/animation utilities
|
|
│ └── mobile.css # 960px 이하 반응형 override
|
|
├── game/
|
|
│ ├── arena/
|
|
│ │ ├── ArenaScene.js # 메인 Phaser Scene orchestrator
|
|
│ │ ├── arenaRenderer.js # 전장 바닥, grid, starting zone 렌더링
|
|
│ │ ├── arenaSpectatorCamera.js # 자동/수동 카메라 포커싱
|
|
│ │ └── fighterLodWorker.js # 대규모 전투 detailed sprite 후보 worker
|
|
│ ├── combat/
|
|
│ │ ├── combat.js # model 기반 전투 AI, 타깃, 피해, 처치 처리
|
|
│ │ ├── aggregateCombatWorker.js# detached/offscreen 집계 전투 worker
|
|
│ │ ├── combatSettings.js # 전투 속도 및 이동 배율 설정
|
|
│ │ ├── arenaFinalCombatEffects.js
|
|
│ │ └── worldEffects.js # 밀집 구역 메테오/냉기/감속/동결 효과
|
|
│ ├── fighter/
|
|
│ │ ├── fighterModel.js # 순수 JS fighter 상태 모델
|
|
│ │ ├── fighterAdapter.js # Phaser Sprite/Physics 접근 경계
|
|
│ │ ├── fighterAssets.js # sprite load, team-shadow texture/animation 생성
|
|
│ │ ├── fighterFactory.js # Sprite 생성, model bridge, HUD pool, detail visibility
|
|
│ │ ├── fighterManifest.js # 캐릭터 스탯/종족/특성 정의
|
|
│ │ ├── fighterStats.js # melee/ranged/magic 프로필 해석
|
|
│ │ └── fighterSelection.js # 캐릭터 선택/셔플 로직
|
|
│ └── match/
|
|
│ ├── matchSetup.js # `닉네임*N` 파싱, 팀 구성, spawn 좌표 계산
|
|
│ └── arenaMatchRuntime.js # match 진행 중 helper
|
|
└── ui/
|
|
├── matchForm.js # 설정 폼 및 localStorage 유지
|
|
├── aboutDialog.js # About dialog 및 Markdown 표시
|
|
├── visitorCounter.js # 방문자 API 호출/표시
|
|
├── dailyMetrics.js # 일일 지표 API 호출
|
|
├── deathStats.js # 사망 통계 API 호출
|
|
├── arenaScoreboard.js # 팀 badge 및 선택 상태
|
|
├── arenaKillLog.js # kill log DOM
|
|
├── battleDeathNotice.js# 상단 사망/통계 안내
|
|
└── victoryCelebration.js
|
|
```
|
|
|
|
로컬/생성 파일인 `config.json`, `node_modules/`, `dist/`, `.vite/`, `package-lock.json`, `*.log`는 `.gitignore` 대상입니다.
|
|
|
|
## 4. 상세 기술 가이드 (Context Routing)
|
|
|
|
토큰 절약 및 효율적인 정보 조회를 위해 상세 로직은 기능별 문서로 분리되어 있습니다. 특정 모듈 작업 시 아래 문서를 먼저 읽으십시오.
|
|
|
|
- **[인프라 및 전역 설정](./context/core.md)**: `main.js`, `constants.js`, 렌더 크기, `PERFORMANCE`, worker entrypoint, 공통 유지보수 규칙.
|
|
- **[아레나 및 카메라](./context/arena.md)**: `ArenaScene`, rolling-window LOD, `fighterLodWorker.js`, minimap, spectator/manual camera.
|
|
- **[전투 엔진](./context/combat.md)**: `combat.js`, model-only combat fallback, target spatial index, `aggregateCombatWorker.js`, world effects.
|
|
- **[캐릭터 및 에셋](./context/fighter.md)**: `FighterModel`, `fighterAdapter.js`, sprite attach/detach, HUD pool, team-shadow texture.
|
|
- **[매치 로직 및 UI](./context/match-ui.md)**: `닉네임*N` 팀 인원, spawn zone, scoreboard, kill log, victory UI, 모바일 레이아웃.
|
|
- **[서버 및 API](./context/server.md)**: Fastify, MongoDB, visitor cookie, daily metrics, death stats, About 콘텐츠.
|
|
- **[스타일 및 디자인](./context/style.md)**: CSS 모듈 구조, 디자인 변수, 반응형 및 애니메이션 가이드.
|
|
|
|
## 5. 주요 기능 상세
|
|
|
|
### 5.1 매치 입력과 스폰
|
|
|
|
- live match 참가자는 `닉네임*N` 형식으로 팀별 배정 인원을 직접 지정합니다. 접미사가 없으면 1명입니다.
|
|
- `SPAWN.MAX_FIGHTER_COUNT`는 참가자 입력으로 배정되는 fighter 수의 상한입니다. Slime의 `spawnMultiplier`, `splitOnDeath` 같은 특성 기반 추가 생성은 이 입력 상한에 포함하지 않습니다.
|
|
- starting-zone placement는 `SPAWN.FIGHTERS_PER_STARTING_ZONE`마다 팀 영역을 추가로 배정해 대규모 팀이 한 점에 뭉치지 않도록 분산합니다.
|
|
- match-start validation은 요청 인원과 허용 인원을 분리해 사용자에게 경고 카드로 보여줍니다.
|
|
|
|
### 5.2 대규모 전투 흐름
|
|
|
|
- match 시작 시 `ArenaScene`은 live fighter 수가 threshold 이상인지 판단하고 large-battle 모드로 들어갑니다.
|
|
- 첫 화면은 full-arena overview가 아니라 living fighter 평균 위치에 가까운 fighter 주변으로 zoom합니다.
|
|
- 최초 LOD sync 후 `fighterLodWorker.js` 또는 동기 resolver가 현재 카메라 상태에 맞는 detailed set을 계산합니다.
|
|
- full overview는 대표 Sprite와 dot field를 유지합니다. focused view는 rolling window 안의 모든 생존자를 detail Sprite로 복구합니다.
|
|
- offscreen/detached model은 집계 squad combat으로 이동/피해/사망을 처리하고, 카메라에 다시 들어오면 model position에서 Sprite를 재attach합니다.
|
|
|
|
### 5.3 모델/렌더 생명주기
|
|
|
|
- `createFighter()`는 항상 실제 Phaser Sprite를 만들고 `FighterModel`을 붙입니다. 과거 lazy `SpriteProxy` 실험은 rollback되었습니다.
|
|
- `attachSprite: false`는 Sprite 생성을 건너뛰는 뜻이 아니라, 생성 직후 `setFighterDetailVisible(false)`로 parking한다는 뜻입니다.
|
|
- parking된 fighter는 render/update/physics traversal에서 빠지지만 model state는 계속 살아 있습니다.
|
|
- model-only death는 model을 inactive/unregister 처리하고 parked fighter entry를 제거합니다.
|
|
- animation helper는 실제 renderable fighter가 없으면 action key resolution/playback을 건너뜁니다.
|
|
|
|
### 5.4 전투, 효과, 월드 이벤트
|
|
|
|
- `updateFighterModel()`은 Sprite가 있으면 기존 Arcade/animation path를 사용하고, Sprite가 없으면 model 좌표/HP/쿨다운 기반으로 이동과 공격을 진행합니다.
|
|
- ranged/magic 공격은 양쪽 Sprite가 모두 있으면 visual projectile/spell path를 사용합니다. detached 참여자가 있으면 같은 windup/travel/hit delay를 model hit로 해석합니다.
|
|
- kill reward, split-on-death, death stats, scoreboard, match finish는 Sprite 유무와 무관하게 기존 authoritative path를 사용합니다.
|
|
- dense-area meteor barrage는 큰 경고 범위를 먼저 표시한 뒤 내부 소형 strike에만 피해/동결/감속을 적용합니다.
|
|
- sudden death는 설정 시간 이후 meteor 주기를 단축하고 필요 시 frost meteor를 강제해 장기전을 방지합니다.
|
|
|
|
### 5.5 카메라와 HUD
|
|
|
|
- `transitionMainCameraTo()`는 수동 focus 이동에 Phaser `pan()`/`zoomTo()`를 적용합니다.
|
|
- selected fighter auto-centering은 수동 tween 중에는 기다려 tween을 취소하지 않습니다.
|
|
- scoreboard에서 선택된 팀을 다시 클릭하면 selection/focus/meteor focus를 정리하고 full-arena view로 돌아갑니다.
|
|
- minimap은 field camera와 분리된 HUD camera로 고정 표시하며, main camera viewport rectangle과 team-colored dot을 그립니다.
|
|
- fighter HUD는 pool 기반입니다. selected/zoom-visible 후보만 health bar를 빌려 쓰고, hidden LOD fighter는 HUD slot과 pointer input을 해제합니다.
|
|
|
|
### 5.6 서버/API와 지표
|
|
|
|
- 방문자 체크는 `arena_visitor_id` HttpOnly 쿠키와 MongoDB `visitors` 컬렉션을 사용합니다.
|
|
- daily metrics는 앱 방문, 실제 전투 시작, 실제 전투 종료, 후원 클릭 예약 지표를 날짜별 합산 문서로 저장합니다.
|
|
- death stats는 프리뷰가 아닌 실제 전투 종료 시 종족별 사망 수를 오늘 일자 문서에 누적합니다.
|
|
- About 콘텐츠는 DB의 Markdown을 실시간 조회하며 서버 메모리 캐시를 두지 않습니다.
|
|
|
|
## 6. 기술 사양 및 튜닝 포인트
|
|
|
|
- **Framework**: Phaser 3.90.0 (Arcade Physics 기반)
|
|
- **Build Tool**: Vite 7.1.12
|
|
- **Server**: Fastify 5.x (`@fastify/static`, `@fastify/middie`)
|
|
- **Database**: MongoDB 7.x Node Driver
|
|
- **UI Logic**: Vanilla JS & CSS
|
|
- **Render**: `RENDER.WIDTH/HEIGHT = 1280`, `ARENA.SIZE = 3200`, `CAMERA.MIN_ZOOM = RENDER_SIZE / ARENA_SIZE`
|
|
- **Large Battle**: `PERFORMANCE.LARGE_BATTLE_*` 상수에서 threshold, simulation buckets, aggregate refresh/cell/squad/death cap, target index refresh, HUD limit, Sprite budget, rolling window, dot redraw를 조정합니다.
|
|
- **World Effect**: `WORLD_EFFECT.*`에서 첫/반복 포격, 밀집 경고 범위, 소형 strike 범위/개수/간격/시각 배율, meteor shake, fire/frost damage, frost stun/slow를 조정합니다.
|
|
- **Camera**: `CAMERA.LARGE_BATTLE_START_ZOOM`, `CAMERA.MANUAL_FOCUS_TWEEN_MS`, `CAMERA.MANUAL_FOCUS_TWEEN_EASE`, meteor focus, spectator thresholds를 조정합니다.
|
|
- **Fighter**: `FIGHTER.DEAD_DESPAWN_DELAY_MS`, `FIGHTER.DEAD_DESPAWN_ALPHA`, `FIGHTER_TYPE_STATS`, kill growth 상수를 조정합니다.
|
|
- **Worker fallback**: LOD/aggregate worker는 성능 최적화 경로이며, 실패 시 main-thread 동기 path가 계속 동작해야 합니다.
|
|
|
|
## 7. 서버/API 설정
|
|
|
|
- 개발 서버는 `npm run dev`, 운영 서버는 `npm start`, 정적 빌드는 `npm run build`로 실행합니다.
|
|
- 기본 포트는 `config.json`의 `SERVER_PORT` 값이며 샘플은 `9736`입니다.
|
|
- `config.json`은 로컬 설정 파일이므로 저장소에 커밋하지 않습니다. 새 환경에서는 `config.json.sample`을 복사해 사용합니다.
|
|
|
|
기본 API:
|
|
|
|
- `GET /api/health`: 서버 및 MongoDB 설정 여부 확인.
|
|
- `POST /api/visitors/check`: 방문자 UUID 쿠키 확인/발급 및 유니크 방문자 수 반환.
|
|
- `GET /api/visitors/stats`: 전체 유니크 방문자 수 조회.
|
|
- `GET /api/daily-metrics/today`: 오늘의 운영 지표 조회.
|
|
- `POST /api/daily-metrics/match-started`: 실제 전투 시작 수 누적.
|
|
- `POST /api/daily-metrics/match-finished`: 실제 전투 종료 수 누적.
|
|
- `POST /api/daily-metrics/donation-clicked`: 후원 클릭 수 누적용 예약 API.
|
|
- `GET /api/death-stats/today`: 오늘의 종족별 전투 사망 통계 조회.
|
|
- `POST /api/death-stats/today`: 종료된 실제 전투의 종족별 사망 수 누적.
|
|
- `GET /api/about`: 개발자정보와 개인정보처리방침 Markdown 조회.
|
|
|
|
## 8. 유지보수 규칙
|
|
|
|
- **문서 동기화**: 구조, 상수, API, 대규모 전투 path가 바뀌면 `agent.md`와 관련 `context/*.md`를 함께 갱신합니다.
|
|
- **모듈 경계**: `ArenaScene`은 orchestration을 맡고, fighter 상태/렌더 세부는 `fighter/`, 전투 판정은 `combat/`, match input/spawn은 `match/`, DOM UI는 `ui/`로 분리합니다.
|
|
- **Fighter 접근**: 새 코드가 fighter body, animation, tint, velocity, position을 직접 다뤄야 한다면 먼저 `fighterAdapter.js`에 적절한 helper가 있는지 확인합니다.
|
|
- **Model-first 안전성**: `fighterForModelId()`는 null을 반환할 수 있습니다. model-only 전투, stale id, death/unregister 이후 상태를 항상 고려합니다.
|
|
- **대규모 전투 성능**: 8,000명급 경로에서는 전체 fighter 배열을 매 프레임 스캔하거나 DOM/HUD/Graphics를 전원 갱신하지 않습니다. throttle, pool, worker, spatial index, set diff를 우선 사용합니다.
|
|
- **Phaser lifecycle**: parked Sprite는 display/update list와 Arcade World에서 모두 빠져야 하며, reattach 시 model 좌표와 body를 동기화합니다.
|
|
- **이펙트 lifecycle**: pooled combat object는 `releaseToPool`/`disposeCombatObject()` 경로로 정리합니다. 새 이펙트도 match reset과 scene cleanup에서 누수되지 않아야 합니다.
|
|
- **API 변경**: `/api/*` 경로는 Fastify route가 담당합니다. 개발 모드에서 Vite SPA fallback이 API 요청을 가로채지 않게 유지합니다.
|
|
- **신규 캐릭터**: `public/assets/characters/`에 에셋을 배치하고 `fighterManifest.js`에 `species`와 combat/stat 정의를 추가합니다. 사망 통계 종족은 `human`, `orc`, `skeleton`, `slime`, `wolf`, `bear` 중 하나를 사용합니다.
|
|
- **스타일 변경**: `src/styles.css`는 모듈 import 엔트리입니다. 실제 수정은 `src/styles/*.css`의 해당 영역에서 진행합니다.
|
|
|
|
## 9. 관련 문서
|
|
|
|
- [context/core.md](./context/core.md): 전역 설정, 성능 상수, 렌더/worker 가이드.
|
|
- [context/arena.md](./context/arena.md): 아레나 씬, 카메라, minimap, render LOD.
|
|
- [context/combat.md](./context/combat.md): 전투 AI, 집계 전투, projectile/world effect.
|
|
- [context/fighter.md](./context/fighter.md): FighterModel, adapter, factory, assets.
|
|
- [context/match-ui.md](./context/match-ui.md): 매치 입력, spawn, HUD, 모바일 UI.
|
|
- [context/server.md](./context/server.md): Fastify/MongoDB API.
|
|
- [context/style.md](./context/style.md): CSS 모듈 및 디자인 규칙.
|
|
- [todo.md](./todo.md): 작업 내역 및 잔여 이슈.
|