전체 코드 : https://github.com/HyangRim/DirectX11-Engine-Client
GitHub - HyangRim/DirectX11-Engine-Client
Contribute to HyangRim/DirectX11-Engine-Client development by creating an account on GitHub.
github.com
아이템 시스템과 동적 제작(Crafting) 시스템
핵심 구현 목표
- 아이템 등급별 분류와 관리
- 5단계 등급 시스템 ( Common → Legendary )
- 등급별 제작 시간 차등 적용
- 타입별 아이템 분류 및 관리
- 동적 제작 가능성 검사 알고리즘
- 실시간 재료 보유량 체크
- 복합 레시피 체인 분석
- 최적화된 제작 순서 결정
1. 시스템 아키텍쳐
1.1 핵심 설계 철학
- 확장 가능한 설계 : 새로운 아이템 추가가 쉽게
- UI와 로직의 분리
- 실시간 상태 기반 : 게임플레이와 자연스러운 연동
// 아이템 시스템의 전체 구조
Item (기본 클래스)
├── EquipableItem (장비 아이템)
└── IngredientItem (재료 아이템)
ItemManager (아이템 관리)
├── 아이템 생성 및 관리
├── 리소스 로딩
└── 아이템 검색
Recipe System
├── Recipe (개별 레시피)
├── RecipeManager (레시피 관리)
└── 실시간 제작 가능 여부 검사
2. Strategy Pattern 기반 아이템 시스템
2.1 Strategy Pattern 이란?

전략 패턴은 객체들이 할 수 있는 행위 각각에 대해 전략 클래스를 생성하고, 유사한 행위들을 캡슐화하는 인터페이스를 정의.
class Item {
public:
// 순수 가상 함수로 타입별 다른 동작 보장
virtual bool Use() = 0;
virtual bool CanUse() const = 0;
virtual Item* Clone() const = 0;
protected:
wstring m_name;
ITEMTYPE m_itemType;
ITEMGRADE m_itemGrade;
int32 m_itemID;
};
class EquipableItem : public Item {
public:
bool Use() override;
const ItemStatus& GetStatus() const { return m_status; }
void SetEquipType(EquipmentType _type) { m_equipType = _type; }
private:
EquipmentType m_equipType;
ItemStatus m_status; // 공격력, 방어력, HP 등
};
class IngredientItem : public Item {
public:
bool Use() override; // 재료는 직접 사용 불가
bool CanUse() const override { return false; }
};
특징
- 각 아이템 타입마다 완전히 다른 동작을 하면서도 일관된 인터페이스를 제공한다.
3. Factory Pattern으로 아이템 생성 관리
아이템 생성 로직을 중앙화하여 확장성과 유지보수성을 향상
class ItemManager {
public:
void CreatItems() {
for (int i = 0; i < itemIconID.size(); i++) {
if (itemType[i] == ITEMTYPE::INGREDIENTS) {
shared_ptr<IngredientItem> ingredientItem = make_shared<IngredientItem>();
ingredientItem->SetItemID(itemIconID[i]);
ingredientItem->SetName(itemIconTag[i]);
ingredientItem->SetItemType(itemType[i]);
ingredientItem->SetItemGrade(itemGrade[i]);
m_itemsContainerByName[itemIconTag[i]] = ingredientItem;
m_itemsContainerByID[itemIconID[i]] = ingredientItem;
}
else if (itemType[i] == ITEMTYPE::EQUIPABLE) {
shared_ptr<EquipableItem> equipableItem = make_shared<EquipableItem>();
// 장비 전용 설정
equipableItem->SetEquipType(equipableItemType[i]);
equipableItem->SetStatus(equipableItemStatus[i]);
m_itemsContainerByName[itemIconTag[i]] = equipableItem;
m_itemsContainerByID[itemIconID[i]] = equipableItem;
}
}
}
// 이름과 ID 두 방식으로 검색 가능
shared_ptr<Item> GetItem(const wstring& name);
shared_ptr<Item> GetItem(int32 ID);
private:
unordered_map<wstring, shared_ptr<Item>> m_itemsContainerByName;
unordered_map<int32, shared_ptr<Item>> m_itemsContainerByID;
};
4. 아이템 등급별 분류 시스템
4.1 아이템 등급 정의
// 아이템 등급 시스템
enum class ITEMGRADE
{
COMMON = 0, // 일반 (흰색)
UNCOMMON, // 고급 (초록색)
RARE, // 희귀 (파란색)
EPIC, // 영웅 (보라색)
LEGENDARY, // 전설 (주황색)
UNIQUE // 유니크 (빨간색)
};
// 아이템 타입 분류
enum class ITEMTYPE
{
CONSUMABLE = 0, // 소모품
EQUIPABLE, // 장착 가능
MATERIAL, // 제작 재료
ETC // 기타
};

