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. Join us on Thursday, June 8, for a Q&A with Unity's Content Pipeline group here on the forum, and on the Unity Discord, and discuss topics around Content Build, Import Workflows, Asset Database, and Addressables!
    Dismiss Notice

Discussion Shop Inventory with the placing of items in Unity and C# (cont'd)

Discussion in 'Scripting' started by winstoniti, Jan 6, 2023.

  1. winstoniti

    winstoniti

    Joined:
    Dec 26, 2020
    Posts:
    3
    Hi there, last year I put up a post asking how would I implement placement of items from an inventory. This is a continuation of that post. Some time last year I managed to get something working.

    There were many useful comments in that post. There was a suggestion that I could use recursive functions or use co-routines. Now I've managed to get some form of implementation, but neither of them are recursive or use co-routines, as far as I'm aware. I wanted to stick to what I know so far and this is what I came up with. I assume what I'm do is using a queue. In my case, I'm using a list as a queue.

    I have three scripts in a ShopManager folder:

    HandleItems.cs
    HandleQuantity.cs
    HandleConfirm.cs

    and two scripts in a InstantiateObjects folder:

    InstantiateObjects.cs
    PlaceObjectHandler.cs

    HandleItems.cs shows the panels. HandleQuantity.cs handles the quantity. HandleConfirm reads a button press from the purchase button and sends a list of all the items including the desired quantity to the InstantiateObjects.cs script. I have other scripts working but they mostly involved button presses and Action events. They can all be seen the github example below.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using UnityEngine.Tilemaps;
    4. using UnityEngine.InputSystem;
    5. using System;
    6.  
    7. public class InstantiateObjects : MonoBehaviour
    8. {
    9.     public static List<HandleConfirm.ItemsData> purchaseItemData;
    10.     public static Action<List<HandleConfirm.ItemsData>> getDataEvent;
    11.     public static Action handleMovementEvent;
    12.     public static Action<GameObject> getGameObjectEvent;
    13.  
    14.     [SerializeField] public GameObject deskToSpawn;
    15.     [SerializeField] public GameObject metalDeskToSpawn;
    16.  
    17.     public bool hasBeenPlaced = false;
    18.    
    19.     private GameObject currentSelectedObject = null;
    20.     private Tilemap map;
    21.  
    22.     private bool isCreating = false;
    23.  
    24.     void Start()
    25.     {
    26.         map = GameObject.Find("Grid/Ground").GetComponent<Tilemap>();
    27.     }
    28.  
    29.     private void OnEnable()
    30.     {
    31.         HandleConfirm.sendPurchaseItemsListEvent += GetPurchasedItems;
    32.         PlaceObjectHandler.setHasBeenPlacedEvent += SetHasBeenPlaced;
    33.         PlaceObjectHandler.setGameObjectEvent += SetGameObject;
    34.         PlaceObjectHandler.setItemRemoveEvent += SetItemData;
    35.     }
    36.  
    37.     private void OnDisable()
    38.     {
    39.         HandleConfirm.sendPurchaseItemsListEvent -= GetPurchasedItems;
    40.         PlaceObjectHandler.setHasBeenPlacedEvent -= SetHasBeenPlaced;
    41.         PlaceObjectHandler.setGameObjectEvent -= SetGameObject;
    42.         PlaceObjectHandler.setItemRemoveEvent -= SetItemData;
    43.     }
    44.  
    45.     private void Update()
    46.     {
    47.         if (isCreating == true)
    48.         {
    49.             StartCreation(purchaseItemData);
    50.         }
    51.     }
    52.  
    53.     private void StartCreation(List<HandleConfirm.ItemsData> itemData)
    54.     {
    55.  
    56.         if (itemData.Count != 0)
    57.         {
    58.             InstantiateItem("Desk", deskToSpawn);
    59.             InstantiateItem("Metal Desk", metalDeskToSpawn);
    60.         }
    61.         else
    62.         {
    63.             isCreating = false;
    64.         }
    65.  
    66.         if (hasBeenPlaced == false)
    67.         {
    68.             Vector3 mousePosition = Camera.main.ScreenToWorldPoint(UnityEngine.InputSystem.Mouse.current.position.ReadValue());
    69.             Vector3Int mousePositionToCell = map.WorldToCell(new Vector3(mousePosition.x, mousePosition.y, 0));
    70.             Vector3 mousePositionCellToWorld = map.GetCellCenterWorld(mousePositionToCell);
    71.  
    72.             if (currentSelectedObject != null)
    73.             {
    74.                 getGameObjectEvent?.Invoke(currentSelectedObject);
    75.                 currentSelectedObject.transform.position = mousePositionCellToWorld;
    76.  
    77.                 if (Keyboard.current.eKey.wasPressedThisFrame == true)
    78.                 {
    79.                     Destroy(currentSelectedObject);
    80.                     isCreating = false;
    81.                 }
    82.             }
    83.         }
    84.  
    85.         handleMovementEvent?.Invoke();
    86.  
    87.     }
    88.  
    89.     private void InstantiateItem(string type, GameObject prefabToSpawn)
    90.     {
    91.         if (purchaseItemData[0].name == type)
    92.         {
    93.             if (currentSelectedObject == null)
    94.             {
    95.                 currentSelectedObject = Instantiate(prefabToSpawn, transform.position, Quaternion.identity);
    96.                 hasBeenPlaced = false;
    97.  
    98.             }
    99.         }
    100.     }
    101.  
    102.     public void GetPurchasedItems(List<HandleConfirm.ItemsData> purchasedList)
    103.     {
    104.         purchaseItemData = purchasedList;
    105.         if (purchaseItemData.Count != 0)
    106.         {
    107.             isCreating = true;
    108.         }
    109.         getDataEvent?.Invoke(purchaseItemData);
    110.     }
    111.  
    112.     void SetHasBeenPlaced(bool _hasBeenPlaced) { hasBeenPlaced = _hasBeenPlaced; }
    113.     void SetGameObject(GameObject _currentSelectedObject) { currentSelectedObject = _currentSelectedObject; }
    114.     void SetItemData(List<HandleConfirm.ItemsData> _itemsData) { purchaseItemData = _itemsData; }
    115. }
    116.  
    The InstantiateObjects.cs script will check if the list is filled, and then look at the first item in the list. An Action event is set to trigger the PlaceObjectHandler.cs function called
    MoveInstanceUpdate which is triggered once instantiation of the object has taken place.

    A counter is used and calculated against the quantity of the current item in the PlaceObjectHandler.cs script.

    Code (CSharp):
    1. public class PlaceObjectHandler : MonoBehaviour
    2. {
    3.     public static Action<bool> setHasBeenPlacedEvent;
    4.     public static Action<GameObject> setGameObjectEvent;
    5.     public static Action<List<HandleConfirm.ItemsData>> setItemRemoveEvent;
    6.     private List<HandleConfirm.ItemsData> itemData;
    7.  
    8.     private GameObject currentSelectedObject;
    9.     private GameObject panel;
    10.     private GameObject itemSpawner;
    11.  
    12.     private bool hasBeenPlaced = false;
    13.     private int counter = 0;
    14.  
    15.     private void OnEnable()
    16.     {
    17.         InstantiateObjects.getDataEvent += GetData;
    18.         InstantiateObjects.getGameObjectEvent += GetGameObject;
    19.         InstantiateObjects.handleMovementEvent += MoveInstanceUpdate;
    20.     }
    21.  
    22.     private void OnDisable()
    23.     {
    24.         InstantiateObjects.getDataEvent -= GetData;
    25.         InstantiateObjects.handleMovementEvent -= MoveInstanceUpdate;
    26.         InstantiateObjects.getGameObjectEvent -= GetGameObject;
    27.     }
    28.  
    29.     private void Start()
    30.     {
    31.         panel = GameObject.Find("Canvas/ShopPanel");
    32.         itemSpawner = GameObject.Find("ItemSpawner");
    33.     }
    34.  
    35.     private void Update()
    36.     {
    37.         if (itemData.Count > 0)
    38.         {
    39.             panel.SetActive(false);
    40.         }
    41.         else
    42.         {
    43.  
    44.             panel.SetActive(true);
    45.             itemSpawner.SetActive(false);
    46.         }
    47.     }
    48.  
    49.     private void MoveInstanceUpdate()
    50.     {
    51.         if (UnityEngine.InputSystem.Mouse.current.leftButton.wasPressedThisFrame == true)
    52.         {
    53.             if (currentSelectedObject.GetComponent<CollisionWithGroundHandler>().IsObjectTouchingGround)
    54.             {
    55.                 if (itemData[0].name == "Desk" || itemData[0].name == "Metal Desk")
    56.                 {
    57.                     counter = counter + 1;
    58.                     if (itemData.Count > 0)
    59.                     {
    60.                         PlaceObject(itemData[0].name, itemData[0].quantity, itemData);
    61.                     }
    62.                 }
    63.             }
    64.         }
    65.     }
    66.  
    67.     void PlaceObject(string name, int quantity, List<HandleConfirm.ItemsData> itemData)
    68.     {
    69.         SetHasBeenPlaced(true);
    70.         SetGameObject(null);
    71.  
    72.         if (counter >= quantity)
    73.         {
    74.             counter = 0;
    75.             itemData.Remove(itemData[0]);
    76.             SetItemData(itemData);
    77.         }
    78.     }
    79.  
    80.     public void SetHasBeenPlaced(bool _hasBeenPlaced) { setHasBeenPlacedEvent?.Invoke(_hasBeenPlaced); }
    81.     public void SetGameObject(GameObject _currentSelectedObject) { setGameObjectEvent?.Invoke(_currentSelectedObject); }
    82.     public void SetItemData(List<HandleConfirm.ItemsData> _itemData) { setItemRemoveEvent?.Invoke(_itemData); }
    83.  
    84.     private void GetGameObject(GameObject _currentSelectedObject) { currentSelectedObject = _currentSelectedObject; }
    85.     private void GetData(List<HandleConfirm.ItemsData> purchasedList) { itemData = purchasedList; }
    86. }
    87.  
    I had actually gone a little further than what I have got here with this project, but I decided to start again and go back, clean the code a little bit, and have only twos items that can be placed.

    I decided to upload the code and project to github. https://github.com/winnieTheWind/2DItemPlacementDemo

    I initially had more items, but it started to make the code look bloated. Currently the two items do the same thing when they are instantiated.

    if I had an item that could only be placed on a desk instead of the ground, it would require a seperate if statement or a different method.

    There are things like the DRY principle that I'm trying to take into consideration. I originally had a lot of code sitting inside one method and repetition, and thought it would be better if I made new methods to fix that.

    I have a lot of Action events going between all the scripts, it can be difficult to keep track of them and know what they do at all times.

    The naming of variables I find very difficult.

    While I'm proud to say I have something working, I'm assuming it ain't perfect, which is why I've come here. There may be crucial things I'm missing out on. I may be doing something wrong.

    I still dont understand how to do this via recursion as well. Unless I have it wrong, what I have so far does not use recursion? I'm a little lost on how to use recursion at this point.



    Feel free to critique my understanding of any of this. I'm all in this to learn and get better. Any suggestions or critiques would be much appreciated. Thanks. :)
     
    Last edited: Jan 6, 2023
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    33,707
    Is any of this a problem that would truly benefit from recursion? I suppose if one of the items in your inventory was actually ANOTHER entire inventory, and you could go into that sub-inventory, and inside of it was a whole bunch of items AND ANOTHER inventory, but you're not making anything silly like that, right?!

    To understand recursion you must first understand recursion.

    If the code works it works. Ship it, move onto the next thing. Inventories (as I wrote to you here: https://forum.unity.com/threads/bui...of-items-in-unity-and-c.1359403/#post-8575264) are very tricky and tightly bound to any game they support. For instance, you would never be able to use a Diablo inventory in WoW, or a Wow inventory in Minecraft.
     
    winstoniti likes this.