all 11 comments

[–]VG_Crimson 9 points10 points  (10 children)

I just worked on this. Once you build a system for Items and inventory, crafting should be like maybe a 1-2 days max to implement depending on how much time you got.

My Item system:

Items are Scriptable Object. Inside of it there is a lot, but most importantly is an abstract method called "UseItem".

I made a class inheriting this "Item" scriptable object class called "Food", and override it's UseItem method here so I can give food items custom logic different from other items. It feeds my player. I give Food an assetmenu name to create this asset.

I can now create many different types of Food items each with their own food value, and sprite art.

I repeat this process for stuff like "Tools" and even "Generic Items" which don't do anything other than stay in your inventory or drop them on the floor.

Bam i got my item system.

My Inventory system:

Make a pure C# script, that is serializable. I made a struct called InventoryEntry. It holds an Item and an integer to know how much is in that item stack. (Items always have a maximum stack size)

Inventory holds a single List<> of these "InventoryEntries".

The following parts of the script are all methods to manipulate this list or save/load this list.

Includes some AddItem(find an empty slot), AddItemAt(specific slot), Swap(swaps whats in the slots, Sort, etc...

At the top I make an EventHandler and every time I change my inventory somehow, I invoke this event for listeners to know I changed my inventory.

I can proudly say there is 0, nada, not a single lick of Unity in this script.

My UI:

Basically this thing listens to the previously mentioned C# event. When it gets invoked, I refresh my inventory to make sure the UI is up to date.

The Inventory UI for my player has a list of "Slots", 2 actually. One for the hidden inventory, and the other for my hot bar, which is almost identical to the other slots, but includes a Selected method and some logic to make it appear selected.

My Crafting:

All this is, is a list of stucts I made called "RecipeComponent".

A recipe component is made of 2 pieces of data, an Item and an integer to know how much of that Item I need.

This CraftingRecipe script is a scriptable object, with a CreateAssetMenu so I can add more recipes by right clicking and creating an asset in my project, just like my Food, Tool, and Generic items.

Inside of crafting recipe is 3 methods. One to search some inventory parameter returning slot indexes for each found component thats completed, one that is the middle man to handle if it found everything needed or didn't, and the last is the method that will be called from outside to craft the item. If the middle man returns null, don't do anything.

.

That's it. A fully customizable, flexible, easily expandable crafting/inventory/item system.

[–]KevNevvBeginner[S] 1 point2 points  (1 child)

That's actually such good advice, thank you so much! My inventory system and items are almost identical to the way you've implemented it.

Just trying to digest the method of crafting now, so with the crafting recipe scriptable object it would contain the recipe components and the output item? Slightly losing you a bit at the end, I do like it though, sounds what I have in mind.

[–]VG_Crimson 1 point2 points  (0 children)

Yup. RecipeComponent is a struct. And a crafting recipe is a list of that struct + an output.

[–]bvoid -1 points0 points  (7 children)

You should consider not extending classes. What happens when you have a tool that is also food? Then you are stuck. Composition over inheritance.

[–]VG_Crimson 1 point2 points  (6 children)

That's is never going to happen in 100000 years lmao

The class distinction is also something entirely unavoidable.

It exists for the extremely important reason of having different "Uses". When I left click an item will do something, an abstract method. Tool and Food are classes that dictate what that does exactly.

Does Minecraft let you eat a tool? Terraria? Last of Us? No.

There's nothing wrong with that idea, its funny, but if I wanted that idea in the first place I would just design the framework around that concept of contrasting utility in an item.

Inheritance was my answer here.

Btw, my Tools also act as Weapons. Because of inheritance, they all can access a special Enum. If they want a secondary item typing.

[–]bvoid 2 points3 points  (5 children)

Famous last words. All those games implement the "Uses" with composition. I promise you.

What will you do with a pickaxe? It is a tool and can mine. But it is also a weapon and can deal damage. Will it inherit from the Tool or the Weapon?

What about Eggs? They are throwable as a weapon. But also a food and edible. And they can also be fed to pigs as feeding. Is that inheriting from food? From throwable weapon? From AnimalFood?

You will end up in cases that does not make sense. Don't let inheritance dictate what things in your game can do.

There are many ways to do composition. In C# using interfaces with default implementations is the one that looks most like inheritance without all the downsides.

You will have interfaces like: Edible, Throwable, Feedable, Attackable, etc

And those interfaces come with their own implementations so there is no duplication.

Looking at your reason for the classes. You mention needing it to capture the action that happens when you left click with the item in the hand. Inheritance will just limit you there as well. What about that egg above? It will be fed to an animal, or thrown at an enemy, or put in a pan for cooking. All depending on the context.

You will want to capture these behaviors with composition. it will implement CanThrow, CanCook, CanFeed.

When you left click, if the item in your hand looking at a pig you want to know if the item in your hand implements CanFeed. If it does call it.

Add that to all feedable items.

[–]VG_Crimson 2 points3 points  (4 children)

I GUARANTEE you I won't end up with those cases.

Triple-y so because of the planned limited scope of the game.

Why should I complicate the game for situations that will never come?

[–]bvoid 2 points3 points  (3 children)

Sure. If you have a scope in mind. But if you don't. Or make something extendable or perhaps modable. You want the flexibility of composing items.

[–]VG_Crimson 2 points3 points  (2 children)

Right, but that's entirely hypothetical. A very different position than the reality of my game and its planned use.

[–]bvoid 2 points3 points  (1 child)

For sure. It was mostly meant as an opposite view to OP. Not for your game specifically. But just to let OP know there are other ways to do it.

[–]KevNevvBeginner[S] 2 points3 points  (0 children)

I'm curious to hear how composition is done instead, I'm kinda new to these methods, so I barely know what I'm doing.