학습일지/C와 C++

C++ 상점 시스템(Store) 설계 및 구현

Tsukino Ren 2026. 3. 30. 19:37

상점 시스템 설계 및 구현

개요

콘솔 기반 RPG에서 사용할 수 있는 상점 시스템을 구현했다.

플레이어와 인벤토리를 연동하여 다음 기능을 제공한다.

  • 아이템 구매
  • 아이템 판매
  • 인벤토리 확인

단순 기능 구현이 아닌, UI / 로직 / 데이터의 역할 분리를 목표로 설계했다.


기존 접근 방식과 문제점

초기에는 하나의 함수에서 모든 처리를 수행하는 방식으로 접근했으나 다음과 같은 문제가 발생했다.

  • UI와 로직이 혼합되어 가독성이 낮음
  • 기능 추가 시 코드 수정 범위 증가
  • 재사용이 어려움

이러한 문제를 해결하기 위해 구조를 분리하는 방향으로 설계를 진행했다.


전체 구조 설계

클래스 구성

 

Store
 ├── Player (외부 의존)
 └── Inventory (외부 의존)

 

{
    std::string name;
    int price;
};

핵심 설계 의도

  • Store는 상점의 흐름만 담당
  • Player는 상태 관리
  • Inventory는 아이템 관리

즉, 각 객체가 하나의 책임만 가지도록 구성했다.


상태 기반 흐름 설계

while (isOpen_)
{
    PrintMainMenu(player);

    int choice;
    std::cin >> choice;

    switch (choice)
    {
    case 1: BuyItem(player, inventory); break;
    case 2: SellItem(player, inventory); break;
    case 3: /* 인벤토리 출력 */ break;
    case 0: Close(); break;
    }
}

설계 포인트

  • 상점은 "열림과 닫힘 상태"를 가진다
  • 입력에 따라 기능이 분기된다
  • 하나의 루프 안에서 모든 흐름을 제어한다

UI와 로직 분리

출력 관련 기능을 별도의 함수로 분리했다

void PrintTitle(const std::string& title) const;
void PrintBorder() const;
void PrintPlayerInfo(const Player& player) const;

의도

  • 출력 형식을 한 곳에서 관리
  • 동일 UI 재사용 가능
  • 로직 코드와 분리하여 가독성 확보

예를 들어 타이틀 출력은 다음과 같이 통일된다

PrintTitle("마녀의 물약 상점");

아이템 구매 로직

if (player.GetGold() < item.price)
{
    // 구매 실패
}

player.loseGold(item.price);
inventory.AddItem(item.name, item.price);

처리 흐름

  • 골드 확인
  • 골드 차감
  • 인벤토리에 아이템 추가

설계 포인트

  • 조건 검증 → 상태 변경 → 결과 처리 순서 유지
  • 실패 케이스를 먼저 처리하여 흐름 단순화

아이템 판매 로직

int sellPrice = item.price * 60 / 100;

inventory.RemoveItem(index);
player.gainGold(sellPrice);

설계 포인트

  • 판매가는 원가의 60%로 설정
  • 처리 순서를 명확히 정의

순서:

  1. 인벤토리에서 제거
  2. 골드 지급

이 순서를 지키지 않으면 문제가 발생할 수 있다


입력 예외 처리

if (std::cin.fail())
{
    std::cin.clear();
    std::cin.ignore(10000, '\n');
}

문제 상황

  • 잘못된 입력 시 cin이 실패 상태 유지
  • 이후 입력이 모두 무시되는 문제 발생

해결

  • clear()로 상태 초기화
  • ignore()로 입력 버퍼 제거

출력 정렬 처리

std::setw(2)
std::left
std::right

역할

  • 출력 정렬
  • UI 가독성 개선

개선해야 할 사항

1. 입력 대기 코드 중복

int temp;
std::cin >> temp;

현재 입력을 받는 코드가 여러 위치에서 반복되고 있다

  • 입력 처리 로직이 중복되면 유지보수 시 수정 범위가 증가
  • 입력 검증(예외 처리) 추가 시 모든 코드에 동일하게 반영해야 하는 문제 발생
입력 처리 로직을 별도의 함수로 분리하여 재사용성을 높일 필요가 있어보인다

2.ClearScreen 방식

std::cout << std::string(30, '\n');

현재 화면을 초기화하기 위해 개행을 출력하는 방식을 사용하고 있다

  • 실제 화면이 지워지는 것이 아니라 단순히 밀어내는 방식
  • 콘솔 환경에 따라 출력 결과가 일관되지 않을 수 있음
추후 찾아보고 변경사항 추가

3.ShopItem 확장

현재 ShopItem은 다음과 같은 구조로 구성되어 있다.

  • name
  • price

이 구조는 기본적인 상점 기능에는 충분하나

  • 아이템 타입 ( 소모품, 장비 등)
  • 효과 ( 회복량, 버프, 디버프 등)
  • 설명 (UI 표시용 텍스트)

와 같은 요소를 추가하기 어려운 구조

기능 확장을 고려하여 구조를 확장 가능한 형태로 개선해야 한다

마무리

이번 구현을 통해 다음과 같은 점을 확인할 수 있엇다.

 

게임 시스템은 상태 흐름을 기반으로 설계되어야 하며,

UI와 로직을 분리함으로써 유지보수성과 확장성을 확보할 수 있다.

 

또한 객체 간 역할을 명확히 나누는 것이 전체 구조의 안정성과 코드 관리 측면에서 중요하다는 것을 이해하게 되었다.

 

특히 팀 프로젝트를 통해

각 기능이 독립적으로 동작할 수 있도록 설계하는 것이 협업에서 필수적이며,

단순 구현을 넘어서 구조를 고려한 개발의 중요성을 경험할 수 있엇다.