TIL
05.26 TIL (ch.2 팀프로젝트 day3)
2026. 5. 26. 21:01

*오늘의 코드카타*

array의 각 element 중 divisor로 나누어 떨어지는 값을 오름차순으로 정렬한 배열을 반환하는 함수, solution을 작성해주세요. divisor로 나누어 떨어지는 element가 하나도 없다면 배열에 -1을 담아 반환하세요.

arr은 자연수를 담은 배열이고, 정수 i,j에 대해 i != j 이면 arr[i] != arr[j] 입니다. divisor는 자연수이고  array는 길이 1 이상인 배열입니다.

 

(1) sort를 사용한 풀이

#include <string>
#include <vector>
#include <algorithm>

using namespace std;

vector<int> solution(vector<int> arr, int divisor) {
    vector<int> answer;
    
    for (int i = 0; i < arr.size(); i++) {
        if (arr[i] % divisor == 0) {
            answer.push_back(arr[i]);
        }
    }
    if (answer.empty()) {
        answer.push_back(-1);
    }
    else {
        sort(answer.begin(), answer.end());
    }
    
    return answer;
}

 

(2) <algorithm> 헤더의 copy_if 사용하기

주어진 배열이 있고 조건에 맞는 값만 배열에 가져오려고 한다면 copy_if를 사용할 수 있다,.

#include <vector>
#include <algorithm>

vector<int> solution(vector<int> arr, int divisor) {
	vector<int> answer;
    
    copy_if(arr.begin(), arr.end(), back_inserter(answer), [divisor](int n) {
    	return n % divisor == 0;
   	});
    
    if (answer.empty()) {
    	return {-1};
    }
    
    sort(answer.begin(), answer.end());
    
    return answer;
}

copy_if(시작점, 끝점, 도착점, 조건식); 형태로 사용할 수 있다.

이름 그대로 조건(if)에 맞는 것만 고라서 복사하라는 뜻의 C++ 내장 함수이다. 도착점은 조건식에 해당하는 값을 어디에 넣을 것인지 적는 곳이라고 보면 된다.

back_inserter는 헬퍼 함수로서, 벡터의 진짜 메서드인 push_back을 간접적으로 호출할 수 있게 해주는 외부함수이다.

그래서 answer 배열에 복사할 값이 생길 때마다 알아서 answer.push_back()을 실행해준다.

[divisor](int n) { return n % divisor == 0; } 는 람다 표현식이라고 부르는 함수로서 copy_if가 배열을 돌면서 원소를 하나씩 보고 결과가 참인 것만 복사한다. [divisor]를 써서 divisor라는 변수를 함수 안에서 사용할 수 있게 하고, n % divisor == 0 인지 확인한다.


*그 외*

[프로그래머스]

옷가게 할인 받기

#include <string>
#include <vector>

using namespace std;

int solution(int price) {
    int answer = 0;
    if (price >= 500000) {
        answer = 0.8 * price;
    }
    else if (price >= 300000) {
        answer = 0.9 * price;
    }
    else if (price >= 100000) {
        answer = 0.95 * price;
    }
    else
        answer = price;

    return answer;
}

 

아이스 아메리카노

#include <string>
#include <vector>

using namespace std;

vector<int> solution(int money) {
    vector<int> answer;
    int americano = 0;
    int leftmoney = 0;
    
    americano = money / 5500;
    leftmoney = money - americano * 5500;
    
    answer.push_back(americano);
    answer.push_back(leftmoney);
    
    return answer;
}

풀이를 개선해보면, return 안에 쓰는 게 한줄로 나와서 더욱 깔끔하다.

#include <vector>

using namespace std;

vector<int> solution(int money) {
	return vector<int> {money / 5500, money % 5500};
}

 

나이출력

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

int solution(int age) {
    int answer = 2023 - age;
    return answer;
}

 

배열 뒤집기

#include <string>
#include <vector>

using namespace std;

