What is the best way to add an enemy character to the story with a fight scheme?

This is interesting Nina, I just checked how to create a dictionary but I can’t figure out how can I make a Dictionary [SerializeField] like I am doing with a list

image

You cannot expose a dictionary.

What you could do is the following:


For your items:

  1. Create a public enum in a separate script with all items. Name it Item.
  2. Create a public struct for your enemy fields in the aforementioned script. In Unity, it’s a bit “complicated” to expose a struct in the Inspector but it is possible.
  3. One of the fields in the struct must be of type Item.
  4. Create a new type of ScriptableObject, name it InventoryItem .
  5. Use the struct in InventoryItem.
  6. Create your items in your assets folder.

For your inventory:

  1. Create a new class, name it Inventory.
  2. Expose a List or array in your Inspector. Assign all InventoryItem objects to it.
  3. Create a Dictionary which is as large as your array, and which contains all items from the enum with the enum elements as the key.
  4. Create a public method which returns what you need in your InventoryScene object.

The visualised dictionary would look like this:

Key Value
ItemCategory.BlackMatter InventoryItem object: { reference to ItemConfig object, 0 }
ItemCategory.PowerGun InventoryItem object: { reference to ItemConfig object, 0 }

And here is how it could/would be implemented (theoretically):

// Where you keep an array of all items and their scriptable objects
// Use each ItemCategory only once! Otherwise, the dictionary will not work as intended.
public class InventoryItems : ScriptableObject
{
    // The array with the items
    [SerializeField] Item[] items = new Item[2]
    {
        new Item(ItemCategory.BlackMatter, null),
        new Item(ItemCategory.PowerGun, null)
    };

   // Your items
   public Item[] GetItems()
   {
       return items;    
   }
}
// Another script where you keep the general stuff for the items and inventory

// To connect an item with a scriptable object
[Serializable]
public struct Item
{
    private ItemCategory _category;
    [SerializeField] private ItemConfig _config;

    // To make the fields readable from outside
    public ItemCategory category  => _category;
    public ItemConfig config => _config;

    // Constructor
    public InventoryItem (ItemCategory category, ItemConfig config)
    {
         this._category = category;
         this._config = config;
    }
}

public enum ItemCategory
{
    BlackMatter,
    PowerGun
}
// Where you configure your objects
public class ItemConfig : ScriptableObject
{
    [SerializeField] int _attack = 0;
    [SerializeField int _defence = 0;

    public int attack  => _attack;
    public int defence => _defence;
}

And now you could, theoretically, generate your dictionary to keep track of the number of items.

public class Iventory : MonoBehaviour
{
    [SerializeField] private InventoryItems inventoryItems;

    public struct InventoryItem
    {
        public ItemConfig config;
        public int amount = 0;
    }

    private Dictionary<ItemCategory category, InventoryItem item> inventory;


    void Awake()
    {
        if (inventoryItems == null)
        {
              Debug.LogError("InventoryItems missing.");
              return;
        }
 
        // remove the ? if it throws a compiler error
        Item[] items = inventoryItems?.GetItems();

        inventory = new Dictionary<ItemCategory category, InventoryItem item>(items.Length);
        
        foreach (Item item in items)
        {
            InventoryItem invItem = new InventoryItem();
            invItem.config = item.config;
            invItem.amount = 0;

            inventory.Add(item.category, invItem);
        } 
    }

    // Your methods to return what you need
}

Something like that. I didn’t test it. Maybe there is a typo somewhere but I hope you’ll get an idea of what you could do.


And if you want to make your game even more complex, learn JSON (very simple) and learn how to read JSON objects in a C# instance (not so simple but not that complicated either, see below). Then you could drop most of the scriptable objects, and you could configure your items in a simple JSON file.

https://docs.unity3d.com/Manual/JSONSerialization.html
https://docs.unity3d.com/ScriptReference/JsonUtility.FromJson.html

Since the JSON website looks a bit overwhelming, this is how your JSON object string could look like:

{
    "items": [
        { 
           "id": "BlackMatter",  // for the enum key in the dictionary
           "name": "Black Matter", // the string you display in your game
           "damage": 10,
           "value": 999
        },
        { 
           "id": "PowerGun",    // for the enum key in the dictionary
           "name": "Power Gun", // the string you display in your game
           "damage": 1000,
           "value": 3
        }
    ]
}

This could replace the suggested ItemConfig files but not the class from which you still generate objects in your Inventory instance during runtime.

Refer to this thread to see how a JSON object like this could be used:
http://answers.unity.com/answers/1416650/view.html

Hi Nina,

I tried to look into a Dictionary strategy but I admit that probably it is still too articulated for my newbie understanding of C#.
I did a couple of experiments since this morning but then I went back to the list and try to master it first.
The code for the adventure became too articulated and any change I try to make in it to incorporate a dictionary would risk to vanish what I have done so far…

I have took some of the advises about the Dictionary so my item class now looks like this:

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

[System.Serializable]

public class Item 
{
    public string itemName;
    public int attack;
    public int defence;
    public int stamina;
    public int value;
    public bool Weapon;
    public bool Potion;
    public bool MagicBook;
    public Sprite sprite;
    }




I have two lists at the moment:

  • a list that belongs to each single state. It is unique characteristic of the state. it represents the list of items of the enemy. The items that the player will get as reward once killed the enemy.
  • a player list (player inventory item) which collects all players items.

I have managed to access each single element in the player inventory with two buttons that allows me to scroll up and down in the list.
Once the player has selected the item he wants than he can perform the action USE

It looks probably little bit over complicated but at the moment it is the only thing I can think of!

public void InventoryScrollUp()
{

   playerDatabaseMaxIndex = playerDatabase.Count;


    
    
    if (index >= playerDatabaseMaxIndex-1)
    {

        index = playerDatabaseMaxIndex-1;
    }
    print(playerDatabaseMaxIndex);
    print(index);

    inventoryScroll.text = playerDatabase[index].itemName.ToString();
    index += 1;

}

Good job. :slight_smile:

How do you connect the item with the story part, so the player can collect items? (Given the player can collect something.)

I was thinking to create a new scriptable object of type Quest (as you suggested before regarding the enemy). This new object would contain one or more item that the player is supposed to have collected during his journey.
Connect the quest to the main State.

When the player reaches a state with a quest, the system disables all the main control buttons and ask the player to do something with his items in the inventory.
Behind the USE method I could compare the item string in the player inventory with the Quest string item. If the two are equal the quest is solved and the player unlock the story controls so he can proceed to the next state. The item is then removed from the inventory.

Other quest would require the player to COMBINE items together and so on.

There is a question mark about that: what if I give the player the DROP method and he drops the item from his inventory during the quest? The system would stall at the moment. I need to figure out a backup state or maybe remove the DROP method from the inventory.

Take into account that the weapons would not be stored in the same inventory.
The weapons would be stored in a different section called EQUIPMENT.

So many things coming out, but at least now I have the basic knowledge to build them together!
I will give the dictionary a second chance as well…:slight_smile:

Or you could add a bool to the Item class: dropable or something like that. The bool would be set to false for items that are required in a quest. When the player selects an item, you could enable/disable the DROP button based on the bool value.

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms