1-1. Battle.h

class Battle {

public:
	static Item startBattle(Player* player, Monster& monster, vector<Item>& inventory);

};

먼저 Battle 클래스가 인벤토리 데이터에 직접 접근하고 아이템을 차감할 수 있도록 startBattle()의 매개변수에 인벤토리를 추가로 넘겨줌. vector라는 상자 안에는 오직 Item 형태의 데이터만 들어갈 수 있고, &(레퍼런스)을 이용해서 직접 복사하는 게 아니라 inventory 원본 자체에 직접 연결함.

1-2. Battle.cpp

#include <algorithm>	//min 사용을 위해 추가

while (player->getHP() > 0 && monster.getHP() > 0) {	//둘다 살아있을 때 전투루프

	cout << "\n--- 플레이어 턴 ---" << endl;				//플레이어 턴, 플레이어 메뉴
	cout << "1. 공격" << endl;
	cout << "2. 아이템 사용" << endl;
	cout << "선택: ";

	int inBattleChoice;
	cin >> inBattleChoice;

	if (inBattleChoice == 1) {
		player->attack(&monster);
	}

	else if (inBattleChoice == 2) {
		cout << "\n[ 인벤토리 ]" << endl;
		//인벤토리에 아이템이 없을 때
		if (inventory.empty()) {
			cout << "사용할 수 있는 아이템이 없습니다." << endl;
		}
		else {
			int i = 1;
			for (const auto& item : inventory) {
				cout << i << ". ";	//인벤토리 번호 출력
				item.PrintItemInfo();	//Item.h 에 정의되어있는 함수
				i++;
			}
			cout << "0. 취소" << endl;
			cout << "사용할 아이템 번호: ";

			int itemChoice;
			cin >> itemChoice;

			if (itemChoice == 0) {
				continue;

			}
			//아이템을 선택하고 사용하는 로직.
			else if (itemChoice > 0 && itemChoice <= inventory.size()) {
				int itemIndex = itemChoice - 1;
				string itemName = inventory[itemIndex].name;

				if (itemName == "HP포션") {	//hp포션
					int currentHP = player->getHP();
					int healAmount = 50;
					player->setHP(min(currentHP + healAmount, player->getMaxHP()));
					cout << "* HP 포션 사용! HP " << healAmount << " 회복 (" << currentHP << " -> " << player->getHP() << ")" << endl;
				}
				else if (itemName == "MP포션") {	//mp포션
					int currentMP = player->getMP();
					int healAmount = 50;
					player->setMP(min(currentMP + healAmount, player->getMaxHP()));
					cout << "* MP 포션 사용! MP " << healAmount << " 회복 (" << currentMP << " -> " << player->getMP() << ")" << endl;
				}
				else {
					cout << "전투 중에 사용할 수 없는 아이템입니다." << endl;
					continue;
				}
				//아이템을 사용했으면 for문을 빠져나와서 인벤토리에서 차감
				if (itemName == "HP포션" || itemName == "MP포션") {
					inventory[itemIndex].count--;
					if (inventory[itemIndex].count == 0) {
						inventory.erase(inventory.begin() + itemIndex);	//사용 후 아이템이 없으면 인벤토리에서 지워줌.
					}
				}
			}
			else {
				cout << "숫자를 잘못 입력하였습니다." << endl;
				continue;
			}
		}
	}
	else {
		cout << "올바른 번호를 입력하여 메뉴를 선택하세요." << endl;
		continue;
	}

min 함수를 사용하기 위해 #include <algorithm>을 추가하고,  int inBattleChoice; 를 선언해서 전투 중 메뉴 선택을 구현. 1을 눌렀을 때 부모 클래스에서 선언한 순수 가상함수를 불러와서 몬스터에게 공격, 2를 눌렀을 때 인벤토리를 보여주고 아이템 목록이 출력되도록 변경. 잘못된 숫자를 입력하면 다시 입력하라는 문자열이 출력되고 다시 이전 메뉴로 돌아감.

 

인벤토리에서 아이템을 문자열로 출력하는 데에는 for문을 사용. int i = 1;로 초기화 시켜 놓고 인덱스 첫번째 부터 i = 1, 2, 3 순서대로 출력되도록 했음. 짝을 맞추어 item.printItemInfo() 함수를 사용해서 아이템 이름과 번호를 매칭시켰음.

 

출력된 아이템을 선택하는 부분에서는 입력한 번호를 아까 저장해 놓은 i와 대조해서 일치하면 해당 아이템이 사용가능한지 확인하고, 0을 누르면 이전 메뉴로 돌아가는 로직을 작성했음. 0을 누르면 문자열이 출력되고 continue;를 통해서 while문이 시작되는 위치로 돌아가게 됨. 

 

사용할 아이템 번호를 선택하는 것에서는 세가지 케이스가 있을 수 있음. 1. 사용할 수 있는 아이템을 선택, 2. 사용할 수 없는 아이템을 선택, 3. 이상한 번호를 입력. 1. 사용할 수 있는 아이템의 경우 : 우선 입력한 숫자의 크기가 인벤토리의 i 숫자보다 작거나 같은 지 테스트 해야 함. 즉, (itemChoice > 0 && itemChoice <= inventory.size()) 조건을 만족해야 함.

 

인벤토리안에 만들어진 방의 크기가 현재 i 변수의 끝 값과 같다는 점을 이용. 조건을 만족한 경우, inventorty에 저장되어 있는 itemIndex와 itemChoice-1 을 비교해서 같은 경우에,  inventory에서 itemIndex와 매칭되는 name을 뽑아와서 string itemName에 대입하게 됨. 여기서  itemIndex는 0부터 시작하고, itemChoice는 우리가 i = 1 부터 시작하도록 했기 때문에 -1을 해야 함.

 

이후 HP포션을 잘 찾아서 번호를 잘 입력하면 HP포션이 사용됨. 체력을 채우기 위해 int currentHP와 int healAmount를 선언하고, 각각 player->getMP(), 50으로 초기화. player->setMP()를 이용해서 체력을 채우게 했고, 이때 min값을 활용해서 최대치를 넘어 회복되지 않게 작성하였음. (min(currentHP + healAmount, player->getMaxHP()). 

 

아이템을 성공적으로 사용한 경우, 즉, 내가 검색한 itemChoice로 인해 뽑아온 item.name이 HP포션이거나 MP포션일 경우, inventory[itemIndex].count--; 를 실행. 이후 또다시 조건문을 달아서 count--를 실행한 결과 inventory[itemIndex].count가 0이 된 경우 inventory.erase(inventory.begin() + itemIndex);

 

풀어서 생각해보면, 2번째 칸 아이템을 다 써서 삭제하고 싶을 때 itemIndex 는 0에서부터 시작한다. 따라서 itemIndex는 1이다. inventory.begin()은 기본적으로 첫번째 원소를 찾으므로 원소들이 줄을 서있는 맨 앞쪽으로 가서 시작 위치를 잡는 거라고 생각하면 된다.  항상 컴퓨터식 사고방식을 해야한다. "inventory의 맨 처음 위치에서 시작해서 itemIndex만큼(한 칸 뒤에 있는) 이동한 곳에 있는 데이터를 삭제해라."2. 사용할 수 없는 아이템의 경우 : 문자열을 출력하고 continue를 사용해서 while문 처음으로 다시 돌아가도록 했다.

 

	if (monster.getHP() <= 0) {
		cout << "\n★ 전투 승리!" << endl;
		cout << "  -> " << monster.getDropItemName() << " 획득!" << endl;
		cout << "  -> 인벤토리에 저장되었습니다." << endl;
		cout << "\n계속하려면 아무 키나 누르세요." << endl;
		system("pause > nul");

		return Item(monster.getDropItemName(), monster.getDropItemPrice(), 1);
	}

이후 전투 승리 시 아이템을 얻을 때 Monster.h에서 정의한 함수를 가져와 아이템이름, 아이템가격, 갯수(1개)를 받아오게 수정.추가적으로 Monster.h에 getDropItemPrice(); 함수가 선언되어 있지 않아 추가로 선언하였음.

 

2. Player.h

public:
	int getMaxHP() { return maxHp; }
	int getMaxMP() { return maxMp; }

포션 사용의 최대 회복치를 구현하기 위해 Player.h에 getMaxHP, getMaxMP 함수를 추가했음.

 

 

+ Recent posts