vector<int> solution(vector<int> num_list) {
    vector<int> answer;
    
    for (int i = num_list.size() - 1; i >= 0; i--) {
        answer.push_back(num_list[i]);
    }
    return answer;
}

C++의 알고리즘 헤더에 reverse라는 함수가 이미 내장되어 있으니까 활용하는 방법도 있다.

#include <algorithm>

vector<int> solution(vector<int> num_list) {
	reverse(num_list.begin(), num_list.end());
    return num_list;

 

뒤집힌 문자열

#include <string>
#include <vector>
#include <algorithm>

using namespace std;

string solution(string my_string) {
    string answer = "";
    for (int i = my_string.length() - 1; i >= 0; i--)
        answer.push_back(my_string[i]);
    return answer;
}

당연하겠지만 rbegin()도 사용할 수 있다. 연습하자!

#include <bits/stdc++.h>

using namespace std;

string solution(string my_string) {
    return string(my_string.rbegin(), my_string.rend());
}

 

직각삼각형 출력하기

#include <iostream>

using namespace std;

int main(void) {
    int n;
    cin >> n;
    
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= i; j++) {
            cout << "*";
        }
        cout << "\n";
    }
        
    return 0;
}
#include <iostream>
#include <string>
using namespace std;

int main(void) {
    int n;
    cin >> n;

    for(int i = 1; i <= n; ++i)
    {
        cout << string(i,'*') << endl;
    }
    return 0;
}

이렇게 string 라이브러리에서 제공하는 문자열 반복 기능을 사용하는 것이 좋다. 단 이때 작은따옴표만 사용 가능하니 주의.

 

짝수 홀수 개수

#include <string>
#include <vector>

using namespace std;

vector<int> solution(vector<int> num_list) {
    vector<int> answer;
    answer= {0, 0};
    
    for (int num : num_list) {
        if (num % 2 == 0) {
            answer[0]++;
        }
        else {
            answer[1]++;
        }
    }
    
    return answer;
}

약간 응용해보자면, 2로 나눴을 때 홀수는 나머지가 1이고, 짝수는 나머지가 0인 것을 이용해서 나머지 값을 그대로 인덱스에 사용하는 방법도 있다.

#include <string>
#include <vector>

using namespace std;

vector<int> solution(vector<int> num_list) {
	vector<int> answer(2, 0);
    for (int num : num_list) {
    	answer[num % 2]++;
    }
    return answer;
}

 

문자 반복 출력하기

#include <string>
#include <vector>

using namespace std;

string solution(string my_string, int n) {
    string answer = "";
    for (char c : my_string) {
        answer += string(n, c);
    }
    return answer;
}

 

[atanny]

(1)블루프린트와 C++ 연동 방식 이해 :

블루프린트의 주요 장점 : 빠른 반복 개발, 접근성, 실시간 개발

C++의 장점과 블루프린트의 장점 : C++은 복잡한 로직 구현에 효율적. 블루프린트는 빠른 프로토타이핑이 가능.

 

(2)Enhanced Input System의 구조와 차이점 분석

Enhanced Input System의 핵심적인 구성 요소: Input Action, Input Mapping Context, Input Modifier

Enhanced Input System의 주요 장점: 런타임에 동적으로 입력 매핑 변경 가능, 하나의 액션에 여러 키 쉽게 바인딩, 입력 값에 대한 전처리와 조건 적용 가능.

Input Modifier의 역할: 입력 값이 최종적으로 전달되기 전에 변환 또는 수정.

Input Mapping Context를 캐릭터에 적용하는 방법: Enhanced Input Local Player Subsystem -> Add Mapping Context함수로 추가.

 

[C++ 프로젝트]

 

(1) RPG 게임에서의 랜덤 요소 사용 사례 공부.

