개요 및 목표

개발 목표

  • 배열, 구조체, 함수를 최대한 활용한다.
  • 기존 탈출 게임을 확장하여 Ver 2.0을 제작한다.

맵 시스템

  • 맵은 타일(Tile) 단위로 구성하며 구조체로 관리한다.
  • 각 타일은 서로 다른 종류를 가진다.
    • 숲 / 늪 / 땅
    • 타일 종류에 따라 등장하는 몬스터가 다르다.
  • 몬스터는 맵에 직접 보이지 않으며, 이동 중 랜덤 인카운터로 전투가 발생한다 (포켓몬 방식).

타일 속성

  • x좌표
  • y좌표
  • 타입
  • 모양 (선택 사항)

플레이어

플레이어 속성

  • x좌표, y좌표
  • 이름
  • 최대 HP
  • 소유 골드
  • 공격력
  • 레벨
  • 경험치

몬스터

몬스터 속성

  • x좌표, y좌표
  • HP
  • 공격력
  • 드랍 골드
  • 이름

상점 시스템

  • 레벨업 (경험치 소모)
  • 체력 회복 (골드 소모)
  • 공격력 증가 (골드 + 소량의 경험치 소모)

전투 시스템

  • 랜덤 확률 기반 전투
  • 특정 키 입력 시 공격 성공
  • 알파 요소: 본인이 원하는 전투 기획을 자유롭게 추가 가능

클리어 조건

  • 특정 레벨에 도달하면 탈출구 생성
  • 탈출구에 도달하면 게임 클리어

구현 결과



#include <iostream>
#include <string>
#include <conio.h> // getch

using namespace std;

// 구조체 설정
struct Tile 
{
    string shape; // 타일 모양 저장
    int type;     // 0:땅, 1:숲, 2:늪, 3:상점, 9:탈출구
};

struct Player 
{
    int x, y;
    int hp, maxHp;
    int gold, exp, level;
    int atk;
};

struct Mob
{
    string mobName;
    int mobHp;
    int mobAtk;
    int rewardGold;
    int rewardExp;
};

// 변수
Tile map[10][10];
Player hero;
bool isGameRunning = true;

// 몬스터 도감 (0:슬라임, 1:늑대, 2:오크)
Mob mobData[3] = 
{
    { "슬라임", 30, 5, 10, 15 },
    { "늑대", 60, 15, 30, 30 },
    { "오크", 100, 30, 50, 50 }
};

// 함수들
// 게임 초기화
void InitGame() 
{
    // 플레이어: (0,0), 체력 100, 골드 0, 경험치 0, 레벨 1, 공격력 10
    hero = { 0, 0, 100, 100, 0, 0, 1, 100 };

    // 맵 만들기
    for (int y = 0; y < 10; y++) 
    {
        for (int x = 0; x < 10; x++) 
        {
            // 상점 (시작 위치)
            if (x == 0 && y == 0) 
            {
                map[y][x].type = 3;
                map[y][x].shape = "상 ";
            }
            else // 랜덤 생성 ( 땅 60프로 , 숲 30프로, 늪 10프로)
            {
                int r = rand() % 10;
                if (r < 6) 
                {
                    map[y][x].type = 0; map[y][x].shape = "땅 ";
                }
                else if (r < 9) 
                {
                    map[y][x].type = 1; map[y][x].shape = "숲 ";
                }
                else 
                {
                    map[y][x].type = 2; map[y][x].shape = "늪 ";
                }
            }
        }
    }
}

// 화면 그리기
void Draw() 
{
    system("cls");
    cout << "게임 이름: 영웅은 절차적\n";
    cout << "======================================\n";
    cout << " Lv." << hero.level << "  HP:" << hero.hp << "/" << hero.maxHp << "\n";
    cout << " 공격:" << hero.atk << "  골드:" << hero.gold << "  경험치:" << hero.exp << "\n";
    cout << "======================================\n";

    for (int y = 0; y < 10; y++) 
    {
        for (int x = 0; x < 10; x++) 
        {
            if (x == hero.x && y == hero.y) 
            {
                cout << "나 ";
            }
            else 
            {
                cout << map[y][x].shape;
            }
        }
        cout << "\n";
    }
    cout << "\n[WASD:이동] [Q:종료]\n";
}

// 레벨업, 탈출구 생성
void CheckLevelUp() 
{
    if (hero.exp >= 100) 
    {
        hero.level++;
        hero.exp -= 100; // 남은 경험치 유지
        hero.maxHp += 20;
        hero.hp = hero.maxHp;
        hero.atk += 5;

        system("cls");
        cout << "\n 레벨업! Lv." << hero.level << " 달성! \n";

        // 레벨 3이 되면 문 생성
        if (hero.level == 2) 
        {
            while (true) 
            {
                int rx = rand() % 10;
                int ry = rand() % 10;
                if ((rx != hero.x || ry != hero.y) && map[ry][rx].type != 3) // 플레이어가 없고, 상점도 아닌 곳
                {
                    map[ry][rx].type = 9;   // 탈출구
                    map[ry][rx].shape = "!! ";
                    cout << "\n !!! 어딘가에 탈출구가 나타났습니다 !!!\n";
                    break;
                }
            }
        }
        cout << " (계속하려면 아무 키나 누르세요)\n";
        _getch();
    }
}

