텍스트던전rpg 분석

2026. 5. 6. 20:15·본캠프

#include

#include <iostream> // cout, cin, endl
#include <string>   // string 문자열 자료형
#include <vector>   // vector 동적 배열
#include <algorithm>// sort, min
#include <map>      // key-value 저장소

 

using namespace std; 

using namespace std;

// std를 안썼을때
std::cout << "hello";
std::string name;

// std를 썼을때
cout << "hello";
string name;

C++ 표준 라이브러리의 기능들은 원래 std::cout, std::string처럼 써야 함.
그런데 이 문장을 쓰면 std::를 생략할 수 있음.

 

템플릿 template<typename T> — 자료형을 일반화

template<typename T> //여기서 T는 “아직 정해지지 않은 타입”.
class Inventory
{
    ...
};

Inventory<Item> inventory(10); // 예시코드

템플릿은 자료형을 나중에 정하게 하는 문법.

이걸 통해 하나의 클래스로 여러 타입을 처리하는 방법을 알수잇음.

 

클래스 class - 사용자 정의 자료형

class Player
{
protected:
    string name;
    string job;
    int level;
    int exp;
    int maxExp;
    int hp;
    int mp;
    int power;
    int defence;
    ...
};

클래스는 데이터와 기능을 하나로 묶는 문법

  • 데이터: 이름, 직업, HP, MP, 공격력
  • 기능: 공격, 상태 출력, getter, setter

접근 지정자 private, protected, public

private: // 클래스 내부에서만 사용
    T* pItems;
    int capacity_;
    int size_;

protected: // 클래스 내부 + 자식 클래스
    string name;
    string job;

public: // 외부에서도 사용 가능
    Player(string name, int hp, int mp, int power, int defence)

 

  • Inventory 내부 배열은 외부가 함부로 건드리면 안 되니까 private
  • Player의 이름/직업은 자식 클래스(전사, 궁수)가 써야 하니까 protected
  • 생성자, getter, setter는 외부에서 써야 하니까 public

생성자 - 객체가 만들어질 때 자동 실행

Player(string name, int hp, int mp, int power, int defence)
{
    this->name = name;
    this->job = "None";
    this->level = 1;
    this->exp = 0;
    this->maxExp = 100;
    this->hp = hp;
    this->mp = mp;
    this->power = power;
    this->defence = defence;
}

 

생성자는 객체를 만들 때 자동으로 호출되는 함수야.

 

역할

플레이어 객체가 만들어지면:

  • 이름 저장
  • 초기 직업 설정
  • 레벨 1 설정
  • 경험치 0 설정
  • 기본 스탯 저장

이런 초기화 작업을 해줌.

 

this-> -- 현재 객체 자신 가리키기

this->name = name;
this->hp = hp;

this는 현재 객체 자신을 가리키는 포인터.

매개변수 이름과 멤버변수 이름이 같아서 구분하려고 씀.

 

상속 : public Player

class Warrior : public Player
{
public:
    Warrior(string name, int hp, int mp, int power, int defence)
        : Player(name, hp, mp, power, defence)
    {
        job = "전사";
        this->hp += 30;
    }

    void attack(Monster* monster) override;
};

상속은 기존 클래스의 기능을 물려받아 새 클래스를 만드는 문법.

 

생성자 초기화 리스트 : Player(...)

Warrior(string name, int hp, int mp, int power, int defence)
    : Player(name, hp, mp, power, defence)
{
    ...
}

자식 클래스가 만들어질 때, 먼저 부모 클래스 생성자를 호출하는 문법.

전사를 만들기 전에 먼저 Player 부분을 초기화하고,
그 다음에 전사 전용 설정을 추가한다.

 

가상 함수와 순수 가상 함수

virtual void attack(Monster* monster) = 0;

순수 가상 함수.
부모 클래스에서는 형태만 정하고, 구현은 자식이 꼭 하게 만드는 문법.