전투 시스템 (Combat System)

  • 데미지 난수 (Damage Variance): 고정된 수치가 아닌, 기준 공격력을 중심으로 일정 범위 내(예: 90%~110%)에서 실제 가해지는 피해량이 무작위로 결정
  • 치명타 판정 (Critical Hits): 공격 시 특정 확률에 따라 평소보다 높은 배율의 피해
  • 명중 및 회피 (Accuracy & Evasion): 캐릭터의 명중률과 적의 회피율 수치에 기반하여 공격이 적중할지 빗나갈지(Miss) 계산
  • 상태이상 확률 (Status Effect Procs): 중독, 기절, 빙결, 출혈 등의 상태이상이 적에게 부여될 확률
  • 선공 판정 (Initiative): 턴제 전투에서 주사위 굴림(난수)을 통해 적과 아군 중 누가 먼저 행동할지 순서를 결정
  • 스킬 발동 확률 (Passive/Trigger Skills): 피격 시 일정 확률로 반격하거나, 공격 시 일정 확률로 연속 공격이 나가는 등 조건부 패시브 스킬의 발동 여부

아이템 및 보상 (Loot & Rewards)

  • 아이템 드랍률 (Drop Rates): 몬스터 처치 시 특정 아이템(장비, 재료, 골드 등)이 떨어질 확률
  • 랜덤 옵션 및 접두사/접미사 (Random Affixes): 동일한 장비를 획득하더라도 부여되는 추가 능력치(힘, 민첩 등)나 특수 효과가 무작위로 결정
  • 아이템 등급 (Item Rarity): 상자를 열거나 몬스터를 잡았을 때 일반, 희귀, 영웅, 전설 중 어떤 등급의 아이템이 나올지 결정하는 시스템
  • 상자 내용물 (Chest Contents): 필드나 던전에 배치된 상자를 열었을 때 획득하는 골드의 양이나 소모품의 종류가 매번 달라짐
  • 가챠 및 뽑기 (Gacha/Loot Boxes): 재화를 소모하여 무작위 캐릭터, 펫, 장비 등을 획득하는 시스템

탐험 및 환경 (Exploration & Environment)

  • 랜덤 인카운터 (Random Encounters): 필드나 던전을 이동할 때 눈에 보이지 않는 적과 무작위 확률로 조우하여 전투 화면으로 넘어감
  • 절차적 맵 생성 (Procedural Generation): 던전에 입장할 때마다 방의 구조, 함정의 위치, 몬스터의 배치, 출구의 위치가 무작위로 조합되어 새롭게 생성
  • 날씨 및 시간 변화 (Weather & Time): 비, 눈, 안개 등의 날씨가 무작위로 발생하며, 이에 따라 특정 몬스터가 등장하거나 특정 속성 마법의 위력 변화
  • 돌발 이벤트 (Random Events): 길을 걷다가 강도를 만나거나, 도움을 요청하는 NPC를 마주치는 등 예측 불가능한 퀘스트나 상황이 발생

캐릭터 육성 및 시스템 (Character & System)

  • 초기 스탯 주사위 (Starting Stat Rolls): 캐릭터 생성 단계에서 주사위를 굴려 힘, 민첩, 지능 등의 기본 스탯 수치를 무작위로 부여
  • 레벨업 스탯 상승 (Level-up Variance): 레벨이 오를 때 고정된 수치가 오르는 것이 아니라, 각 스탯별 성장 확률에 따라 능력치가 오를지 말지 결정
  • 상점 리스트 갱신 (Merchant Inventory): 주기적으로 또는 특정 조건마다 상인이 판매하는 장비나 소모품의 종류와 품질이 무작위로 변경
  • 스킬 판정 (Skill Checks): 자물쇠 따기, 함정 해제, NPC 설득 등의 비전투 행동을 시도할 때 성공 여부가 확률적으로 결정

Text RPG 팀프로젝트(day 3) :

(1) 오전 스크럼: 칸반보드에서 할 일 나눠가지기(역할 분배), 명확한 역할 분배> 무기, 장비, 아이템 이름과 변수 설정 / 강화 로직

