Crafting system

Hi,

I have been searching for a crafting system to implement to my fps game.

ItemA+ItemB = ItemC

Just like in the game Europa ( http://forum.unity3d.com/threads/140149-My-7-day-fps-entry-Europa-Concept )

Is that hard to do in javascript ?

What I want to do is having a robot( or a box) that I press “E” and then my inventory and the robots inventory pops up. Then I can move items over to the robot and when I press craft it will make that item.

Is that hard to make ?

It doesn’t sound too relatively difficult. Use an array or list for both inventories, tie some functions in for inventory access and things, draw a gui, and then tie functions in to gui buttons.

I asked this question a while ago but didn’t get really helpfull responses.

One way to do it is using item ID’s and create some kind of formula to get a resulting item ID from the 2 compontent item ID’s. The disadvantage is this will create some sort of “hard limit” in how many items your game can have and it is less dynamic in my opinion.

What I did was create a “recipe” class, which stores 3 strings ( name of the needed components + name of result item ) and store those recipes in an array. Then, assuming you know the 2 names of the components you want to combine, loop through the recipe array and check if the two component names match the two in the recipe, when it does, return the resulting item name.

Hope this helps :smile:

This is how I pulled it off.

First I have an InvItemManager. This is the manager that I contact for creating and combing items to “craft” them. It also has a pool of all the graphics used so that I can manage that too.

It loads some xml which defines all the items that exist, and information about them. Like the class of item it is, the properties of said class, and the graphics used (it can also have different graphics for where the item is used. An item held in hand may use dif graphics then shown in inventory). And of course it is where the ‘recipes’ for the items is stored as well.

Here is a tiny example of the XML

<?xml version="1.0" encoding="UTF-8" ?>
<inventory>
	<item name="Stick" type="SimpleItem" found="true">
		<attrib name="meleedamage" type="float">0.1</attrib>
		<attrib name="throwrange" type="float">1.0</attrib>
		<attrib name="rangedamage" type="float">0.05</attrib>
		<graphics state="all" prefab="Items/Dummy" cachesize="100" resizebuffer="25" />
	</item>
	<item name="String" type="SimpleItem" found="true">
		<attrib name="meleedamage" type="float">0</attrib>
		<attrib name="throwrange" type="float">0.05f</attrib>
		<attrib name="rangedamage" type="float">0</attrib>
		<graphics state="all" prefab="Items/Dummy" cachesize="100" resizebuffer="25" />
	</item>
	<item name="Hook" type="SimpleItem" found="true">
		<attrib name="meleedamage" type="float">0.05</attrib>
		<attrib name="throwrange" type="float">0.2f</attrib>
		<attrib name="rangedamage" type="float">0.1</attrib>
		<graphics state="all" prefab="Items/Dummy" cachesize="100" resizebuffer="25" />
	</item>
	<item name="FishingLine" type="FishingRod">
		<attrib name="meleedamage" type="float">0</attrib>
		<attrib name="throwrange" type="float">0.1</attrib>
		<graphics state="all" prefab="Items/Dummy" cachesize="10" resizebuffer="5" />
		<combo>String, Hook</combo>
	</item>
	<item name="SimpleFishingRod" type="FishingRod">
		<attrib name="meleedamage" type="float">1.0</attrib>
		<attrib name="castrange" type="float">4.0</attrib>
		<attrib name="throwrange" type="float">4.0</attrib>
		<graphics state="all" prefab="Items/FishingRod_basic" cachesize="10" resizebuffer="5" />
		<combo>Stick, FishingLine</combo>
	</item>
</inventory>

This makes adding new items to it very easily as it’s all in a simple xml file.

Note the ‘type’ associated with each item is actually a class in the code. It defines the how this item will operate. So a FishingLine (just a string with a hook) and a FishingRod (string, hook, and rod) operate the same way. The only dif being cast distance and melee damage if you attempted to use it to smash something.

So they’re both of the same type, with slightly different values passed in for their meleedamage and range.

There are several of these classes in the background. For instance Gun, Sword, Potion, Tool, etc…

Dear Lordofduct,

I am interested in knowing how you parse this script/ what code you use for the parsing. I’m sure it shouldn’t be too hard, but I haven’t looked into it yet and this looks awesomely simple.

Currently I am managing with manually defining datatypes, then adding them to a list with a structure that holds all these datatypes together. It works great, but it’s not really user friendly.

Well this is the basic script that does the actual parsing of that xml:

        public void Load()
        {
            TextAsset data = UnityEngine.Resources.Load("Inventory") as TextAsset;

            var itemDict = new Dictionary<string, InvItem>();
            var graphicOpts = new List<SpawnPool.ItemOptions>();
            var comboList = new List<ComboInfo>();

            var xdoc = new XmlDocument();
            xdoc.LoadXml(data.text);

            var xitems = xdoc.DocumentElement.SelectNodes("./item");

            foreach (XmlElement xel in xitems)
            {
                //create IInvItem
                string sname = xel.GetAttribute("name");
                if (itemDict.ContainsKey(sname)) continue;

                string stype = (xel.HasAttribute("type")) ? xel.GetAttribute("type") : "SimpleItem";
                var info = new InventorySerializedInfo(sname, stype);

                var xprops = xel.SelectNodes("./attrib");
                foreach (XmlElement xprop in xprops)
                {
                    info.SetAttrib(xprop.GetAttribute("name"), xprop.InnerText);
                }

                var item = DeserializeItem(info);
                itemDict.Add(sname, item);

                //load graphics GameObject prefab and prepare for pool
                var xgraphics = xel.SelectSingleNode("./graphics") as XmlElement;
                var opts = new SpawnPool.ItemOptions();
                opts.Prefab = UnityEngine.Resources.Load(xgraphics.GetAttribute("prefab")) as GameObject;
                opts.ItemName = sname;

                if (xgraphics.HasAttribute("cachesize")) opts.CacheSize = ConvertUtil.ToInt(xgraphics.GetAttribute("cachesize"));
                if (xgraphics.HasAttribute("resizebuffer")) opts.ResizeBuffer = ConvertUtil.ToInt(xgraphics.GetAttribute("resizebuffer"));

                graphicOpts.Add(opts);

                //get combo to make if any
                var combo = new ComboInfo();
                combo.ItemName = sname;
                combo.Found = (xel.HasAttribute("found")) ? ConvertUtil.ToBool(xel.GetAttribute("found")) : false;
                
                var xcombo = xel.SelectSingleNode("./combo") as XmlElement;
                if (xcombo != null  StringUtil.IsNotNullOrWhitespace(xcombo.InnerText))
                {
                    string[] sparts = xcombo.InnerText.Split(',');
                    Array.Resize(ref sparts, 2);
                    combo.Part1 = StringUtil.Trim(sparts[0]);
                    combo.Part2 = StringUtil.Trim(sparts[1]);
                }

                comboList.Add(combo);
            }

            //set properties
            _itemDict = itemDict;

            _graphicPool.ClearCache();
            _graphicPool.CacheInstances(graphicOpts);

            _comboInfos = comboList;
        }

        private InvItem DeserializeItem(InventorySerializedInfo info)
        {
            var tp = Type.GetType("Ponyo.Items." + info.ClassName);
            if (tp != null  tp.IsSubclassOf(typeof(InvItem)))
            {
                var obj = Activator.CreateInstance(tp) as InvItem;
                obj.Deserialize(this, info);
                return obj;
            }

            throw new Exception("Failed to deserialize item " + info.Name + ".");
        }

It makes reference to quite a bit of different classes.

See I’ve been building my own framework (independent of Unity really) for a long time now and I’ve merely pulled them into my unity project to work with. Modifying what was necessary to get it to work together.

In this I’m using several things including:

SpawnPool - this is a system that deals with caching and pooling GameObjects, especially those with graphics that are heavy. I can ask for already create gameobjects from the pool, and if none are available the cache is buffered.

ConvertUtil - a conversion utility I use with my own standard/expectation of object parsing.

StringUtil - another utility I use with my own standard/expectation of dealing with strings

IInvItem - this represents an item, not as a gameobject, but as a basic object. An IInvItem can have a graphic associated with it so it can appear on screen.

InventorySerializedInfo - a wrapper object for sending serialized info around. InvItem’s are serializable, this is the serializedInfo that is passed to and retrieved from it when serializing it.

You’ll not that in ‘DeserializeItem’ I call ‘Deserialize’ on an InvItem… that’s where I pass in the info. Each InvItem sub-class has it’s own unique properties. They retrieve them from this ‘info’ passed in.

So that attribute @type in each item in the xml… that’s a class (which I have in the Ponyo.Items namespace). Those classes MUST inherit from InvItem, else they fail to work.

Me too im aslo looking for these,actually im looking for a crafting system with GUI that can be pressed like cube1 + cube2 = sphere.

I have a working system…

public void Craft(Craftable recipe){
		bool b = CheckItems (recipe.InputItems);
		if(b){//Craft...
}
}

public bool CheckItems(List<Item> check) {
		List<Item> it = new List<Item> (check);
		foreach(Item inventoryItem in MyItems) {
			if (it.Contains(inventoryItem)) {
				it.Remove(inventoryItem);
				if(it.Count == 0) {
					return true;
				}
			}
		}
		return false;
	}

Item, and craftable…

using UnityEngine;
using System.Collections;

[System.Serializable]
public class Item {

	public string itname;
	public float itvalue;
	public float itdur;
	public string ittype;
	public Texture2D iticon;

	public override bool Equals(object other) {
		if (other.GetType() != typeof(Item)) return false;
		if (((Item)other).itname == this.itname  ((Item)other).ittype == this.ittype) {
			return true;
		}
		return false;
		//return ((Item)other).itname == this.itname;
	}
}

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Craftable {

	public List<Item> InputItems = new List<Item>();

	public List<Item> Outputs = new List<Item>();

	public bool RequiresWorkBench;

}

You should also be able to use mono serialization: Redirecting…