레슨 7 / 8·25분
실전: 간단한 게임 엔진
프로젝트 개요 — 텍스트 기반 RPG 엔진
지금까지 배운 C++ 기능을 활용하여 텍스트 기반 RPG 게임 엔진을 만들어 봅니다. 상속, 다형성, STL 컨테이너, 스마트 포인터를 실전에서 어떻게 조합하는지 경험합니다.
게임 엔티티 설계
cpp
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <map>
#include <cstdlib>
#include <ctime>
using namespace std;
// ── 기본 엔티티 클래스 ──
class Entity {
protected:
string name;
int hp;
int maxHp;
int attack;
int defense;
public:
Entity(const string& n, int h, int atk, int def)
: name(n), hp(h), maxHp(h), attack(atk), defense(def) {}
virtual ~Entity() = default;
virtual void showStatus() const {
cout << name << " [HP: " << hp << "/" << maxHp
<< " ATK: " << attack << " DEF: " << defense << "]" << endl;
}
bool isAlive() const { return hp > 0; }
const string& getName() const { return name; }
int getAttack() const { return attack; }
void takeDamage(int dmg) {
int actual = max(1, dmg - defense);
hp = max(0, hp - actual);
cout << name << "이(가) " << actual << " 데미지를 받았다! "
<< "(HP: " << hp << ")" << endl;
}
void heal(int amount) {
hp = min(maxHp, hp + amount);
cout << name << " HP " << amount << " 회복! "
<< "(HP: " << hp << ")" << endl;
}
};플레이어와 몬스터 구현
cpp
// ── 아이템 시스템 ──
struct Item {
string name;
string type; // "weapon", "potion"
int value;
};
// ── 플레이어 클래스 ──
class Player : public Entity {
int level;
int exp;
vector<Item> inventory;
public:
Player(const string& n)
: Entity(n, 100, 15, 5), level(1), exp(0) {}
void showStatus() const override {
cout << "=== " << name << " (Lv." << level << ") ===" << endl;
Entity::showStatus();
cout << "경험치: " << exp << "/100" << endl;
cout << "인벤토리: " << inventory.size() << "개 아이템" << endl;
}
void gainExp(int amount) {
exp += amount;
cout << name << "이(가) 경험치 " << amount << " 획득!" << endl;
while (exp >= 100) {
exp -= 100;
levelUp();
}
}
void addItem(const Item& item) {
inventory.push_back(item);
cout << item.name << "을(를) 획득했다!" << endl;
}
void usePotion() {
for (auto it = inventory.begin(); it != inventory.end(); ++it) {
if (it->type == "potion") {
heal(it->value);
inventory.erase(it);
return;
}
}
cout << "포션이 없습니다!" << endl;
}
private:
void levelUp() {
level++;
maxHp += 20;
hp = maxHp;
attack += 3;
defense += 2;
cout << "*** 레벨 업! Lv." << level << " ***" << endl;
}
};
// ── 몬스터 클래스 ──
class Monster : public Entity {
int expReward;
public:
Monster(const string& n, int h, int atk, int def, int expR)
: Entity(n, h, atk, def), expReward(expR) {}
int getExpReward() const { return expReward; }
};전투 시스템과 게임 루프
cpp
// ── 전투 시스템 ──
class BattleSystem {
public:
static bool fight(Player& player, Monster& monster) {
cout << "\n=== 전투 시작: " << monster.getName()
<< " 등장! ===" << endl;
while (player.isAlive() && monster.isAlive()) {
// 플레이어 턴
int playerDmg = player.getAttack() + (rand() % 5);
monster.takeDamage(playerDmg);
if (!monster.isAlive()) {
cout << monster.getName() << "을(를) 처치했다!" << endl;
player.gainExp(monster.getExpReward());
return true;
}
// 몬스터 턴
int monsterDmg = monster.getAttack() + (rand() % 3);
player.takeDamage(monsterDmg);
}
cout << "패배했습니다..." << endl;
return false;
}
};
// ── 몬스터 팩토리 ──
class MonsterFactory {
static vector<tuple<string, int, int, int, int>> templates;
public:
static void init() {
templates = {
{"슬라임", 30, 5, 2, 20},
{"고블린", 50, 10, 4, 35},
{"오크", 80, 15, 8, 50},
{"드래곤", 150, 25, 12, 100},
};
}
static unique_ptr<Monster> create(int difficulty) {
int idx = min(difficulty, (int)templates.size() - 1);
auto& [n, h, a, d, e] = templates[idx];
return make_unique<Monster>(n, h, a, d, e);
}
};
vector<tuple<string, int, int, int, int>> MonsterFactory::templates;
// ── 메인 게임 루프 ──
int main() {
srand(time(nullptr));
MonsterFactory::init();
Player hero("용사");
hero.addItem({"체력 포션", "potion", 30});
hero.addItem({"체력 포션", "potion", 30});
cout << "\n=== 텍스트 RPG 시작! ===" << endl;
hero.showStatus();
for (int stage = 0; stage < 4; stage++) {
auto monster = MonsterFactory::create(stage);
if (!BattleSystem::fight(hero, *monster)) break;
hero.usePotion();
hero.showStatus();
}
cout << "\n=== 게임 종료 ===" << endl;
return 0;
}- •상속과 다형성 — Entity 기반 클래스에서 Player, Monster 파생
- •스마트 포인터 — MonsterFactory가 unique_ptr로 몬스터 생성
- •STL 컨테이너 — vector로 인벤토리, map으로 데이터 관리
- •가상 함수 — showStatus()를 override하여 다형적 동작
- •팩토리 패턴 — MonsterFactory로 객체 생성 캡슐화
💡
이 프로젝트를 확장해 보세요: 마법 시스템, 장비 착용, 상점, 던전 탐험, 파일로 세이브/로드 기능 등을 추가하면 더 풍부한 게임이 됩니다. 각 기능을 별도 클래스로 분리하는 연습을 하세요.