RPG 게임의 랜덤요소들: (+) 포션 사용 아이템 선택 창에서 인벤토리에서 포션만 골라서 출력하는 방법.

 

아이템 랜덤 획득(무기 or 장비 or 강화석 or 골드 강화석은 1~5개 랜덤 획득)

 

(2) 오전 작업:

-0. 기존에 작성했던 Item.h, Item.cpp 수정(Getter 함수와 Setter함수 사용, AddAttack함수 활용)

#include "Item.h"
#include "../Character.h"
#include <iostream>

void HealthPotion::use(Character* character) {

	if (count <= 0) {
		std::cout << "체력 포션이 없습니다." << std::endl;
		return;
	}

	count--;

	//변수를 선언 하고 getter함수 호출

	int currentHealth = character->GetHealth();
	int maxHealth = character->GetMaxHealth();

	//함수 수정(Entity.h의 AddHealth 함수 활용)
	if (currentHealth + healthRestore > maxHealth) {
		character->AddHealth(maxHealth - currentHealth);
	}
	else {
		character->AddHealth(healthRestore);
	}

	std::cout << "체력 회복 (현재 : " << character->GetHealth() << ")" << std::endl;
}

void AttackBoost::use(Character* character) {
	if (count <= 0) return;
	count--;

	//마찬가지로 Entity.h의 AddAttack 함수 활용
	character->AddAttack(attackIncrease);

	std::cout << "공격력 증가 (현재 : " << character->GetAttack() << ")" << std::endl;
}

 

 

 

-1. 플레이어 아이템 사용 → index를 이용해 인벤토리에서 사용 (나중에 전투 루프 만들어지면 여기다가 삽입해야 함)

아이템 사용을 위한 AddItem(), 메모리 누수 방지를 위한 소멸자 ~Character(), 아이템 이름 getter함수 std::string getName()

//character.cpp
//아이템 메모리 누수 방지
Character::~Character() {
	for (Item* item : inventory) {
		delete item;
	}
	inventory.clear( );
}

//인벤토리 기능 구현 위해서 추가
void Character::AddItem(Item* item) {
	inventory.push_back(item);
}

 

 

-2. 상점 클래스→ 아이템 구입과 판매 + 랜덤 박스 기능도 구현해보았음.

//Shop.h
#pragma once

class Character;

class Shop
{
public:
	//아이템 정보 출력, 아이템 선택 구매
	void ShowItems( ) const;
	void BuyItem(Character* player , int choice);

	//상점을 호출 인터페이스
	void OpenShop(Character* player);

};
//Shop.cpp
#include "Shop.h"
#include "../Character.h"
#include "Item.h"

#include <iostream>
#include <random>



void Shop::ShowItems( ) const
{
	std::cout << "\n======== [ 상 점 ] ========" << std::endl;
	std::cout << "1. 체력 포션 (50G)" << std::endl;
	std::cout << "2. 공격력 포션 (50G)" << std::endl;
	std::cout << "3. 랜덤 박스 (10G)" << std::endl;
	std::cout << "0. 상점 나가기" << std::endl;
	std::cout << "=========================" << std::endl;
}

