Print Friendly and PDF

C++/C++입문

[C++] 1. TextRPG

나는야 개발자 2025. 3. 28. 07:03
반응형

로비 메뉴 구성

enum MAIN_MENU
{
	MM_NONE,
	MM_MAP,
	MM_STORE,
	MM_INVENTORY,
	MM_EXIT
};

- 맵, 상점, 인벤, 종료로 enum(열거체) 추가

 

메뉴 선택 구성

int main()
{
	while (true)
	{
		//로비 구성
		system("cls");
		cout << "******로비******" << endl;
		cout << "1. 맵" << endl;
		cout << "2. 상점" << endl;
		cout << "3. 가방" << endl;
		cout << "4. 종료" << endl;

		cout << "메뉴를 선택하세요! : ";
		int imenu;
		cin >> imenu;

		if (cin.fail())
		{
			cin.clear();
			cin.ignore(1024, '\n');
			continue;
		}

		if (imenu == MM_EXIT)
		{
			break;
		}
	}
	return 0;
}

- main 함수에 while문을 이용해 종료되지 않도록 구성

- 플레이어가 메뉴를 선택할 수 있도록 구성

 

- 현재 4번을 누르면 종료되고 나머진 다시 선택하도록 되어 있음

 

맵 선택지 추가

enum MM_TYPE
{
	MT_NONE,
	MT_EASY,
	MT_NORMAL,
	MT_HARD,
	MT_BACK
};

- enum(열거체)로 맵 선택시 선택지 추가

 

//메뉴에 따른 처리 
switch (imenu)
{
	//맵 선택
case MM_MAP:
	while (true)
	{
		system("cls");
		cout << "******맵******" << endl;
		cout << "1. 쉬움" << endl;
		cout << "2. 보통" << endl;
		cout << "3. 어려움" << endl;
		cout << "4. 뒤로가기" << endl;

		cout << "난이도를 선택해 주세요 : ";
		cin >> imenu;
		if (cin.fail())
		{
			cin.clear();
			cin.ignore(1024, '\n');
			continue;
		}

		//이 if문은 맵 메뉴를 돌려주기 위한 while에 속해 있으므로 이 while문을 빠져나감
		if (imenu == MT_BACK)
		{
			break;
		}
	}
	break;
case MM_STORE:
	break;
case MM_INVENTORY:
	break;
default:
	break;
}

- while문을 이용해 각각 enum에 따른 처리 구성

- MAP에 while문을 이용해 선택지 추가

 

- 1번 선택시 맵으로 가고 -> 맵에서 4번 선택시 -> 로비로 잘 감

 

플레이어 구조체 추가

enum JOB
{
	JOB_NONE,
	JOB_KNIGHT,
	JOB_ARCHER,
	JOB_WIZARD,
    JOB_END
};

#define NAME_SIZE 32

struct _tagPlayer
{
	char strName[NAME_SIZE];
	char strJobNAME[NAME_SIZE];
	JOB eJob;
	int iAttackMin;
	int iAttackMax;
	int iArmorMin;
	int iArmorMax;
	int iHp;
	int iHpMax;
	int iMP;
	int iMPMax;
	int iExp;
	int iLevel;
};

- 플레이어의 직업으로 enum추가

- 각 필요한 요소들 추가

- min, max값은 범위값으로 주기 위함

 

몬스터 구조체 추가

struct _tagMonster
{
	char strName[NAME_SIZE];
	int iAttackMin;
	int iAttackMax;
	int iArmorMin;
	int iArmorMax;
	int iHp;
	int iHpMax;
	int iMP;
	int iMPMax;
	int iExp;
	int iLevel;
	int iGoleMin;
	int iGoleMax;
};

- 몬스터에게 iGold는 몬스터 처지 시 획득용

- 나머지는 비슷

 

캐릭터 생성

