I want to make a check to see if the player has the required ores (single ores are easy) needed to create an alloy without a dedicated section for each alloy.
My question is how can I implement this? (In terms of structure)
Thats the best solution I can think of, but i always think there might be a better solution that the one I thought off.
Correct. I would like to check if the inventory has the required ores for an alloy.
Its not to much of a problem with how to code it but how to do it structure wise.
Im wondering if there maybe a better solution before implementing the 2 variablesā¦
If I understand you correctly (which Iām not sure), I would do something like this:
create recipes in HashSet -s, like Tin, Copper
when the user clicking on metals and they selected two already would iterate over each recipe and check if the HashSet is equal to the HashSet you create out of the button clicks
if the recipe is found ā create the alloy
if the recipe isnāt found, message that it is not a valid compositon
basically what Iām saying is this system is just a filtered inventory of the player with the converting logic on it, so would handle it like that (on this way you donāt have to treat it separately from the inventory)
drawback: you canāt create recipe which needs more than one metal of one type (like 2 copper and 1 whatever)
Right. Iāve done my research on Hashtables & Dictionaries.
Lurkingninjadev
I think I understand your response.
You mentioned a Hashtable cannot use "
drawback: you canāt create recipe which needs more than one metal of one type (like 2 copper and 1 whatever)" this is because it cant use <int, string, string>? It has to have a single value datatype. Correct ?
Doug
I donāt understand your code. Iāll explain when I get home
Sure, feel free. But just before you do that, would you try this :
Try the code out below.
Put a breakpoint on line 10.
Once you hit the breakpoint, just keep pressing F11 through til you get to line 11.
Did you see how the result was achieved?
What happens if you call result = craft.TheseMake("Iron", "Wood"); instead?
public class Test : MonoBehaviour
{
void Awake()
{
craft = new CCrafting();
}
void Start()
{
var result = craft.TheseMake("Wood", "Iron");
}
CCrafting craft;
}
There are so many ways of creating the same result.
My setup would be something like the code below, where a Player monobehaviour has an Inventory and whenever you āuseā a recipe you can check the Recipe.CanCraft and give a reference to your inventory.
you can think of some more logic to actually craft the item (in the ItemRecipe).
basically simple logic where if the Inventory.GetItem returns null it means your item is not in the inventory. If it is it will not be null and you can check itās quantity.
With the ItemRecipe you could write a method Craft that takes the inventory as reference. Then call the Inventory.RemoveItem(Item, Quantity) or something like that. Then Inventory.AddItem(Item, Quantity).
I really love scriptable objects, still figuring out how to use them efficiently
Edit:
The reason that I put the logic of CanCraft / AddItem / RemoveItem in their ScriptableObject is because then you can easily debug where the call is coming from.
Your logic on how the Data changes will be contained within the ScriptableObject.
So if an NPC would be taking items from the inventory it would have to call the Inventory.RemoveItem of the Player Inventory. You can get a stack trace who is calling the RemoveItem method, you will know who is calling it. If the NPC has that logic to change the Inventory directly you may be searching all over the place where the Inventory is being managed by something. So containing such functionality within the ScriptableObject would be handy for debugging.
So instead of having a Remove method all over the place in several scripts, it is contained within the ScriptableObject. This makes automated testing easier as well, if you have automated tests you donāt need other scripts like an NPC, only the ScriptableObject.
using UnityEngine;
[CreateAssetMenu(menuName = "Scriptable Objects/Item")]
public class Item : ScriptableObject
{
public int ID;
}
using System;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(menuName = "Scriptable Objects/Item Recipe")]
public class ItemRecipe : ScriptableObject
{
public int ID;
public List<ItemRequirement> Recipe = new List<ItemRequirement>();
public ItemOutput OutputItem;
public bool CanCraft(ref Inventory inventory)
{
foreach (var itemRequirement in Recipe)
{
var inventoryItem = inventory.GetItem(itemRequirement.Item);
if (inventoryItem == null || inventoryItem.Quantity < itemRequirement.RequiredQuantity)
return false;
}
return true;
}
}
[Serializable]
public class ItemRequirement
{
public Item Item;
public int RequiredQuantity;
}
[Serializable]
public class ItemOutput
{
public Item Item;
public int Quantity;
}
using System;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(menuName = "Scriptable Objects/Inventory")]
public class Inventory : ScriptableObject
{
public List<InventoryItem> Items;
public InventoryItem GetItem(Item itemReference)
{
for (int i = 0; i < Items.Count; i++)
{
var inventoryItem = Items[i];
if (inventoryItem.Item.Equals(itemReference))
return inventoryItem;
}
return null;
}
}
[Serializable]
public class InventoryItem
{
public Item Item;
public int Quantity;
}
This is only true to the Sets (HashSet). Since the simplicity of the solution I proposed, it means you canāt have duplicated values in the Set. But you can choose other storage like Dictionary, where you can have duplicates, but for that, you will have to have your own check for equation (duplicates, order of the items matter).
Iāve been busy with creating an inventory system some time ago, opened up the project last night and even got the example I posted here implemented into it (it was better than what I made before). I extended it a little bit but I am at work now, canāt spend too much time hanging on the forum haha.
I extended its functionality by making the Item class abstract, the Item class itself contains the fields that all Items should have (such as an ID, Sprite, Description etc). I made a sub-class StackableItem that extends Item and gave it a MaxStacks integer field. Thats all what StackableItem adds on top of Item, a maximum amount of stacks.
So now when I try to call AddItem of the Inventory class I check whether the passed Item is a StackableItem, if so I check if I have it in the inventory already and if that is the case then try adding quantity +1. If it has reached max stacks I fill up a new slot. if there are no inventory slots left I return.
Eventually I want to hook up the inventory to the UI. On Inventory window open I want it to use the Player Inventory as reference, change the visuals using on the data that resides inside the Inventory ScriptableObject.
For easy debugging I can create a new Inventory asset file with different items and hook that up to the UI. It doesnāt have to be the player inventory for testing purposes. Thatās what I love about Scriptable Objects, the UI will not care where the information came from, you give it a reference to an inventory and it will do the magic.
Thanks Methos
One last thing.
I noticed the craftMatrix needs to be part of a function to work and for the defintions to be declared. Why is this?
Does the function reflect the Start() function?