// 상점 함수
void OpenShop() 
{
    while (true) 
    {
        system("cls");
        cout << " [ 상 점 ] \n";
        cout << " (내 돈: " << hero.gold << "G 내 경험치: " << hero.exp << ")\n\n";
        cout << " 1. 치료하기         (비용: 20 Gold) -> 체력 100% 회복\n";
        cout << " 2. 최대 체력 늘리기 (비용: 50 Exp)  -> 최대 체력 +10\n";
        cout << " 3. 무기 강화하기    (비용: 30 Gold + 30 Exp) -> 공격력 +3\n";
        cout << " 4. 나가기\n";
        cout << "\n 무엇을 하시겠습니까? >> ";

        char key = _getch();

        if (key == '1') // 치료
        { 
            if (hero.gold >= 20) 
            {
                hero.gold -= 20;
                hero.hp = hero.maxHp;
                cout << "\n >> 체력이 모두 회복되었습니다!\n";
            }
            else 
            {
                cout << "\n >> 골드가 부족합니다!\n";
            }
        }
        else if (key == '2') // 최대 체력 증가
        { 
            if (hero.exp >= 50) 
            {
                hero.exp -= 50;
                hero.maxHp += 10;
                hero.hp += 10; // 늘어난 만큼 현재 체력도 채워줌
                cout << "\n >> 최대 체력이 늘어났습니다!\n";
            }
            else 
            {
                cout << "\n >> 경험치가 부족합니다!\n";
            }
        }
        else if (key == '3') // 공격력 증가
        { 
            if (hero.gold >= 30 && hero.exp >= 30) 
            {
                hero.gold -= 30;
                hero.exp -= 30;
                hero.atk += 3;
                cout << "\n >> 공격력이 강해졌습니다!\n";
            }
            else 
            {
                cout << "\n >> 골드나 경험치가 부족합니다!\n";
            }
        }
        else if (key == '4') // 나가기 
        {
            break;
        }
        if (key != '4') // 확인
        {
            cout << " (확인)";
            _getch();
        }
    }
}

// 전투
void Battle(Mob* origin)
{
    Mob monster = *origin;

    system("cls");
    cout << "야생의 " << monster.mobName << " 발견 !!!\n";

    while (true)
    {
        cout << "\n--------------------------------\n";
        cout << " 나 : HP " << hero.hp << " (공격력 " << hero.atk << ")\n";
        cout << " 적 : HP " << monster.mobHp << " (공격력 " << monster.mobAtk << ")\n";
        cout << "--------------------------------\n";
        cout << " [Z] 공격하기! ";

        char key = _getch();
        if (key == 'z' || key == 'Z')
        {
            monster.mobHp -= hero.atk;
            cout << "\n\n " << monster.mobName << "에게 " << hero.atk << " 데미지!";

            if (monster.mobHp <= 0)
            {
                cout << "\n\n >> 승리! " << monster.rewardGold << "골드, " << monster.rewardExp << "경험치 획득!\n";
                hero.gold += monster.rewardGold;
                hero.exp += monster.rewardExp;
                CheckLevelUp();
                _getch();
                break;
            }

            hero.hp -= monster.mobAtk;
            cout << "\n 적에게 " << monster.mobAtk << "만큼 맞았습니다!";

            if (hero.hp <= 0)
            {
                cout << "\n\n >> 사망했습니다. (게임 오버)\n";
                isGameRunning = false;
                _getch();
                break;
            }
        }
    }
}

// 플레이어 이동
void Move(int dx, int dy) 
{
    int nx = hero.x + dx;
    int ny = hero.y + dy;

    if (nx < 0 || nx >= 10 || ny < 0 || ny >= 10) return;

    hero.x = nx;
    hero.y = ny;

    int tileType = map[ny][nx].type;

    // 상점
    if (tileType == 3) 
    {
        OpenShop(); // 상점 함수 호출
    }
    // 탈출구
    else if (tileType == 9) 
    {
        system("cls");
        cout << "\n\n 축하합니다! 탈출에 성공했습니다! \n\n";
        isGameRunning = false;
        _getch();
    }
    // 전투 (땅, 숲, 늪)
    else 
    {
        int chance = 0;
        if (tileType == 0) chance = 30; // 땅 30%
        if (tileType == 1) chance = 60; // 숲 60%
        if (tileType == 2) chance = 90; // 늪 90%

        if (rand() % 100 < chance) 
        {
            {
                Battle(&mobData[tileType]);
            };
        }
    }
}

int main() 
{
    srand(time(NULL));
    InitGame();

    while (isGameRunning) 
    {
        Draw();
        char key = _getch();
        if (key == 'w') Move(0, -1);
        else if (key == 's') Move(0, 1);
        else if (key == 'a') Move(-1, 0);
        else if (key == 'd') Move(1, 0);
        else if (key == 'q') isGameRunning = false;
    }
    return 0;
}

구현 과정

  1. 타일 구조체와 플레이어, 몬스터의 구조체 설정
  2. 타일맵 크기와 플레이어의 변수 추가
  3. 몬스터 정보 설정
  4. 함수들 설정 ( 게임 초기화, 화면 구성, 레벨업과 탈출구 생성, 상점 구성, 전투, 이동)
  5. 타일의 형태는 땅, 숲, 늪 문자 그대로 넣었고 탈출구는 '문'으로 설정했다가 잘 안보여서 '!!'로 수정

0개의 댓글