int main()
{
	srand((unsigned int)time(0));
	//게임 시작할때 플레이어 정보 설정

	_tagPlayer tPlayer = {};

	//이름 설정
	cout << "이름 : ";
	//끝까지 문자열을 다 채워버리면 null을 인식 못하기 때문
	cin.getline(tPlayer.strName, NAME_SIZE - 1);


	//직업 설정 
	int iJob = JOB_NONE;
	while (iJob == JOB_NONE)
	{
		system("cls");
		cout << "1. 기사" << endl;
		cout << "2. 궁수" << endl;
		cout << "3. 마법사" << endl;
		cout << "직업을 선택하세요 : " << endl;

		if (cin.fail())
		{
			cin.clear();
			cin.ignore(1024, '\n');
			continue;
		}
		else if (iJob <= JOB_NONE || iJob >= JOB_END)
		{
			iJob = JOB_NONE;
		}

		//직업 이름
		tPlayer.eJob = (JOB)iJob;

		switch (tPlayer.eJob)
		{
		case JOB_KNIGHT:
			strcpy_s(tPlayer.strJobNAME, "기사");
			tPlayer.iAttackMin = 5;
			tPlayer.iAttackMax = 10;
			tPlayer.iArmorMin = 15;
			tPlayer.iArmorMin = 20;
			tPlayer.iHpMax = 500;
			tPlayer.iHp = 500;
			tPlayer.iMP = 100;
			tPlayer.iMPMax = 100;
			break;
		case JOB_ARCHER:
			strcpy_s(tPlayer.strJobNAME, "궁수");
			tPlayer.iAttackMin = 10;
			tPlayer.iAttackMax = 15;
			tPlayer.iArmorMin = 10;
			tPlayer.iArmorMin = 15;
			tPlayer.iHpMax = 400;
			tPlayer.iHp = 400;
			tPlayer.iMP = 200;
			tPlayer.iMPMax = 200;
			break;
		case JOB_WIZARD:
			strcpy_s(tPlayer.strJobNAME, "마법사");
			tPlayer.iAttackMin = 15;
			tPlayer.iAttackMax = 20;
			tPlayer.iArmorMin = 5;
			tPlayer.iArmorMin = 10;
			tPlayer.iHpMax = 300;
			tPlayer.iHp = 300;
			tPlayer.iMP = 300;
			tPlayer.iMPMax = 300;
			break;
		}

		tPlayer.iLevel = 1;
		tPlayer.iExp = 0;
	}

...생략

- 캐릭터 이름, 직업 선택 후 각 직업별 능력치 추가

 

몬스터 생성

...생략
    tPlayer.iLevel = 1;
	tPlayer.iExp = 0;
}

//몬스터 생성
_tagMonster tMonsterArr[MT_BACK - 1] = {};

//고블린 생성
strcpy_s(tMonsterArr[0].strName, "고블린");
tMonsterArr[0].iAttackMin = 20;
tMonsterArr[0].iAttackMax = 30;
tMonsterArr[0].iArmorMin = 2;
tMonsterArr[0].iArmorMax = 5;
tMonsterArr[0].iHp = 100;
tMonsterArr[0].iHpMax = 100;
tMonsterArr[0].iMP = 10;
tMonsterArr[0].iMPMax = 10;
tMonsterArr[0].iLevel = 1;
tMonsterArr[0].iExp = 1000;
tMonsterArr[0].iGoleMin = 500;
tMonsterArr[0].iGoleMax = 1500;

//트롤 생성
strcpy_s(tMonsterArr[1].strName, "트롤");
tMonsterArr[1].iAttackMin = 80;
tMonsterArr[1].iAttackMax = 130;
tMonsterArr[1].iArmorMin = 60;
tMonsterArr[1].iArmorMax = 90;
tMonsterArr[1].iHp = 2000;
tMonsterArr[1].iHpMax = 2000;
tMonsterArr[1].iMP = 100;
tMonsterArr[1].iMPMax = 100;
tMonsterArr[1].iLevel = 5;
tMonsterArr[1].iExp = 7000;
tMonsterArr[1].iGoleMin = 6000;
tMonsterArr[1].iGoleMax = 8000;

//드래곤 생성
strcpy_s(tMonsterArr[2].strName, "드래곤");
tMonsterArr[2].iAttackMin = 250;
tMonsterArr[2].iAttackMax = 500;
tMonsterArr[2].iArmorMin = 200;
tMonsterArr[2].iArmorMax = 400;
tMonsterArr[2].iHp = 30000;
tMonsterArr[2].iHpMax = 30000;
tMonsterArr[2].iMP = 20000;
tMonsterArr[2].iMPMax = 20000;
tMonsterArr[2].iLevel = 10;
tMonsterArr[2].iExp = 30000;
tMonsterArr[2].iGoleMin = 20000;
tMonsterArr[2].iGoleMax = 50000;



