최신 C++ 기능을 활용한 프로그램 작성
프로그램 개요 : 텍스트 기반 RPG 게임
이 절에서는 C++ 20의 새로운 기능들을 활용하여 실제 프로그램을 작성해보겠습니다.
간단한 텍스트 기반 게임을 구현하면서 최신 C++ 기능들을 적용해 볼 것입니다.
우리가 만들 게임은 다음 기능을 포함합니다.
- 캐릭터 생성 및 관리
- 아이템 시스템
- 간단한 전투 시스템
- 퀘스트 시스템
- 게임 진행 상황 저장 및 불러오기
기본 구조 설계
먼저 게임의 기본 구조를 설계합니다.
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <random>
#include <concepts>
#include <coroutine>
#include <fstream>
#include <json.hpp> // nlohmann/json 라이브러리 사용
// 캐릭터 관련 클래스
class Character {
public:
Character(std::string name, int health, int attack, int defense)
: name_(std::move(name)), health_(health), attack_(attack), defense_(defense) {}
virtual ~Character() = default;
virtual void attack(Character& target) = 0;
virtual void take_damage(int damage) = 0;
const std::string& name() const { return name_; }
int health() const { return health_; }
int attack() const { return attack_; }
int defense() const { return defense_; }
protected:
std::string name_;
int health_;
int attack_;
int defense_;
};
// 아이템 클래스
class Item {
public:
Item(std::string name, int value) : name_(std::move(name)), value_(value) {}
const std::string& name() const { return name_; }
int value() const { return value_; }
private:
std::string name_;
int value_;
};
// 게임 관리 클래스
class Game {
public:
void run();
private:
void create_character();
void battle();
void shop();
void save_game();
void load_game();
std::unique_ptr<Character> player_;
std::vector<Item> inventory_;
};
개념 (Concepts) 활용
캐릭터와 아이템에 대한 개념을 정의합니다.
template<typename T>
concept Attackable = requires(T a, T b) {
{ a.attack(b) } -> std::same_as<void>;
{ a.take_damage(int{}) } -> std::same_as<void>;
};
template<typename T>
concept Inventoriable = requires(T a) {
{ a.name() } -> std::convertible_to<std::string>;
{ a.value() } -> std::convertible_to<int>;
};
static_assert(Attackable<Character>);
static_assert(Inventoriable<Item>);
코루틴을 활용한 비동기 전투 시스템
struct BattleResult {
bool player_won;
int exp_gained;
};
struct BattleAwaiter {
bool await_ready() const noexcept { return false; }
void await_suspend(std::coroutine_handle<> h) const noexcept {}
BattleResult await_resume() const noexcept { return result; }
BattleResult result;
};
class BattleCoroutine {
public:
struct promise_type {
BattleResult result;
BattleCoroutine get_return_object() { return BattleCoroutine(this); }
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
BattleAwaiter yield_value(BattleResult r) {
result = r;
return BattleAwaiter{r};
}
};
BattleCoroutine(promise_type* p) : coro_(std::coroutine_handle<promise_type>::from_promise(*p)) {}
~BattleCoroutine() { if (coro_) coro_.destroy(); }
BattleResult get_result() { return coro_.promise().result; }
private:
std::coroutine_handle<promise_type> coro_;
};
BattleCoroutine battle_system(Character& player, Character& enemy) {
while (player.health() > 0 && enemy.health() > 0) {
player.attack(enemy);
if (enemy.health() <= 0) {
co_yield BattleResult{true, 100}; // Player won
co_return;
}
enemy.attack(player);
if (player.health() <= 0) {
co_yield BattleResult{false, 0}; // Player lost
co_return;
}
co_yield BattleResult{false, 0}; // Battle ongoing
}
}
게임 클래스 구현
void Game::run() {
std::cout << "Welcome to the Text RPG Game!" << std::endl;
while (true) {
std::cout << "\n1. Create Character\n2. Battle\n3. Shop\n4. Save Game\n5. Load Game\n6. Exit\n";
std::cout << "Enter your choice: ";
int choice;
std::cin >> choice;
switch (choice) {
case 1: create_character(); break;
case 2: battle(); break;
case 3: shop(); break;
case 4: save_game(); break;
case 5: load_game(); break;
case 6: return;
default: std::cout << "Invalid choice. Please try again.\n";
}
}
}
void Game::create_character() {
std::string name;
std::cout << "Enter character name: ";
std::cin >> name;
player_ = std::make_unique<PlayerCharacter>(name, 100, 10, 5);
std::cout << "Character created successfully!" << std::endl;
}
void Game::battle() {
if (!player_) {
std::cout << "Please create a character first." << std::endl;
return;
}
EnemyCharacter enemy("Goblin", 50, 8, 3);
std::cout << "Battle started! " << player_->name() << " vs " << enemy.name() << std::endl;
auto battle = battle_system(*player_, enemy);
auto result = battle.get_result();
if (result.player_won) {
std::cout << "You won the battle! EXP gained: " << result.exp_gained << std::endl;
} else {
std::cout << "You lost the battle." << std::endl;
}
}
// shop(), save_game(), load_game() 메서드의 구현은 생략
컴파일 및 실행
이 프로그램을 컴파일하려면 C++ 20을 지원하는 최신 컴파일러가 필요합니다.
g++ -std=c++20 rpg_game.cpp -o rpg_game
./rpg_game
프로그램 설명
이 프로그램은 다음과 같은 C++ 20 기능을 활용합니다.
- 개념(Concepts) :
Attackable
과Inventoriable
개념을 사용하여 캐릭터와 아이템의 인터페이스를 정의했습니다. - 코루틴(Coroutines) : 전투 시스템을 비동기적으로 구현하기 위해 코루틴을 사용했습니다.
std::unique_ptr
: 스마트 포인터를 사용하여 메모리 관리를 자동화했습니다.
연습 문제
- 캐릭터에 레벨 시스템을 추가하고, 전투에서 승리할 때마다 경험치를 얻어 레벨업할 수 있도록 구현해보세요.
- 아이템 시스템을 확장하여 무기, 방어구, 포션 등 다양한 종류의 아이템을 추가하고, 이를 인벤토리에서 사용할 수 있도록 구현해보세요.
참고자료
- C++ 20 표준 문서
- "C++ 20 : The Complete Guide" by Nicolai M. Josuttis
- CppCon 발표 영상들 - C++ 20 관련 세션들
- C++ Reference 웹사이트의 C++ 20 섹션
- "Mastering the C++17 STL" by Arthur O'Dwyer (C++ 20 업데이트 참고)