Hello, I’m implementing a crafting system and was wondering if this is a good way to do so. It uses a fair bit of dictionaries and wasn’t sure if there was a more optimized approach. Honestly, if anywhere needs improvement or I’m using something incorrectly, please let me know.
I have two scriptable objects, one for all items in the game and another for recipes for making said item. This could probably be combined into one, but I felt it was a bit cluttered and don’t believe all items will be craftable further down the road.
Inventory items:
public class InventoryItemData : ScriptableObject
{
public int ID = -1;
public int MaxStackSize;
public int GoldValue;
[TextArea(4, 4)]
public string Description;
public string DisplayName;
public Sprite Icon;
public GameObject ItemPrefab;
public CraftingRecipe RequiredItems;
}
Recipes:
[Serializable]
public struct RecipeIngredients
{
public InventoryItemData RecipeItemNeeded;
public int RecipeItemAmountNeeded;
}
[CreateAssetMenu(menuName = "Crafting System/Crafting Recipes")]
public class CraftingRecipe : ScriptableObject, IEnumerable
{
public string ItemName;
public InventoryItemData ItemToMake;
public List<RecipeIngredients> CraftingIngredients = new List<RecipeIngredients>();
public Dictionary<InventoryItemData, List<RecipeIngredients>> CraftingItemRecipe = new Dictionary<InventoryItemData, List<RecipeIngredients>>();
private void OnEnable()
{
CraftingItemRecipe.Add(ItemToMake, CraftingIngredients);
}
public List<RecipeIngredients> GetIngredientsList(InventoryItemData item)
{
return CraftingItemRecipe[item];
}
}
Finally, where I check if the player’s inventory has the required ingredients:
public bool TryBuild(InventoryItemData itemToBuild)
{
// Get the ingredients needed for the selected item.
var ingredientsNeeded = itemToBuild.RequiredItems.GetIngredientsList(itemToBuild);
// Get all the items in the player's inventory.
var inventoryIngredients = playerInventory.GetAllItemsHeld();
// Declare a dictionary of items and bools to determine which the player has and has enough of.
var ingredientsInPlayerInventory = new Dictionary<InventoryItemData, bool>();
// For every ingredient in the item we're trying to build.
foreach(var itemNeeded in ingredientsNeeded)
{
Debug.Log("Item needed from recipe: " + itemNeeded.RecipeItemNeeded + " Amount needed from recipe: " + itemNeeded.RecipeItemAmountNeeded);
// For every item in the player's inventory that's on the ingredients list.
if(!inventoryIngredients.ContainsKey(itemNeeded.RecipeItemNeeded))
{
Debug.Log("Boo, item NOT in player inventory.");
ingredientsInPlayerInventory.TryAdd(itemNeeded.RecipeItemNeeded, false);
}
else
{
Debug.Log("Woo, item IS in player inventory.");
ingredientsInPlayerInventory.TryAdd(itemNeeded.RecipeItemNeeded, true);
}
// If player has greater amount than required.
if(inventoryIngredients.ContainsKey(itemNeeded.RecipeItemNeeded) && (inventoryIngredients[itemNeeded.RecipeItemNeeded] >= itemNeeded.RecipeItemAmountNeeded))
{
Debug.Log("Amount left over in player's inventory: " );
Debug.Log(inventoryIngredients[itemNeeded.RecipeItemNeeded] - itemNeeded.RecipeItemAmountNeeded);
Debug.Log("Player has enough " + itemNeeded.RecipeItemNeeded + " in their inventory.");
}
else
{
// Else, player lacks ingredients.
Debug.Log("Player does not have enough " + itemNeeded.RecipeItemNeeded + " in their inventory.");
ingredientsInPlayerInventory.TryAdd(itemNeeded.RecipeItemNeeded, false);
}
}
// If our Dictionary doesn't contain a false, we can craft the item.
if(!ingredientsInPlayerInventory.ContainsValue(false))
{
playerInventory.AddToInventory(itemToBuild, 1);
return true;
}
return false;
}
Feedback is greatly appreciated!