C++ WinAPI 기반 Pixel Dungeon 모작 게임 개발을 위한 구조 분석
Pixel Dungeon은 전통적인 로그라이크 던전 크롤러 게임으로, 랜덤 생성된 레벨과 적, 다양한 아이템을 특징으로 합니다. 이 문서는 Pixel Dungeon의 핵심 게임 시스템 구조를 UML 다이어그램으로 표현하여 모작 게임 개발에 도움을 제공합니다.
아래 다이어그램은 주요 클래스와 그들의 관계, 핵심 기능 동작 방식을 보여줍니다. 실제 구현에서는 프로젝트 요구사항에 맞게 조정이 필요합니다.
classDiagram class Game { +scene: Scene +create() +resume() +pause() +finish() } class PixelDungeon { +instance: PixelDungeon +scene(): Scene } class Dungeon { +level: Level +hero: Hero +init() +newLevel() +saveGame() +loadGame() } class GameScene { +create() +update() +add(Gizmo) +updateMap(int) } Game <|-- PixelDungeon PixelDungeon *-- Dungeon Game *-- GameScene
classDiagram class Level { +map: int[] +passable: boolean[] +visited: boolean[] +mobs: HashSet~Mob~ +heaps: HashMap~Int, Heap~ +create() +drop(Item, int) +press(int, Char) } class RegularLevel { +rooms: ArrayList~Room~ +roomEntrance: Room +roomExit: Room +createItems() +createMobs() +initRooms() +joinRooms() +placeDoors() } class SewerLevel { +decorate() +randomRespawnCell() } class Room { +left, top, right, bottom: int +neighbors: ArrayList~Room~ +connected: HashMap~Room, Door~ +type: Type +paint() +random() } class Painter { +paint(Level, Room) } Level <|-- RegularLevel RegularLevel <|-- SewerLevel RegularLevel <|-- PrisonLevel RegularLevel <|-- CavesLevel RegularLevel <|-- CityLevel RegularLevel <|-- HallsLevel RegularLevel *-- Room Painter --> Room Painter --> Level
classDiagram class Actor { +id: int +act(): boolean +spend(float) +getTime(): float } class Char { +pos: int +HP: int +sprite: CharSprite +buffs: HashSet~Buff~ +move(int): boolean +attack(Char): boolean +damage(int, Object): void +die(Object): void +defenseSkill(Char): int +attackSkill(Char): int } class Mob { +enemy: Char +state: AiState +intelligentAlly: boolean +doAttack(Char): void +getCloser(int): boolean +getFurther(int): boolean +canAttack(Char): boolean +notice(): void +beckon(int): void } class Hero { +heroClass: HeroClass +STR: int +exp: int +belongings: Belongings +handle(): void +move(int): boolean +actAttack(HeroAction.Attack): void +actMove(HeroAction.Move): void +rest(boolean): void +search(boolean): void } Actor <|-- Char Char <|-- Mob Char <|-- Hero Mob <|-- Rat Mob <|-- Gnoll Mob <|-- Crab Mob <|-- DM300 Mob <|-- King Mob <|-- Yog
classDiagram class Item { +image: int +name: String +quantity: int +unique: boolean +cursed: boolean +identify(): Item +collect(): boolean +execute(Hero): void +actions(Hero): ArrayList~String~ +doPickUp(Hero): boolean } class Weapon { +tier: int +ACU: float +MIN: int +MAX: int +STR: int +enchantment: Enchantment +proc(Char, Char): void +typicalSTR(): int +damageRoll(): int } class Armor { +tier: int +DR: int +STR: int +glyph: Glyph +proc(Char, Char): void +typicalSTR(): int +defenseProc(Char, Char): int } class Potion { +isKnown(): boolean +drink(Hero): void } class Scroll { +isKnown(): boolean +read(Hero): void } Item <|-- EquippableItem EquippableItem <|-- Weapon EquippableItem <|-- Armor Item <|-- Potion Item <|-- Scroll Item <|-- Ring Item <|-- Wand Item <|-- Bag Weapon <|-- MeleeWeapon Weapon <|-- Projectile
classDiagram class Buff { +target: Char +type: BuffType +act(): boolean +attachTo(Char): boolean +detach(): void } class Hunger { +hunger: float +satisfy(float): void +isStarving(): boolean } class Bestiary { +mob(int): Mob +mobClass(int): Class~? extends Mob~ } class Generator { +generate(Category): Item +random(Category): Item } class Heap { +type: Type +items: LinkedList~Item~ +sprite: ItemSprite +drop(Item): void +pickUp(): Item } Buff <|-- FlavourBuff Buff <|-- Hunger Buff <|-- Burning Buff <|-- Paralysis Buff <|-- Poison Buff <|-- Invisibility Buff <|-- Levitation Actor <|-- Buff
classDiagram class Gizmo { +parent: Gizmo +remove(): void +update(): void +destroy(): void } class Visual { +x: float +y: float +width: float +height: float +draw(): void } class Group { +members: ArrayList~Gizmo~ +add(Gizmo): void +remove(Gizmo): void } class Scene { +update(): void +create(): void +destroy(): void } class CharSprite { +idle(): void +move(int, int): void +attack(int): void +die(): void } class DungeonTilemap { +SIZE: int +screenToTile(int, int): int +tileToScreen(int): PointF +drawVisuals(): void } Gizmo <|-- Visual Gizmo <|-- Group Group <|-- Scene Scene <|-- GameScene Visual <|-- CharSprite Visual <|-- DungeonTilemap
sequenceDiagram actor 플레이어 participant 게임시스템 participant 던전 participant 캐릭터 participant UI 플레이어->>게임시스템: 게임 시작 게임시스템->>던전: 새 던전 생성 던전->>던전: 레벨 생성 던전->>캐릭터: 영웅 초기화 게임시스템->>UI: 게임 화면 표시 rect rgb(240, 240, 250) note right of 플레이어: 기본 게임플레이 루프 플레이어->>캐릭터: 이동 명령 캐릭터->>던전: 위치 갱신 던전->>UI: 시야 및 맵 업데이트 end 플레이어->>캐릭터: 적과 전투 캐릭터->>캐릭터: 공격 계산 캐릭터->>UI: 전투 결과 표시 플레이어->>캐릭터: 아이템 사용 캐릭터->>캐릭터: 아이템 효과 적용 캐릭터->>UI: 상태 업데이트
sequenceDiagram actor 플레이어 participant 영웅 participant 던전 participant 몬스터 participant 아이템 플레이어->>영웅: 던전 레벨 탐험 영웅->>던전: 안개 제거 및 시야 업데이트 던전->>영웅: 발견된 요소 정보 제공 영웅->>아이템: 바닥의 아이템 발견 플레이어->>영웅: 아이템 획득 명령 영웅->>아이템: 아이템 획득 아이템->>영웅: 인벤토리에 추가 영웅->>몬스터: 몬스터 발견 몬스터->>몬스터: AI 상태 갱신 (수면->사냥) 플레이어->>영웅: 전투 또는 회피 결정 영웅->>던전: 계단 발견 플레이어->>영웅: 다음 층으로 이동 명령 영웅->>던전: 다음 레벨로 이동 요청 던전->>던전: 새 레벨 생성 던전->>영웅: 새 레벨에 영웅 배치
sequenceDiagram actor 플레이어 participant 영웅 participant 몬스터 participant 무기 participant 버프 플레이어->>영웅: 공격 명령 영웅->>영웅: 공격 정확도 계산 (attackSkill) 영웅->>몬스터: 회피 확인 (defenseSkill) alt 명중 영웅->>무기: 데미지 계산 (damageRoll) 무기->>영웅: 무기 데미지 반환 영웅->>무기: 특수 효과 처리 (proc) 무기->>버프: 효과에 따른 버프 적용 영웅->>몬스터: 최종 데미지 적용 alt 몬스터 사망 몬스터->>몬스터: die() 메서드 실행 몬스터->>아이템: 보상 드롭 몬스터->>영웅: 경험치 제공 else 몬스터 생존 몬스터->>영웅: 다음 턴에 반격 end else 회피 영웅->>영웅: 공격 실패 몬스터->>영웅: 다음 턴에 반격 end
sequenceDiagram actor 플레이어 participant 영웅 participant 인벤토리 participant 아이템 participant 장비 플레이어->>인벤토리: 인벤토리 열기 인벤토리->>플레이어: 소지 아이템 표시 플레이어->>아이템: 아이템 사용 선택 아이템->>아이템: 사용 가능 액션 반환 (actions) 아이템->>플레이어: 가능한 액션 표시 alt 장비 착용 플레이어->>장비: 착용 명령 장비->>인벤토리: 기존 장비 해제 장비->>영웅: 새 장비 착용 장비->>영웅: 능력치 수정 (STR, DEF 등) else 소비 아이템 사용 플레이어->>아이템: 포션/스크롤 사용 아이템->>영웅: 효과 적용 아이템->>인벤토리: 아이템 소모 else 아이템 버리기 플레이어->>아이템: 버리기 명령 아이템->>인벤토리: 인벤토리에서 제거 아이템->>던전: 현재 위치에 배치 end
Pixel Dungeon은 전통적인 로그라이크 방식의 턴 기반 시스템을 사용합니다. 모든 행동(이동, 공격, 아이템 사용 등)은 턴을 소모하며, 플레이어의 턴이 끝난 후 모든 NPC와 몬스터가 자신의 턴을 실행합니다.
몬스터의 AI는 상태 기계(State Machine) 패턴으로 구현되어 있으며, 다양한 상태에 따라 행동 패턴이 결정됩니다.
던전 생성은 절차적 생성(Procedural Generation) 방식으로 매번 다른 맵을 생성합니다.
전투 시스템은 공격/방어 스킬과 무기/방어구의 속성을 고려하여 계산됩니다.
다양한 아이템은 식별, 사용, 강화, 저주 등의 복잡한 메커니즘을 가집니다.
생존을 위한 다양한 자원을 관리해야 합니다.
마일스톤 | 주요 구현사항 | 구현 권장 클래스 |
---|---|---|
마일스톤 1: 기본 프레임워크 |
|
|
마일스톤 2: 전투 시스템 |
|
|
마일스톤 3: 아이템 및 인벤토리 |
|
|
마일스톤 4: 다층 던전 및 진행 |
|
|
마일스톤 5: 자원 및 상호작용 |
|
|
Pixel Dungeon의 코드 구조는 모듈화가 잘 되어 있어 확장성이 좋습니다. 다음과 같은 구조적 특징을 모작 게임에도 반영하는 것이 좋습니다:
특히 턴 기반 시스템의 핵심인 Actor 클래스와 적 행동을 결정하는 AiState 시스템은 초기부터 올바르게 설계해야 합니다.
Pixel Dungeon과 같은 복잡한 게임은 단계적으로 개발하는 것이 중요합니다:
각 마일스톤마다 기능을 테스트하고 안정화한 후 다음 단계로 진행하세요.
원본 Pixel Dungeon은 Java/LibGDX로 개발되었으므로, C++ WinAPI로 포팅 시 다음 사항을 고려해야 합니다:
또한 WinAPI 기반 게임에서는 더블 버퍼링을 사용하여 화면 깜빡임을 방지하고, 픽셀 아트를 위한 적절한 스케일링 방법을 구현해야 합니다.