void Shop::BuyItem(Character* player , int choice) {
	if ( choice == 1 ) {
		if ( player->GetGold( ) >= 50 ) {
			player->UseGold(50);
			player->AddItem(new HealthPotion("체력 포션" , 50 , 1));
			std::cout << "남은 골드: " << player->GetGold( ) << " G" << std::endl;
		}
		else {
			std::cout << "골드가 부족합니다." << std::endl;
		}
	}
	else if ( choice == 2 ) {
		if ( player->GetGold( ) >= 50 ) {
			player->UseGold(50);
			player->AddItem(new AttackBoost("공격력 포션" , 10 , 1));
			std::cout << "남은 골드: " << player->GetGold( ) << " G" << std::endl;
		}
		else {
			std::cout << "골드가 부족합니다." << std::endl;
		}
	}
	//랜덤박스. 체력 포션(10%), 공격력 포션(10%), 강화석(20%), 5G(20%), 꽝(40%)
	else if ( choice == 3 ) {
		if ( player->GetGold( ) >= 10 ) {
			player->UseGold(10);
			std::cout << "랜덤 박스 오픈!" << std::endl;
			std::random_device rd;
			std::mt19937 gen(rd( ));
			std::uniform_int_distribution<int> dis(1 , 100);
			int randNum = dis(gen);

			if ( randNum <= 10 ) {
				std::cout << "체력 포션 당첨!" << std::endl;
				player->AddItem(new HealthPotion("체력 포션" , 50 , 1));
			}
			else if ( randNum <= 20 ) {
				std::cout << "공격력 포션 당첨!" << std::endl;
				player->AddItem(new AttackBoost("공격력 포션" , 10 , 1));
			}
			else if ( randNum <= 40 ) {
				std::cout << "강화석 당첨!" << std::endl;
				player->AddItem(new EnhanceStone("강화석" , 1));
			}
			else if ( randNum <= 60 ) {
				std::cout << "5G 당첨!" << std::endl;
				player->AddGold(5);
			}
			else {
				std::cout << "ㅋ" << std::endl;
			}
		}
		else {
			std::cout << "골드가 없습니다. 돈을 벌어오세요." << std::endl;
		}
	}
	else if ( choice != 0 ) {
		std::cout << "숫자를 다시 입력하세요." << std::endl;
	}
}

//OpenShop 함수 -> 전투루프 끝나고 상점 방문 시 호출.
void Shop::OpenShop(Character* player) {
	int choice = -1;
	while ( choice != 0 ) {
		ShowItems( );
		std::cout << "번호를 입력하세요: ";
		std::cin >> choice;
	}

	if ( choice != 0 ) {
		BuyItem(player , choice);
	}
}

현재 Item 로직으로는 구매하였을 때 개수가 추가되는 걸 구현하기가 어려워서 다음과 같이 수정하였음

//Item.h에 다음과 같이 AddCount 함수를 선언하고
void AddCount(int amount) { count += amount; }
//Character.cpp
//...

//인벤토리 기능 구현 위해서 추가, AddItem 함수가 호출될 때 중복 검사
void Character::AddItem(Item* newItem) {
	for ( Item* item : inventory ) {
		if ( item->getName() == newItem->getName()) {
			item->AddCount(newItem->getCount());

			std::cout << newItem->getName( ) << "을(를) 획득했습니다." << std::endl;
			delete newItem;
			return;
		}
	}
	inventory.push_back(newItem);
	std::cout << newItem->getName( ) << "을(를) 획득했습니다." << std::endl;
}

AddItem을 위와 같이 수정했음.

 

//Item.h
//강화석
class EnhanceStone : public Item {
public:
	EnhanceStone(std::string name , int count = 1)
		: Item(name , count) {
	}
	void use(Character* character) override;
};

//Item.cpp
void EnhanceStone::use(Character* character) {
	if ( count <= 0 ) return;
	count--;

	std::cout << "무기 장착 시스템, 강화 시스템 추가 예정" << std::endl;
}

 

아이템 판매와 구매 기능을 구현하기 위해 다음과 같이 수정하였음.

//Character.h

	//Item* 해제 위한 소멸자, 인벤토리 기능
	~Character();
	void AddItem(Item* item);
	void ShowInventory( ) const;
	void SellItem(int index);
	void RemoveItem(int index);

	int GetInventorySize( ) const;

	Item* GetItem(int index) const;
//Character.cpp

void Character::ShowInventory( ) const {
	std::cout << "현재 소지 골드 : " << gold << " G" << std::endl;
	std::cout << "=== [ 인벤토리 ] ===" << std::endl;
	
	if ( inventory.empty( ) ) {
		std::cout << "(비어 있음)" << std::endl;
		return;
	}
	for ( int i = 0; i < inventory.size( ); ++i ) {
		std::cout << i + 1 << ". " << inventory[i]->getName( ) << " (" << inventory[i]->getCount( ) << "개) "
			<< "(" << inventory[i]->getSellPrice( ) << " G" << std::endl;
	}
}

