마인크래프트 스타일 제작 시스템


개요

이 프로젝트는 기본적인 아이템 인벤토리마인크래프트 스타일 제작 시스템을 구현을 다루고 있습니다. 유저는 아이템을 제작대에 아이템을 조합하여 새로운 아이템을 만들 수 있습니다. 이 시스템은 쉬운 확장성을 고려하여 설계되었기 때문에, 개발자가 새로운 레시피를 손쉽게 추가할 수 있습니다.

저장소 보기
시연 보기


아이템 제작 시연

아래 영상에서는 시스템에 미리 정의된 8가지 레시피를 사용하여 아이템을 제작하는 과정을 보여줍니다.


클래스 목록 및 설명

Item 관련 클래스

  • ItemInfo class:
    • 아이템의 아이콘, 설명, 그리고 eItemType을 저장하는 ScriptableObject로, 아이템의 모든 객체가 공유하는 정보를 담고 있습니다.
    • eItemType enum:
      • 각 아이템을 식별하기 위한 고유 ID를 정의하며, 제작 알고리즘에서 아이템 구분을 하는데 사용됩니다.
  • ItemInstance class:
    • 인벤토리 UI의 ItemSlot을 나타냅니다. ItemInfo와 수량을 추적하며, 아이콘과 수량 표시를 갱신하고 마우스를 올리면 아이템 상세정보를 보여줍니다.

ItemSlot 관련 클래스

  • ItemSlot class:
    • 아이템의 들기, 놓기, 바꾸기, 쌓기와 같은 상호작용을 관리합니다.
    • 인벤토리제작 시스템에서 공통으로 사용하는 ItemSlot의 기반 클래스입니다.
  • CraftingInputSlot class:
    • ItemSlot상속하며 제작 재료 칸의 아이템 배치를 처리합니다.
    • 재료 아이템 상호작용 이후, 제작 시스템을 갱신합니다.
  • CraftingOutputSlot class:
    • ItemSlot상속하며 제작 생성 칸의 아이템 배치를 처리합니다.
    • 제작 생성 칸에 아이템을 생성하고, 가져가면 제작 재료 칸의 재료를 갱신합니다.

Crafting 관련 클래스

  • Recipe class:
    • 필요한 제작 재료생성되는 아이템제작 공식을 저장하는 ScriptableObject입니다.
  • Crafting class:
    • 전반적인 제작 시스템의 동작을 관리합니다.
    • 제작 재료 칸의 아이템이 레시피와 일치하는지 확인하고, 일치할 경우 제작 아이템을 생성합니다.

프로젝트 주요 특징

1. 재정의 가능한 아이템 칸(ItemSlot) 상호작용

  • 재사용 가능한 이벤트 및 조건 로직.
  • ItemSlot 상속을 통한 손쉬운 확장성.

작동 원리

ItemSlot 클래스는 아이템 칸 상호작용을 위한 유연하고 모듈화된 기반을 제공합니다.

public class ItemSlot : MonoBehaviour, IPointerClickHandler
{
	public virtual void OnPointerClick(PointerEventData eventData)
	{
		if (eventData.button == PointerEventData.InputButton.Left)
		{
			if (ItemOnSlotAndCursor())
			{
				if (!SlotAndCursorSameItem())
					SwapItem();
				else 
					StackAllItemCursorToSlot();
			}
			else if (ItemOnSlotAndNoCursor())
			{
				PickItem();
			}
			else if (ItemOnNoSlotAndCursor())
			{
				PlaceItem();
			}
		}
	    else if (eventData.button == PointerEventData.InputButton.Right)
	    {
			if (ItemOnSlotAndCursor())
			{
				if (!SlotAndCursorSameItem())
					SwapItem();
				else
					StackOneItemCursorToSlot();
			}
			else if (ItemOnSlotAndNoCursor())
			{
				PickHalfOfItem();
			}
			else if (ItemOnNoSlotAndCursor())
			{
				DropOneItemCursorToSlot();
			}
		}
	}
}

  • virtual void OnPointerClick() 함수는 아이템 칸이 클릭에 어떻게 반응할지를 결정합니다.
  • 이 함수 내부에서는 미리 만들어둔 이벤트조건 함수들블록처럼 조합하여 원하는 동작을 만들 수 있습니다.
  • 이 방식 덕분에 핵심 로직을 다시 작성하지 않고도 복잡한 상호작용을 손쉽게 정의 할 수 있습니다.

CraftingOutputSlot 같은 자식 클래스는 아래에 정의된 가상 함수를 간단히 오버라이드하여 원하는 동작을 재정의 할 수 있습니다.

public class CraftingOutputSlot : ItemSlot
{
	public override void OnPointerClick(PointerEventData eventData)
	{
		if (SlotAndCursor())
		{
			if (SlotAndCursorSameItem())
			{
				StackAllItemSlotToCursor();
				UpdateInputPanel();
			}
		}
		else if (SlotAndNoCursor())
		{
			PickItem();
			UpdateInputPanel();
		}
	}
}
결과: 아이템 칸 유형별로 쉽게 확장, 디버그, 맞춤 설정할 수 있는 깔끔하고 재사용 가능한 동작 구조를 얻을 수 있습니다.


2. 쉬운 레시피(Recipe) 설정

  • ScriptableObject를 통한 새로운 레시피 추가.
  • 직관적인 시각화 설정을 위한 RecipeEditor.

작동 원리

RecipeScriptableObject로, RecipeEditor의 드래그-앤-드롭 인터페이스를 통해 손쉽게 편집할 수 있습니다.

결과: 위의 RecipeEditor 사용 전후 예시에서 보듯이, Recipe손쉽게 설정할 수 있어, 제작 레시피의 생성과 관리를 빠르고 실수 없이 할 수 있고, 개발자와 디자이너 모두가 간편하고 쉽게 활용할 수 있습니다.


3. 유연한 제작(Crafting) 알고리즘

  • 어떤 사이즈의 n x n 제작 격자도 대응.
  • 모양 기반 레시피 판별 방식.

작동 원리

제작 알고리즘은 아주 직관적입니다:

  1. 제작 재료 칸에서 eItemType 고유 ID행 단위로 하나의 문자열로 결합시킵니다.
    • <Sample 3>과 같이 아이템이 여러 행에 연속적으로 배치된 경우, 행 사이에 추가 문자를 삽입하여 구조를 유지합니다.
  2. 생성된 문자열에서 외각의 “빈 슬롯 아이템 타입” 문자제거합니다.
  3. 모양만 동일하면 아이템 배치가 어느 위치에 있어도 정확히 일치하는 것을 확인할 수 있습니다.
  4. 마지막으로, 만들어진 문자열을 정의된 모든 레시피 문자열과 비교하여 일치하는지를 확인합니다.

맺는 말

이 제작 시스템은 유연성, 확장성, 그리고 간편한 레시피 구현 기능을 제공합니다. 직관적인 설계 덕분에 통합과 사용자 정의가 쉽고, 개발자뿐만 아니라 디자인 팀도 복잡한 코드 없이 레시피를 효율적으로 관리할 수 있습니다.