전체 구조 설명
Gpt를 통해 아래의 간단한 턴제 RPG 시스템 예제를 받아 작성해 보았다.

핵심 구성
- Player : 플레이어 정보
- Monster : 적 정보
- Item : 포션 (회복 아이템)
- vector : 인벤토리 관리
- 전투 로직 : 공격 / 회복 / 턴 진행
클래스 설계
Player 클래스
class Player
{
public:
Player(std::string name, int maxhp, int hp, int maxmp, int mp, int atk, int def)
:name(name), maxhp(maxhp), hp(hp), maxmp(maxmp), mp(mp), atk(atk), def(def)
{
}
~Player() {}
std::string getName() const
{
return name;
}
int getMaxHP() const
{
return maxhp;
}
int getMaxMP()const
{
return maxmp;
}
int getHP() const
{
return hp;
}
int getMP() const
{
return mp;
}
int getATK() const
{
return atk;
}
int getDEF() const
{
return def;
}
void setName(std::string name)
{
this->name = name;
}
void setMaxHP(int maxhp)
{
this->maxhp = maxhp;
}
void setMaxMP(int maxmp)
{
this->maxmp = maxmp;
}
void setHP(int hp)
{
this->hp = hp;
}
void setMP(int mp)
{
this->mp = mp;
}
void setATK(int atk)
{
this->atk = atk;
}
void setDEF(int def)
{
this->def = def;
}
private:
std::string name;
int maxhp;
int maxmp;
int hp;
int mp;
int atk;
int def;
};
역할
- 플레이어의 모든 능력치 관리
특징
- Getter / Setter 완전 분리
- 상태값 직접 접근 ❌ → 함수로만 접근 ⭕
이유
→ 캡슐화 (Encapsulation)
→ 데이터 보호 + 유지보수 쉬움
Monster 클래스
class Monster
{
public:
Monster(std::string type, int hp, int atk, int def)
:type(type), hp(hp), atk(atk), def(def)
{
}
std::string getType() const
{
return type;
}
int getHP() const
{
return hp;
}
int getATK() const
{
return atk;
}
int getDEF() const
{
return def;
}
void setType(std::string type)
{
this->type = type;
}
void setHP(int hp)
{
this->hp = hp;
}
void setATK(int atk)
{
this->atk = atk;
}
void setDEF(int def)
{
this->def = def;
}
private:
std::string type;
int hp;
int atk;
int def;
};
역할
- 몬스터 능력치 관리
특징
Player보다 단순한 이유
→ 기능이 적기 때문 (MP 없음 등)
Item 클래스
class Item
{
public:
Item(std::string name, int healAmount, int count)
:name(name), healAmount(healAmount), count(count)
{
}
std::string getName() const
{
return name;
}
int gethealAmount() const
{
return healAmount;
}
int getCount() const
{
return count;
}
void setName(std::string name)
{
this->name = name;
}
void sethealAmount(int healAmount)
{
this->healAmount = healAmount;
}
void setCount(int count)
{
this->count = count;
}
private:
std::string name;
int healAmount;
int count;
};
역할
- 포션 관리
핵심 포인트
- 회복량
- 개수 관리
enum class
enum class ItemType
{
HP,
MP,
ALL
};
현재 코드에서는 직접 활용은 안 했지만 확장용 구조로 사용 예정
왜 enum class 사용하는가?
- 타입 안정성
- 이름 충돌 방지
- 가독성
전투 로직
Player → Monster 공격
void attackMonster(Player* player, Monster* monster)
{
int Damage;
Damage = player->getATK() - monster->getDEF();
if (Damage <= 0)
{
Damage = 1;
}
monster->setHP(monster->getHP() - Damage);
if (monster->getHP() <= 0)
{
monster->setHP(0);
std::cout << "처치했습니다\n";
}
printMonsterInfo(monster);
}
핵심 로직
- 최소 대미지 보장
이유
- 공격이 아예 안 들어가는 상황 방지
- 역으로 HP가 회복되는 상황 방지
Monster → Player 공격
구조는 동일
void attackPlayer(Monster* monster, Player* player)
{
int Damage;
Damage = monster->getATK() - player->getDEF();
if (Damage <= 0)
{
Damage = 1;
}
player->setHP(player->getHP() - Damage);
if (player->getHP() <= 0)
{
player->setHP(0);
std::cout << "사망하셨습니다.\n";
}
std::cout << "\n몬스터의 공격 턴\n";
printPlayerInfo(player);
}
포션 사용
void usePotion(Item* potion, Player* player)
{
if (potion->getCount() > 0)
{
int newHP = player->getHP() + potion->gethealAmount();
if (player->getHP() >= player->getMaxHP())
{
std::cout << "\n체력이 이미 최대치입니다.\n";
}
else
{
player->setHP(newHP);
if (player->getHP() > player->getMaxHP())
{
player->setHP(player->getMaxHP());
}
std::cout << "\n체력이 회복되었습니다!\n";
printPlayerInfo(player);
potion->setCount(potion->getCount() - 1);
}
std::cout << "\n남은 포션: " << potion->getCount() << std::endl;
}
else
{
std::cout << "\n포션이 없습니다..\n";
}
}
처리 과정
- 포션 개수 확인
- 최대 HP 초과 방지
- HP 회복
- 포션 개수 감소
인벤토리 시스템 (vector)
std::vector<Item> Inventory;
Inventory.reserve(3u);
Inventory.emplace_back("HP포션", 30, 3);
Inventory.emplace_back("MP포션", 30, 2);
Inventory.emplace_back("만능 회복약", 100, 1);
추후 변경점에선 클래스 나누면서 인벤토리도 과제에서 했던 것처럼 바뀔 예정이다.
특징
함수설명
| reserve | 미리 공간 확보 (성능 최적화) |
| emplace_back | 객체 직접 생성 |
push_back을 안 쓴 이유는 enum class에 있는 Type을 쓰기 위해 미리 변경해 뒀다.
게임 루프
while (player.getHP() > 0 && m.getHP() > 0)
{
int num;
std::cout << "\n|[1] 공격|[2] 회복|[0] 종료|\n";
std::cout << "번호를 입력하세요 : ";
std::cin >> num;
switch (num)
{
case 0:
return 0;
case 1:
attackMonster(&player, &m);
if (m.getHP() <= 0)
{
break;
}
attackPlayer(&m, &player);
if (player.getHP() <= 0)
{
break;
}
break;
case 2:
std::cout << "\n|[1] HP포션|[2] MP포션|[3] 만능 회복약|\n";
int itemNum;
std::cin >> itemNum;
if (0 < itemNum && itemNum <= Inventory.size())
{
usePotion(&Inventory[itemNum - 1], &player);
}
else
{
std::cout << "\n입력을 제대로 못한 죄로 이번턴은 그냥 넘깁니다.\n";
}
attackPlayer(&m, &player);
break;
default:
std::cout << "\n번호를 다시 입력하세요\n";
}
}
반복 조건
- 플레이어 살아있고
- 몬스터 살아있을 때
필자가 만들 때마다 즐겨 사용하는 while문 정말 좋다..
선택지
[1] 공격
[2] 회복
[3] 종료
공격 흐름
- 플레이어 공격
- 몬스터 죽었는지 확인
- 몬스터 공격
회복 흐름
- 아이템 선택
- 회복
- 몬스터 공격 (턴 유지)
중요 포인트!
행동 후 몬스터 턴 진행
핵심 정리
포인터 사용
- 원본 객체 수정 가능
캡슐화
- 직접 접근 대신 함수 사용
최소 대미지 처리
- 게임 밸런스 핵심
vector 활용
- 동적 배열
- 인벤토리 구현에 적합
턴제 전투 구조
플레이어 행동 → 몬스터 행동으로 게임 기본 구조
개선점
- enum class 활용하기
- class 분리해서 정리하기 (지금은 main 에만 다 구현되어 있음)
- 함수 전투 부분 포인터 대신 참조 사용하기
마무리
오늘은 GPT를 활용해 보며 예제들을 받아 배운 것들을 통해 직접 구현해 보는 과정을 가졌다.
직접 테스트해보며 문제가 있으면 수정하고 완성본을 보여주면서 괜찮았던 점 아쉬웠던 점 등을 gpt가 알려주며 다른 방식도 있다는 것 정도만 알려주고 다음 예제를 받아 추가하는 식으로 해봤습니다.
'학습일지 > C와 C++' 카테고리의 다른 글
| C++ 첫 번째 협업 체험 팀 프로젝트 (0) | 2026.03.26 |
|---|---|
| C++ 연금술 공방 관리 시스템 구현 과제 (0) | 2026.03.24 |
| C++ 스마트 포인터 (0) | 2026.03.18 |
| C++ 인벤토리 시스템 구현 (0) | 2026.03.17 |
| C++ Debugging (0) | 2026.03.16 |