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 기반 게임에서는 더블 버퍼링을 사용하여 화면 깜빡임을 방지하고, 픽셀 아트를 위한 적절한 스케일링 방법을 구현해야 합니다.