Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Bug Variables not being set using enums

Discussion in 'Scripting' started by d55d, Jul 6, 2023.

  1. d55d

    d55d

    Joined:
    Oct 4, 2020
    Posts:
    4
    Hi, yall. I'm both new to asking questions here and writing code for Unity.

    I'm trying to build this Shop that takes an array of shopItems[] in the inspector inherited from an Item class. The specific version of that item is then set with an enum in the inspector (basic, advance, rare, etc.) that is supposed to decide the version with each item's respective SetVariables-method. The issue is that the values for the items aren't set in the Shop-class

    I first thought it had something to do with the Shop Start method being triggered before the Item could set its values (since the Debug.Log in the Shop class was triggered before the one in the Item class, so I tried both using Awake for the Item class and coroutine for the Start method, but the variables weren't set either way. Any help or suggestion is appreciated.

    Code (CSharp):
    1. public class Shop : MonoBehaviour
    2. {
    3.     #region Serialized Fields
    4.     [SerializeField] private Item[] shopItems;
    5.     [SerializeField] private PlayerCamera playerCamera;
    6.     [SerializeField] private ExplorationController playerController;
    7.     [SerializeField] private DialogManager dialogManager;
    8.     [SerializeField] private ShopHandlers dialogHandlers;
    9.     [SerializeField] private Item emptySpot;
    10.     private readonly List<Vector3> shopItemPositions = new();
    11.  
    12.     #endregion
    13.  
    14.     #region Private Fields
    15.     [HideInInspector] public bool pauseShoppingControls;
    16.     [HideInInspector] public Item focusedShopItem;
    17.     private int focusedShopItemIndex = 0;
    18.     #endregion
    19.  
    20.     #region MonoBehaviour Methods
    21.     private void Start()
    22.     {
    23.         for (int positionIndex = 1; positionIndex <= 6; positionIndex++)
    24.         {
    25.             string positionName = "Position " + positionIndex;
    26.             Transform childTransform = transform.Find(positionName);
    27.             if (childTransform != null)
    28.             {
    29.                 Vector3 childPosition = childTransform.position;
    30.                 shopItemPositions.Add(childPosition);
    31.             }
    32.         }
    33.         SpawnItems();
    34.         Debug.Log(shopItems[0].Name);
    35.     }
    36. }
    37.  
    Code (CSharp):
    1. public class Bait : Item
    2. {
    3.     [SerializeField] private BaitTag baitTag;
    4.  
    5.     public enum BaitTag
    6.     {
    7.         BasicBait,
    8.         AdvanceBait,
    9.         RareBait,
    10.     }
    11.     public int Level { get; set; }
    12.  
    13.     private void Awake()
    14.     {
    15.         SetBaitVariables();
    16.     }
    17.  
    18.     private void SetBaitVariables()
    19.     {
    20.         itemTag = ItemTag.Bait;
    21.         switch (baitTag)
    22.         {
    23.             case BaitTag.BasicBait:
    24.                 Id = 1;
    25.                 Name = "Basic Bait";
    26.                 Level = 1;
    27.                 Description = "A basic bait given at childbirth";
    28.                 Price = 0;
    29.                 break;
    30.             case BaitTag.AdvanceBait:
    31.                 Id = 2;
    32.                 Name = "Advanced Bait";
    33.                 Level = 2;
    34.                 Description = "A more advanced bait not as easily found";
    35.                 Price = 5;
    36.                 break;
    37.             case BaitTag.RareBait:
    38.                 Id = 3;
    39.                 Name = "Premium Bait";
    40.                 Level = 3;
    41.                 Description = "A premium bait very rarely found";
    42.                 Price = 10;
    43.                 break;
    44.         }
    45.     }
    46.  
     
  2. KillDashNine

    KillDashNine

    Joined:
    Apr 19, 2020
    Posts:
    449
    I'm reading what you wrote. Your Shop is taking in items. Makes sense. But your problem is that the item values aren't set in your Shop class. Why would they? Shops sell items, they don't build them.
     
  3. d55d

    d55d

    Joined:
    Oct 4, 2020
    Posts:
    4
    Sorry might have phrased it poorly. It's not that the values should be set in the Shop, but that the items have empty values when they are being used in the shop. The values are selected by picking a tag in the inspector, then I apply the attached item script to a list of shop items in the shop object. The values should then be set in each Item-script on awake (like the bait-script shown earlier), using the setVariables method for each Item.
     

    Attached Files:

  4. KillDashNine

    KillDashNine

    Joined:
    Apr 19, 2020
    Posts:
    449
    Your SpawnItems() code is not visible so it's not too clear how you're spawning items.

    I am also spawning items in my game. I have item "blueprints" in JSON (one could also use ScriptableObjects), then I have various spawner methods that take a blueprint and create an item out of it. That's the logic.
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    I see you are using inheritance here and yet your Awake() method does not call base.Awake().

    This may be fine but highlights one of the critical failures when using inheritance in Unity: nobody using MonoBehaviour EXPECTS to call base classes, leading to a constant chance of introducing bugs, literally every single time you implement an inherited class or decide to implement an additional Unity method.

    Unity uses a Component architecture and it may be useful to you to follow suit.

    Unity's component architecture

    https://forum.unity.com/threads/custom-gameobject.967582/#post-6299125

    Also, keep this in mind:

    These things (inventory, shop systems, character customization, dialog tree systems, crafting, etc) are fairly tricky hairy beasts, definitely deep in advanced coding territory.

    Inventory code never lives "all by itself." All inventory code is EXTREMELY tightly bound to prefabs and/or assets used to display and present and control the inventory. Problems and solutions must consider both code and assets as well as scene / prefab setup and connectivity.

    Inventories / shop systems / character selectors all contain elements of:

    - a database of items that you may possibly possess / equip
    - a database of the items that you actually possess / equip currently
    - perhaps another database of your "storage" area at home base?
    - persistence of this information to storage between game runs
    - presentation of the inventory to the user (may have to scale and grow, overlay parts, clothing, etc)
    - interaction with items in the inventory or on the character or in the home base storage area
    - interaction with the world to get items in and out
    - dependence on asset definition (images, etc.) for presentation

    Just the design choices of such a system can have a lot of complicating confounding issues, such as:

    - can you have multiple items? Is there a limit?
    - if there is an item limit, what is it? Total count? Weight? Size? Something else?
    - are those items shown individually or do they stack?
    - are coins / gems stacked but other stuff isn't stacked?
    - do items have detailed data shown (durability, rarity, damage, etc.)?
    - can users combine items to make new items? How? Limits? Results? Messages of success/failure?
    - can users substantially modify items with other things like spells, gems, sockets, etc.?
    - does a worn-out item (shovel) become something else (like a stick) when the item wears out fully?
    - etc.

    Your best bet is probably to write down exactly what you want feature-wise. It may be useful to get very familiar with an existing game so you have an actual example of each feature in action.

    Once you have decided a baseline design, fully work through two or three different inventory tutorials on Youtube, perhaps even for the game example you have chosen above.

    Breaking down a large problem such as inventory:

    https://forum.unity.com/threads/weapon-inventory-and-how-to-script-weapons.1046236/#post-6769558

    If you want to see most of the steps involved, make a "micro inventory" in your game, something whereby the player can have (or not have) a single item, and display that item in the UI, and let the user select that item and do things with it (take, drop, use, wear, eat, sell, buy, etc.).

    Everything you learn doing that "micro inventory" of one item will apply when you have any larger more complex inventory, and it will give you a feel for what you are dealing with.

    Breaking down large problems in general:

    https://forum.unity.com/threads/opt...n-an-asteroid-belt-game.1395319/#post-8781697
     
    d55d likes this.
  6. d55d

    d55d

    Joined:
    Oct 4, 2020
    Posts:
    4
    Here's the spawner method. Just realized that the issue had to do with me trying to access the data for the item before the gameObject had been instantiated. Since the prefabs haven't been set in the scene, the Item Awake() method wasn't triggered. I fixed the issue by replacing the ShopItem in the array with the Item from the instantiated gameObject in SpawnShopItem.

    Thx for the help either ways! :D

    Code (CSharp):
    1.     private void SpawnItems()
    2.     {
    3.         // Loop through all shop item positions
    4.         for (int i = 0; i < shopItemPositions.Count; i++)
    5.         {
    6.             if (i < shopItems.Length && shopItems[i] != null)
    7.             {
    8.                 // Check if the current shop item is a fishing rod and is already in the player's inventory
    9.                 if (MainManager.Instance.game.HasItem(shopItems[i].Id, shopItems[i].itemTag))
    10.                 {
    11.                     // If the fishing rod is already in the player's inventory, spawn an empty spot instead
    12.                     SpawnEmptySpot(i);
    13.                 }
    14.                 else
    15.                 {
    16.                     // Otherwise, spawn the shop item
    17.                     SpawnShopItem(i);
    18.                 }
    19.             }
    20.             else
    21.             {
    22.                 SpawnEmptySpot(i);
    23.             }
    24.         }
    25.  
    26.         // Set the initial focused shop item
    27.         focusedShopItem = shopItems[focusedShopItemIndex];
    28.     }
    29.  
    30.     private void SpawnEmptySpot(int index)
    31.     {
    32.         shopItems[index] = emptySpot;
    33.         GameObject gameObject = Instantiate(shopItems[index].gameObject, shopItemPositions[index], Quaternion.identity);
    34.         gameObject.transform.parent = transform;
    35.     }
    36.  
    37.     private void SpawnShopItem(int index)
    38.     {
    39.         GameObject newObject = Instantiate(shopItems[index].gameObject, shopItemPositions[index], Quaternion.identity);
    40.         newObject.transform.parent = transform;
    41. //The Fix
    42.      Item item = newObject.GetComponent<Item>();
    43.         shopItems[index] = item;
    44.     }
     
  7. d55d

    d55d

    Joined:
    Oct 4, 2020
    Posts:
    4
    Awesome suggestions! I will definitely put some extra thought into these things. So far I do feel like I have a good grasp of what I want my inventory and items to do, It is more about figuring out how to implement it on a solid basis. Tho I'm not completely sure why I should call the base.awake() in the inherited class. I don't currently have any values I want to set default values for all items.
     
  8. KillDashNine

    KillDashNine

    Joined:
    Apr 19, 2020
    Posts:
    449
    Think about your data type. Your items have configuration data which tells how new items should be created when you create an instance of your item. Your items might also have runtime data that starts to apply after the item is created that can be unique to each item instance, such as "durability" or such.