Goal

Build a Minecraft-style crafting and drag-and-drop inventory that’s easy for designers to extend. Recipes and items are ScriptableObjects, items are draggable, stackable, and splittable, and crafting consumes inputs and produces outputs automatically.

System Overview

The system combines a UI-driven inventory with a data-driven crafting grid:

  • Items are UI prefabs that implement Unity’s drag interfaces to move between slots.

  • Slots manage stacking, splitting, and drop logic.

  • Recipes are ScriptableObjects defining ingredients (names), consume amount, output item, and output amount.

  • The Crafting Inventory watches the grid, matches recipes (order-agnostic), validates counts, spawns the output, and deducts inputs.

Architecture

Data Layer (ScriptableObjects):

  • ScriptableItem – icon, name, description, stackable flag.

  • ScriptableRecipe – ingredient list (names), consume amount, output item & amount.

  • UI/Runtime Layer (MonoBehaviours):

    • Item – draggable UI element; tracks count and icon; handles begin/drag/end with raycastTarget toggling and parent swapping.

    • ItemSlot – owns an Item; accepts drops, merges stacks, splits on right-click, exposes output-slot mode.

    • Inventory – manages slots and split behavior via an event; finds empty slots and redistributes counts.

    • CraftingInventory – scans crafting slots each frame, matches recipes ignoring order, checks required amounts, creates the output, and decrements inputs.

Component Breakdown

Item (MonoBehaviour)

  • Implements IBeginDragHandler, IDragHandler, IEndDragHandler.

  • Temporarily re-parents to the root during drag and disables raycasts for smooth UI interaction.

  • Tracks and displays stack count (TMP) and icon.

ItemSlot (MonoBehaviour)

  • Handles OnDrop: moves item if empty, otherwise merges stacks when same item & stackable.

  • Right-click split (emits SplitItemEvent), tooltip name/description on hover.

  • Optional output slot flag to prevent accidental drops/merges.

Inventory (MonoBehaviour)

  • Subscribes to SplitItemEvent: finds an empty slot and splits the stack (ceiling/remaining).

  • Maintains a cached list of slots and refreshes after changes.

ScriptableItem / ScriptableRecipe (SO)

  • Items: data-only assets for icons, names, stackable behavior.

  • Recipes: ingredient names list + counts; supports one-to-many outputs and configurable consumption.

Result

  • Designer-friendly: new items/recipes added by creating ScriptableObjects—no code changes.

  • Smooth UX: intuitive drag-and-drop, stack merging, and right-click split.

  • Robust crafting: order-independent recipe matching, input validation, and automatic consumption/output.

Key Takeaways

  • Data-Driven Design – ScriptableObjects made content creation fast and safe for designers.

  • UI Interaction Patterns – Clean drag/parenting/raycast control yields reliable, snappy inventory behavior.

  • Stack Logic & Splitting – Centralizing split/merge rules in ItemSlot/Inventory keeps the system consistent.

  • Order-Agnostic Crafting – Matching by ingredient set (plus count checks) simplifies designer workflows.

  • Extensibility – The prefab + SO approach makes it straightforward to add features like shift-click move, tool durability, or shaped recipes later.

What I Learned

  • Separation of Core Logic: Designed the crafting system so that core inventory mechanics remain unchanged, allowing designers to easily add or modify recipes without altering the base code.

  • ScriptableObject Usage: Leveraged ScriptableObjects for both items and recipes, enabling centralized data management and simplifying the creation of new items or crafting recipes.

  • Interactive UI & User Feedback: Implemented drag-and-drop, stack splitting, and stacking mechanics to provide intuitive item manipulation and inventory organization.

  • Crafting Validation Logic: Learned to efficiently verify recipe ingredients and quantities against player inventory before crafting, ensuring balanced and bug-free crafting mechanics.

  • Dynamic Inventory Updates: Developed a refresh system to keep inventory UI and internal data synchronized in real time, even after crafting or item splitting.

CraftingInventory (MonoBehaviour)

  • Collects current ingredient names from occupied crafting slots.

  • Order-agnostic match: recipe.RecipeIngredients.All(SlotsIngredients.Contains) plus count parity.

  • Validates ConsumeAmount, then:

    • Spawns output in the output slot with OutputAmount.

    • Decrements each input slot by ConsumeAmount.

  • Resets internal lists to keep state in sync.