void Character::SellItem(int index) {
	if ( index < 0 || index >= inventory.size( ) ) {
		std::cout << "잘못된 번호를 입력했습니다." << std::endl;
		return;
	}
	Item* item = inventory[index];
	int sellPrice = item->getSellPrice( );

	AddGold(sellPrice);
	item->AddCount(-1);

}

void Character::RemoveItem(int index) {
	if ( index < 0 || index >= inventory.size( ) ) return;
	delete inventory[index];
	inventory.erase(inventory.begin( ) + index);
}

int Character::GetInventorySize( ) const {
	return inventory.size( );
}

Item* Character::GetItem(int index) const {
	if ( index < 0 || index >= inventory.size( ) ) return nullptr;
	return inventory[index];
}
//Item.h

	//아이템 판매를 위한 가상 함수 추가
	virtual int getSellPrice( ) const { return 1; }
//Shop.h

#pragma once

class Character;

class Shop
{
public:
	//아이템 정보 출력, 아이템 선택 구매
	void ShowItems( ) const;
	void BuyItem(Character* player , int choice);

	//상점을 호출 인터페이스
	void OpenShop(Character* player);

};
#include "Shop.h"
#include "../Character.h"
#include "Item.h"
#include "ItemManager.h"
#include "../../../FrameWork.h"



void Shop::ShowItems( ) const
{
	std::cout << "\n======== [ 상 점 ] ========" << std::endl;
	std::cout << "1. 체력 포션 (50G)" << std::endl;
	std::cout << "2. 공격력 포션 (50G)" << std::endl;
	std::cout << "3. 랜덤 박스 (10G)" << std::endl;
	std::cout << "4. 아이템 판매" << std::endl;
	std::cout << "0. 상점 나가기" << std::endl;
	std::cout << "=========================" << std::endl;
}

//1~3 아이템 구입
void Shop::BuyItem(Character* player , int choice) {
	if ( choice == 1 ) {
		if ( player->GetGold( ) >= 50 ) {
			player->UseGold(50);
			player->AddItem(ItemManager::getInstance()->CreateItem(ItemType::HealthPotion, 1));
			std::cout << "남은 골드: " << player->GetGold( ) << " G" << std::endl;
		}
		else {
			std::cout << "골드가 부족합니다." << std::endl;
		}
	}
	else if ( choice == 2 ) {
		if ( player->GetGold( ) >= 50 ) {
			player->UseGold(50);
			player->AddItem(ItemManager::getInstance()->CreateItem(ItemType::AttackBoost, 1));
			std::cout << "남은 골드: " << player->GetGold( ) << " G" << std::endl;
		}
		else {
			std::cout << "골드가 부족합니다." << std::endl;
		}
	}
	//랜덤박스. 체력 포션(10%), 공격력 포션(10%), 강화석(20%), 5G(20%), 꽝(40%)
	else if ( choice == 3 ) {
		if ( player->GetGold( ) >= 10 ) {
			player->UseGold(10);
			std::cout << "랜덤 박스 오픈!" << std::endl;
			std::random_device rd;
			std::mt19937 gen(rd( ));
			std::uniform_int_distribution<int> dis(1 , 100);
			int randNum = dis(gen);

			if ( randNum <= 10 ) {
				std::cout << "체력 포션 당첨!" << std::endl;
				player->AddItem(ItemManager::getInstance()->CreateItem(ItemType::HealthPotion, 1));
			}
			else if ( randNum <= 20 ) {
				std::cout << "공격력 포션 당첨!" << std::endl;
				player->AddItem(ItemManager::getInstance()->CreateItem(ItemType::AttackBoost, 1));
			}
			else if ( randNum <= 40 ) {
				std::cout << "강화석 당첨!" << std::endl;
				player->AddItem(ItemManager::getInstance()->CreateItem(ItemType::EnhanceStone, 1));
			}
			else if ( randNum <= 60 ) {
				std::cout << "5G 당첨!" << std::endl;
				player->AddGold(5);
			}
			else {
				std::cout << "꽝" << std::endl;
			}
		}
		else {
			std::cout << "골드가 없습니다. 돈을 벌어오세요." << std::endl;
		}
	}
	else if ( choice == 4 ) {
		int sellChoice = -1;
		while ( sellChoice != 0 ) {
			player->ShowInventory( );
			std::cout << "판매할 아이템 번호를 입력하세요 :" << std::endl;
			std::cout << "0. 뒤로가기";
			std::cin >> sellChoice;

			if ( sellChoice > 0 && sellChoice <= player->GetInventorySize( ) ) {
				int index = sellChoice - 1;
				Item* soldItem = player->GetItem(index);

				if ( soldItem != nullptr ) {
					int price = soldItem->GetSellPrice( );
					player->AddGold(price);
					soldItem->AddCount(-1);
					if ( soldItem->GetCount( ) <= 0 ) {
						player->RemoveItem(index);
					}
				}
			}
			else if ( sellChoice != 0 ) {
				std::cout << "잘못된 번호입니다." << std::endl;
			}
		}
	}

	else if ( choice != 0 ) {
		std::cout << "숫자를 다시 입력하세요." << std::endl;
	}
}