Player는 “플레이어는 공격할 수 있다”는 틀만 제공하고,
실제 공격 방식은 전사/마법사/도적/궁수가 각자 구현.

 

오버라이딩 override

void attack(Monster* monster) override;  // 예시코드

void Archer::attack(Monster* monster)
{
    int damage = (power - monster->getDefence()) / 3;
    ...
}

오버라이딩은 부모 클래스의 함수를 자식 클래스가 다르게 다시 구현.

  • 전사: 한 번 강하게
  • 마법사: 한 번 강하게
  • 궁수: 3번 나눠 때림
  • 도적: 5번 나눠 때림

같은 attack인데 행동이 다르다.

 

전방 선언 class Monster;

class Monster;

이건 “Monster라는 클래스가 뒤에 나올 거다”라고 미리 이름만 알려주는 문법.

 

왜 필요한가?

virtual void attack(Monster* monster) = 0;

player 안에서 위의 코드가있음

그런데 Monster 클래스 정의는 뒤쪽에 있기때문에
컴파일러에게 “Monster라는 타입이 나중에 나와”라고 미리 알려줘야 한다.

 

포인터 T*, Player*, Monster*

T* pItems;  // 아이템 배열의 시작 주소
Player* player = nullptr; // 플레이어 객체를 가리키는 주소
virtual void attack(Monster* monster) = 0; // 몬스터 객체를 가리키는 주소

포인터는 메모리 주소를 저장하는 변수.

 

  • 동적 메모리 할당
  • 함수에 원본 객체 전달
  • 부모 포인터로 자식 객체 다루기

동적 메모리 new, delete[], delete

pItems = new T[capacity_];
delete[] pItems;


player = new Warrior(name, stat[0], stat[1], stat[2], stat[3]);
...
delete player;

 

프로그램 실행중에 메모리를 직접 만들고 해제하는 문법.

 

  • new T[capacity_] : 배열 생성
  • delete[] pItems : 배열 해제
  • new Warrior(...) : 객체 1개 생성
  • delete player : 객체 1개 해제

소멸자 ~Inventory()

~Inventory()
{
    delete[] pItems;
}

 

소멸자는 객체가 사라질 때 자동 호출되는 함수.

Inventory가 사라질 때 내부에서 new[]로 만든 메모리를 정리한다.

 

복사 생성자

Inventory(const Inventory& other)
{
    capacity_ = other.capacity_;
    size_ = other.size_;
    pItems = new T[capacity_];

    for (int i = 0; i < size_; i++)
    {
        pItems[i] = other.pItems[i];
    }
}

복사 생성자는 객체를 복사해서 새 객체를 만들 때 호출되는 함수.

Inventory는 내부에 포인터 pItems가 있어서,
그냥 복사하면 주소만 복사되는 얕은 복사 문제가 생길 수 있음.

그래서 새 메모리를 만들고, 안의 값들을 직접 복사해야함.

 

배열과 인덱스

int stat[SIZE] = { 0 };
cout << "HP: " << stat[0] << "     MP: " << stat[1] << endl;
cout << "공격력: " << stat[2] << "     방어력: " << stat[3] << endl;

배열은 같은 타입의 데이터를 순서대로 저장하는 구조.

 

함수 매개변수와 반환값

int GetStock(map<string, int>& potionStock, string name)
{
    return potionStock[name];
}

함수는 입력을 받고 결과를 돌려줄 수 있음.

 

참조 & 와 포인터 * 차이

// 예시1
int GetStock(map<string, int>& potionStock, string name)
// 예시2
void setPotion(int count, int* p_HPPotion, int* p_MPPotion)
{
    *p_HPPotion = count;
    *p_MPPotion = count;
}

둘 다 원본에 접근할 수 있지만 다르다.

  • 참조 & : 원본의 다른 이름처럼 사용
  • 포인터 * : 주소를 받아서 역참조해서 사용

둘다나오는 이유

  • map은 참조로 넘겨서 편하게 수정/조회
  • 포션 숫자는 포인터로 넘겨서 주소 개념 연습