아이템 등급에 따라 배경 색이 다름
4.2 등급별 제작 시간 차등화
등급이 높을수록 제작 시간이 증가하여 게임 밸런스를 유지
// BiancaCraftState.cpp - 등급별 제작 시간 설정
void BiancaCraftState::SetCraftTimeByGrade(ITEMGRADE grade)
{
m_craftingItemGrade = grade;
switch (grade) {
case ITEMGRADE::COMMON: m_craftingTime = 1.0f; break;
case ITEMGRADE::UNCOMMON: m_craftingTime = 3.0f; break;
case ITEMGRADE::RARE: m_craftingTime = 5.0f; break;
case ITEMGRADE::EPIC: m_craftingTime = 7.0f; break;
case ITEMGRADE::LEGENDARY: m_craftingTime = 9.0f; break;
default: m_craftingTime = 11.0f; break;
}
}
동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.
- 제작하는 등급에 따라 제작 시간이 달라짐
- Z키와 아이템을 누르면 제작 가능
5. 레시피 관리 시스템
5.1 레시피 구조 설계
// Recipe.h - 레시피 기본 구조
struct RecipeIngredient
{
wstring itemID;
int requiredCount;
RecipeIngredient(const wstring& id, int count = 1)
: itemID(id), requiredCount(count) {}
};
class Recipe
{
private:
wstring m_resultItemID; // 결과 아이템
vector<RecipeIngredient> m_ingredients; // 필요 재료들
public:
bool CanCraft(const vector<shared_ptr<ItemSlot>>& slots) const;
bool ExecuteCraftFromSlots(vector<shared_ptr<ItemSlot>>& slots);
};
5.2 복합 레시피 체인 구현
실제 게임에서 사용되는 비질란테(헬멧) 제작 체인:
// RecipeManager.cpp - 3단계 제작 체인 예시
void RecipeManager::RegisterBasicRecipes()
{
auto itemManager = ItemManager::GetInstance();
// 1단계: 안전모 = 자전거 헬멧 + 돌멩이
RegisterRecipe(
make_shared<Recipe>(
itemManager->GetItem(L"안전모")->GetItemID(),
RecipeIngredient(itemManager->GetItem(L"자전거 헬멧")->GetItemID()),
RecipeIngredient(itemManager->GetItem(L"돌멩이")->GetItemID())
)
);
// 2단계: 소방 헬멧 = 안전모 + 흑연
RegisterRecipe(
make_shared<Recipe>(
itemManager->GetItem(L"소방 헬멧")->GetItemID(),
RecipeIngredient(itemManager->GetItem(L"안전모")->GetItemID()),
RecipeIngredient(itemManager->GetItem(L"흑연")->GetItemID())
)
);
// 3단계: 비질란테 = 소방 헬멧 + 화약 (최종 EPIC 등급)
RegisterRecipe(
make_shared<Recipe>(
itemManager->GetItem(L"비질란테")->GetItemID(),
RecipeIngredient(itemManager->GetItem(L"소방 헬멧")->GetItemID()),
RecipeIngredient(itemManager->GetItem(L"화약")->GetItemID())
)
);
}
6. 동적 제작 가능성 검사 알고리즘
6.1 실시간 제작 가능성 검사
// InventoryManager.cpp - 핵심 알고리즘
vector<shared_ptr<Recipe>> InventoryManager::GetAvailableRecipes() const
{
vector<shared_ptr<Recipe>> availableRecipes;
auto allRecipes = RecipeManager::GetInstance()->GetAllRecipes();
// 모든 레시피에 대해 제작 가능성 검사
for (const auto& recipe : allRecipes)
{
if (recipe->CanCraft(m_inventorySlots)) // 동적 검사
{
availableRecipes.push_back(recipe);
}
}
// 우선순위 정렬 (높은 등급부터)
sort(availableRecipes.begin(), availableRecipes.end(),
[](const shared_ptr<Recipe>& a, const shared_ptr<Recipe>& b) {
auto itemA = ItemManager::GetInstance()->GetItem(a->GetResultItemID());
auto itemB = ItemManager::GetInstance()->GetItem(b->GetResultItemID());
return static_cast<int>(itemA->GetItemGrade()) >
static_cast<int>(itemB->GetItemGrade());
});
return availableRecipes;
}
6.2 재료 보유량 검사 로직
// Recipe.cpp - 세밀한 재료 체크
bool Recipe::CanCraft(const vector<shared_ptr<ItemSlot>>& slots) const
{
// 각 필요 재료별로 검사
for (const auto& ingredient : m_ingredients)
{
int foundCount = 0;
// 인벤토리 전체 스캔
for (const auto& slot : slots)
{
if (slot && !slot->IsEmpty())
{
auto item = slot->GetItem();
if (item && item->GetItemID() == ingredient.itemID)
{
foundCount += slot->GetCount();
// 필요량 충족 시 조기 종료 (최적화)
if (foundCount >= ingredient.requiredCount)
break;
}
}
}
// 하나라도 부족하면 제작 불가
if (foundCount < ingredient.requiredCount)
return false;
}
return true; // 모든 재료 보유량 충족
}
7. 실시간 제작 시스템 통합
7.1 게임 루프와의 연동
// LumiaIsland.cpp - 제작 시스템 통합
void LumiaIsland::Start()
{
// 제작 시도 이벤트 등록
m_player->GetPlayerStateMachine()->OnTryCraft.Push([this](bool& success) {
auto inventoryMgr = InventoryManager::GetInstance();
auto recipes = inventoryMgr->GetAvailableRecipes();
success = !recipes.empty(); // 제작 가능한 레시피 존재 여부
if (success)
{
// 제작 준비 작업
auto resultItem = ItemManager::GetInstance()->GetItem(recipes[0]->GetResultItemID());
if (resultItem)
{
// 등급별 제작 시간 동적 적용
ITEMGRADE itemGrade = resultItem->GetItemGrade();
float craftTime = GetCraftTimeByGrade(itemGrade);
// UI 업데이트
m_uiManager->GetCraftGageUI()->SetVisible(true);
m_uiManager->GetCraftGageUI()->SetItem(resultItem);
}
}
});
}
7.2 제작 완료 상태 체크
// PlayerStateMachine.cpp - 상태 기반 제작 관리
void PlayerStateMachine::CheckCraftCompletion()
{
if (IsInState(PlayerStateType::Craft))
{
bool craftCompleted = false;
OnCraftCompleted(craftCompleted); // Client에게 완료 여부 확인
if (craftCompleted)
{
cout << "제작 완료 감지 - Wait 상태로 전환" << endl;
RequestStateChange(PlayerStateType::Wait);
if (m_animationStateMachine)
{
m_animationStateMachine->RequestStateChange(AnimationStateType::Wait);
}
}
}
}
8. 성능 최적화 및 확장성
8.1 메모리 효율성
// ItemManager.cpp - 싱글톤 패턴으로 메모리 절약
class ItemManager
{
private:
static ItemManager* m_instance;
unordered_map<wstring, shared_ptr<Item>> m_items; // 아이템 풀링
ItemManager() = default;
public:
static ItemManager* GetInstance()
{
if (m_instance == nullptr)
m_instance = new ItemManager();
return m_instance;
}
shared_ptr<Item> GetItem(const wstring& itemID)
{
auto it = m_items.find(itemID);
return (it != m_items.end()) ? it->second : nullptr;
}
};
확장 가능한 레시피 시스템
현재 구현된 제작 체인들
- 비잘란테 ( 3단계 헬멧 )
- 운명의 수레바퀴 ( 3단계 무기 )
- 타키온 브레이스 ( 3단계 신발 )
- 어사의 ( 3단계 의상 )
결론
시스템의 장점
- 동적 가능성 검사 : 실시간으로 제작 가능한 아이템만 표시
- 등급별 차등화 : 높은 등급일수록 더 오래 걸리는 자연스러운 밸런스
- 복합 체인 지원 : 3단계 이상의 복잡한 제작 과정 구현
- 확장성 : 새로운 레시피 추가가 간단함
향후 개선 방향
- 대량의 레시피 : 레시피가 지금보다 더 많아질 경우 XML 파일이나 JSON파일의 형태로 저장한 뒤 불러오기
- 아이템의 스택화 : 현재 소모형 아이템과 재료아이템들의 스택화는 미구현되어 있음
- 제작창 : 현재는 단순히 인벤토리 위에 제작 가능한 레시피를 보여주지만 특정 키를 누르면 제작 UI를 출력하는것도 고려해볼 수 있음
'DirectX11 > Eternal Return 모작' 카테고리의 다른 글
| [DirectX 11 Eternal Return 모작] 11. 스킬 시스템 (0) | 2025.09.03 |
|---|---|
| [DirectX 11 Eternal Return 모작] 10. 인벤토리와 장비 시스템 (0) | 2025.09.03 |
| [DirectX 11 Eternal Return 모작] 8. State Machine & Delegate (0) | 2025.09.03 |
| [DirectX 11 Eternal Return 모작] 7. ResourceManager (0) | 2025.09.03 |
| [DirectX 11 Eternal Return 모작] 6. Scene (0) | 2025.09.02 |