//OpenShop 함수 -> 전투루프 끝나고 상점 방문 시 호출.
void Shop::OpenShop(Character* player) {
	int choice = -1;
	while ( choice != 0 ) {
		ShowItems( );
		std::cout << "번호를 입력하세요: ";
		std::cin >> choice;
	}

	if ( choice != 0 ) {
		BuyItem(player , choice);
	}
}

 

-3. ItemManager (확장성 만들어가면서 아이템 추가)

아이템을 enum class로 관리하기 위해 다음과 같이 추가했음. 현재 체력포션, 공격력 포션, 강화석, 무기, 장비 정도가 있음.

#pragma once

class Item;

enum class ItemType {
	HealthPotion,
	AttackBoost,
	EnhanceStone,
	Weapon,
	Armor
};

class ItemManager {
private:
	static ItemManager* instance;
	ItemManager( ) {}

public:
	static ItemManager* getInstance( );

	Item* CreateItem(ItemType type , int count = 1);
};
#include "ItemManager.h"
#include "Item.h"
#include "Equipment/Weapon.h"
#include "EquipMent/Armor.h"
#include "EquipMent/Equipment.h"

ItemManager* ItemManager::instance = nullptr;

ItemManager* ItemManager::getInstance( ) {
	if ( instance == nullptr ) {
		instance = new ItemManager( );
	}
	return instance;
}

Item* ItemManager::CreateItem(ItemType type , int count) {
	switch ( type ) {

	case ItemType::HealthPotion:
		return new HealthPotion("체력 포션" , 50 , count, 50);

	case ItemType::AttackBoost:
		return new AttackBoost("공격력 포션" , 10 , count, 50);

	case ItemType::EnhanceStone:
		return new EnhanceStone("강화석" , count, 20);

	case ItemType::Weapon:
		return new BaseSword("기본 검" , 20, count, 100);

	case ItemType::Armor:
		return new BaseArmor("기본 갑옷" , 50, count, 100);

	default:
		return nullptr;
	}
}

ItemManager에서는 Equipment.h 의 자식 클래스인 Weapon, Armor를 받아와서 BaseSword, BaseArmor 형태로 enum class 로 만들어 두었음.

 

//Item.h

public:
	//아이템 생성자
	Item(std::string itemName, int count, int price)
		: name(name), count(count), sellPrice(price) {
	}

이후 이제서야 전투 중 아이템 메뉴를 열어 사용가능한 아이템을 사용할 수 있는 로직을 작성함.