getter / setter

int getHP()
{
    return hp;
}

void setHP(int hp)
{
    this->hp = hp;
}

클래스 내부 데이터를 직접 열어두지 않고,
함수를 통해 읽고 수정하는 방법.

  • 외부가 내부 구조를 직접 건드리지 않음
  • 나중에 검증 로직 추가 가능
  • 캡슐화 강화

구조체 struct

struct Item
{
    string name;
    int price;

    void PrintInfo() const
    {
        cout << name << " (" << price << "G)" << endl;
    }
};

// 또는

struct PotionRecipe
{
    string potionName;
    string ingredient1;
    string ingredient2;
};

 

구조체는 관련 있는 데이터를 묶는 자료형.
C++에서는 함수도 넣을 수 있어서 class와 비슷하게 쓸 수 있음.

  • Item : 아이템 정보
  • PotionRecipe : 포션 레시피 정보
  • DungeonRoom : 방 정보

const - 수정 금지 약속

void PrintInfo() const

void ShowAllRecipes(const vector<PotionRecipe>& recipes)

const는 “이걸 수정하지 않겠다”는 약속이야.

  • PrintInfo() const : 이 함수는 객체의 멤버값을 바꾸지 않음
  • const vector<PotionRecipe>& : recipes를 읽기만 하고 수정하지 않음

vector — 동적 배열

vector<PotionRecipe> recipes;
recipes.push_back({ "HP포션", "허브", "맑은물" });

vector는 크기가 자동으로 늘어나는 배열.

포션 레시피 개수가 고정이 아니어도 편하게 추가할 수 있음.

 

map<string, int> — key-value 자료구조

map<string, int> potionStock;

potionStock["HP 포션"] = 3;
potionStock["MP 포션"] = 3;

map은 이름표(key) 와 값(value) 를 짝으로 저장하는 자료구조.

 

반복문 for, while

for (int i = 0; i < size_; i++)
{
    pItems[i] = other.pItems[i];
}


while (true)
{
    ...
}
  • for : 횟수가 명확할 때
  • while : 조건이 참인 동안 반복할 때

예시

  • for : 인벤토리 복사, 배열 출력, 방 순회
  • while : 게임 메뉴 반복, 전투 반복, 입력 검증

조건문 if, else if, switch

if (damage <= 0)
{
    damage = 1;
}


switch (jobChoice)
{
case 1:
    player = new Warrior(...);
    break;
...
}

조건에 따라 분기하는 문법이야.

  • if : 범위, 비교, 복합 조건에 강함
  • switch : 번호 선택 메뉴에 적합

sort, min — 알고리즘 함수

sort(pItems, pItems + size_, compareByPrice);

int newHP = min(player->getHP() + 50, 100);

표준 라이브러리 알고리즘을 직접 사용하는 방법이야.

  • sort : 정렬
  • min : 둘 중 작은 값

예시

  • 아이템 가격순 정렬
  • HP/MP가 최대값을 넘지 않게 제한

'본캠프' 카테고리의 다른 글

5/8 (코드카타)  (0) 2026.05.08
5/7 (코드카타)  (0) 2026.05.07
5/6 (개인프로젝트,과제2도전step8)  (0) 2026.05.06
4/30(코드카타)  (0) 2026.04.30
던전탈출rpg과제 총정리+학습  (0) 2026.04.29
'본캠프' 카테고리의 다른 글
  • 5/8 (코드카타)
  • 5/7 (코드카타)
  • 5/6 (개인프로젝트,과제2도전step8)
  • 4/30(코드카타)
백구
백구
게임개발 공부블로그 입니다.
  • 백구
    백구 게임개발 스터디
    백구
  • 전체
    오늘
    어제
    • 분류 전체보기 (21) N
      • 사전캠프 (5)
      • 본캠프 (16) N
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
백구
텍스트던전rpg 분석
상단으로

티스토리툴바