while (true)
{
	//로비 구성
    
...생략

- 각 몬스터 별로 셋팅

 

난이도 별 전투

...생략
        }

		//이 if문은 맵 메뉴를 돌려주기 위한 while에 속해 있으므로 이 while문을 빠져나감
		if (imenu == MT_BACK)
		{
			break;
		}

		//선택한 메뉴 1을 빼주면 몬스터 배열의 인덱스가 된다
		//그렇게 해서 해당 맵의 몬스터 생성
		_tagMonster tMonster = tMonsterArr[imenu - 1];

		//전투 시작
		while (true)
		{
			switch (imenu)
			{
			case MT_EASY:
				cout << "********* 쉬움 *********" << endl;
				break;
			case MT_NORMAL:
				cout << "********* 보통 *********" << endl;
				break;
			case MT_HARD:
				cout << "********* 어려움 *********" << endl;
				break;
			}
		}
	}
	break;
case MM_STORE:
...생략

- 맵 선택 후 각 난이도별 처리용 swich문 추가

 

최종코드

#include <iostream>
#include <time.h>


using namespace std;

enum MAIN_MENU
{
	MM_NONE,
	MM_MAP,
	MM_STORE,
	MM_INVENTORY,
	MM_EXIT
};

enum MM_TYPE
{
	MT_NONE,
	MT_EASY,
	MT_NORMAL,
	MT_HARD,
	MT_BACK
};

enum JOB
{
	JOB_NONE,
	JOB_KNIGHT,
	JOB_ARCHER,
	JOB_WIZARD,
	JOB_END
};

#define NAME_SIZE 32

struct _tagPlayer
{
	char strName[NAME_SIZE];
	char strJobNAME[NAME_SIZE];
	JOB eJob;
	int iAttackMin;
	int iAttackMax;
	int iArmorMin;
	int iArmorMax;
	int iHp;
	int iHpMax;
	int iMP;
	int iMPMax;
	int iExp;
	int iLevel;
};

struct _tagMonster
{
	char strName[NAME_SIZE];
	int iAttackMin;
	int iAttackMax;
	int iArmorMin;
	int iArmorMax;
	int iHp;
	int iHpMax;
	int iMP;
	int iMPMax;
	int iExp;
	int iLevel;
	int iGoleMin;
	int iGoleMax;
};