//Item.h
	//사용 가능한 아이템만 전투 중 인벤토리에 출력하기 위해 가상함수 추가
	virtual bool isUsableInBattle( ) const { return false; }
    
//...

class HealthPotion : public Item {
//...

bool isUsableInBattle() const override {return true;}
bool Character::UseItemInBattle( ) {
	vector<int> usableItems;
	std::cout << "==== [ 사용 가능한 아이템 ] ====" << std::endl;

	int displayIndex = 1;
	for ( int i = 0; i < inventory.size( ); ++i ) {
		if ( inventory[i]->isUsableInBattle( ) ) {
			cout << displayIndex << ". " << inventory[i]->GetName( ) << " (" << inventory[i]->GetCount( ) << "개)" << std::endl;
		
			usableItems.push_back(i);
			displayIndex++;
		}
	}
	if ( usableItems.empty( ) ) {
		cout << "(비어 있음)" << endl;
		return false;
	}

	std::cout << "0. 뒤로 가기" << std::endl;
	std::cout << "사용할 아이템 번호를 입력하세요: ";
	int itemChoice;
	cin >> itemChoice;

	if ( itemChoice == 0 ) {
		return false;
	}

	if ( itemChoice > 0 && itemChoice < displayIndex ) {
		int targetInventoryIndex = usableItems[itemChoice - 1];
		Item* selectedItem = inventory[targetInventoryIndex];

		selectedItem->use(this);

		if ( selectedItem->GetCount( ) <= 0 ) {
			RemoveItem(targetInventoryIndex);
		}
		return true;
	}

	std::cout << "번호를 다시 입력하세요." << std::endl;
	return false;
}

 

 

 

(4) 저녁 스크럼:

팀원들과 함께 오늘 한 작업 내용을 공유하고 점검. 컴파일 에러 문제, 변수명 통합, 헤더 파일 정리 등을 했음.

현재 몬스터 드랍테이블이 미완성 된 것을 확인 : 아직 아이템이 존재하지 않아서 강화와 인벤토리에 추가 진행이 어려움을 파악했음. 다음 날 오전 스크럼때 이를 다시 확인하고 이번에는 최대한 작은 단위로 분업해서 프로젝트를 진행하기로 이야기가 되었음.


(5) 트러블 슈팅/해결 및 개선: 역할 분담,

역할 분담을 최대한 세분화해서 업무의 모호함을 제거하기. (아이템이면 아이템 사용, 아이템 생성, 아이템 드랍, 아이템 종류 등, 세부적으로 구분해놓고 업무분담하기)

 

+ 문서를 통한 커뮤니케이션(진행 상황 확인, 문제상황 빠른 공유)

코딩을 잘하고 그런 것도 중요하지만 결국 팀 단위로 프로젝트를 계속 진행한다는 것을 감안하면 무엇보다도 소통에 문제가 없고 원활하게 소통이 가능해야 할 것 같다.

 

+코드가 중복작성이 됨. 기존 Auto로 진행되었던 전투가 Manual로 변경되었는데, 두 전투 모드가 동시에 존재해서 충돌이 발생했음. --> 작성 시에 미리 소통하면서 진행하고, 작업하기 전에 새로운 버전을 dev 브랜치에서 가져오는 걸 미리 약속해놓아야 할듯.

 

+넘길 때 컴파일 에러가 나지 않도록 테스트 하면서 진행해야함!

 

 

 

 

'TIL' 카테고리의 다른 글

05.29 TIL (ch.2 팀프로젝트 day6)  (0) 2026.05.29
05.28 TIL (ch.2 팀프로젝트 day5)  (0) 2026.05.28
05.27 TIL (ch.2 팀프로젝트 day4)  (0) 2026.05.27
05.22 TIL (ch.2 팀프로젝트 day2)  (0) 2026.05.22
05.21 TIL (ch.2 팀프로젝트 day1)  (0) 2026.05.21