int main()
{
	srand((unsigned int)time(0));
	//게임 시작할때 플레이어 정보 설정

	_tagPlayer tPlayer = {};

	//이름 설정
	cout << "이름 : ";
	//끝까지 문자열을 다 채워버리면 null을 인식 못하기 때문
	cin.getline(tPlayer.strName, NAME_SIZE - 1);


	//직업 설정 
	int iJob = JOB_NONE;
	while (iJob == JOB_NONE)
	{
		system("cls");
		cout << "1. 기사" << endl;
		cout << "2. 궁수" << endl;
		cout << "3. 마법사" << endl;
		cout << "직업을 선택하세요 : " << endl;

		if (cin.fail())
		{
			cin.clear();
			cin.ignore(1024, '\n');
			continue;
		}
		else if (iJob <= JOB_NONE || iJob >= JOB_END)
		{
			iJob = JOB_NONE;
		}

		//직업 이름
		tPlayer.eJob = (JOB)iJob;

		switch (tPlayer.eJob)
		{
		case JOB_KNIGHT:
			strcpy_s(tPlayer.strJobNAME, "기사");
			tPlayer.iAttackMin = 5;
			tPlayer.iAttackMax = 10;
			tPlayer.iArmorMin = 15;
			tPlayer.iArmorMin = 20;
			tPlayer.iHpMax = 500;
			tPlayer.iHp = 500;
			tPlayer.iMP = 100;
			tPlayer.iMPMax = 100;
			break;
		case JOB_ARCHER:
			strcpy_s(tPlayer.strJobNAME, "궁수");
			tPlayer.iAttackMin = 10;
			tPlayer.iAttackMax = 15;
			tPlayer.iArmorMin = 10;
			tPlayer.iArmorMin = 15;
			tPlayer.iHpMax = 400;
			tPlayer.iHp = 400;
			tPlayer.iMP = 200;
			tPlayer.iMPMax = 200;
			break;
		case JOB_WIZARD:
			strcpy_s(tPlayer.strJobNAME, "마법사");
			tPlayer.iAttackMin = 15;
			tPlayer.iAttackMax = 20;
			tPlayer.iArmorMin = 5;
			tPlayer.iArmorMin = 10;
			tPlayer.iHpMax = 300;
			tPlayer.iHp = 300;
			tPlayer.iMP = 300;
			tPlayer.iMPMax = 300;
			break;
		}

		tPlayer.iLevel = 1;
		tPlayer.iExp = 0;
	}

	//몬스터 생성
	_tagMonster tMonsterArr[MT_BACK - 1] = {};

	//고블린 생성
	strcpy_s(tMonsterArr[0].strName, "고블린");
	tMonsterArr[0].iAttackMin = 20;
	tMonsterArr[0].iAttackMax = 30;
	tMonsterArr[0].iArmorMin = 2;
	tMonsterArr[0].iArmorMax = 5;
	tMonsterArr[0].iHp = 100;
	tMonsterArr[0].iHpMax = 100;
	tMonsterArr[0].iMP = 10;
	tMonsterArr[0].iMPMax = 10;
	tMonsterArr[0].iLevel = 1;
	tMonsterArr[0].iExp = 1000;
	tMonsterArr[0].iGoleMin = 500;
	tMonsterArr[0].iGoleMax = 1500;

	//트롤 생성
	strcpy_s(tMonsterArr[1].strName, "트롤");
	tMonsterArr[1].iAttackMin = 80;
	tMonsterArr[1].iAttackMax = 130;
	tMonsterArr[1].iArmorMin = 60;
	tMonsterArr[1].iArmorMax = 90;
	tMonsterArr[1].iHp = 2000;
	tMonsterArr[1].iHpMax = 2000;
	tMonsterArr[1].iMP = 100;
	tMonsterArr[1].iMPMax = 100;
	tMonsterArr[1].iLevel = 5;
	tMonsterArr[1].iExp = 7000;
	tMonsterArr[1].iGoleMin = 6000;
	tMonsterArr[1].iGoleMax = 8000;

	//드래곤 생성
	strcpy_s(tMonsterArr[2].strName, "드래곤");
	tMonsterArr[2].iAttackMin = 250;
	tMonsterArr[2].iAttackMax = 500;
	tMonsterArr[2].iArmorMin = 200;
	tMonsterArr[2].iArmorMax = 400;
	tMonsterArr[2].iHp = 30000;
	tMonsterArr[2].iHpMax = 30000;
	tMonsterArr[2].iMP = 20000;
	tMonsterArr[2].iMPMax = 20000;
	tMonsterArr[2].iLevel = 10;
	tMonsterArr[2].iExp = 30000;
	tMonsterArr[2].iGoleMin = 20000;
	tMonsterArr[2].iGoleMax = 50000;

	

	while (true)
	{
		//로비 구성
		system("cls");
		cout << "******로비******" << endl;
		cout << "1. 맵" << endl;
		cout << "2. 상점" << endl;
		cout << "3. 가방" << endl;
		cout << "4. 종료" << endl;

		cout << "메뉴를 선택하세요! : ";
		int imenu;
		cin >> imenu;

		if (cin.fail())
		{
			cin.clear();
			cin.ignore(1024, '\n');
			continue;
		}

		if (imenu == MM_EXIT)
		{
			break;
		}

		//메뉴에 따른 처리 
		switch (imenu)
		{
			//맵 선택
		case MM_MAP:
			while (true)
			{
				system("cls");
				cout << "******맵******" << endl;
				cout << "1. 쉬움" << endl;
				cout << "2. 보통" << endl;
				cout << "3. 어려움" << endl;
				cout << "4. 뒤로가기" << endl;

				cout << "난이도를 선택해 주세요 : ";
				cin >> imenu;
				if (cin.fail())
				{
					cin.clear();
					cin.ignore(1024, '\n');
					continue;
				}

				//이 if문은 맵 메뉴를 돌려주기 위한 while에 속해 있으므로 이 while문을 빠져나감
				if (imenu == MT_BACK)
				{
					break;
				}

				//선택한 메뉴 1을 빼주면 몬스터 배열의 인덱스가 된다
				//그렇게 해서 해당 맵의 몬스터 생성
				_tagMonster tMonster = tMonsterArr[imenu - 1];

				//전투 시작
				while (true)
				{
					switch (imenu)
					{
					case MT_EASY:
						cout << "********* 쉬움 *********" << endl;
						break;
					case MT_NORMAL:
						cout << "********* 보통 *********" << endl;
						break;
					case MT_HARD:
						cout << "********* 어려움 *********" << endl;
						break;
					}
				}
			}
			break;
		case MM_STORE:
			break;
		case MM_INVENTORY:
			break;
		default:
			break;
		}
	}
	return 0;
}
반응형

'C++ > C++입문' 카테고리의 다른 글

[C++] 3. TextPRG 상점 제작  (0) 2025.04.01
[C++] 2. TextRPG 전투  (0) 2025.03.30
[C++] 구조체와 문자열  (0) 2025.03.28
[C++] 빙고 게임 하드모드  (0) 2025.03.27
[C++] 빙고 게임_3  (0) 2025.03.26