Page 1 of 1

accessing global variables in a project

Posted: Tue Aug 29, 2023 8:32 am
by Smoky
Good afternoon I had a question about how to access variables from any part of the game. I have an inventory in the game where you can put items and remove them from it

Code: Select all


namespace UI.InventoryScripts
{
    [System.Serializable]
    public class Item
    {
      //  public int ID { get; set; }
        public string Name { get; set; }
        public int Count { get; set; }
        public string Img { get; set; }
        public string Description { get; set; }
        public bool IsUsed { get; set; }
        // добавить описание, bool значение одет предмет или нет, максимум два кольца и одно ожерелье
    }
}

Code: Select all

namespace UI.InventoryScripts
{
    public class ItemsDB : MonoBehaviour
    {
        public List<Item> _items = new();
    }
}

Code: Select all

using System;
using System.Collections.Generic;
using System.IO;
using TMPro;
using Newtonsoft.Json;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.EventSystems;
using Button = UnityEngine.UI.Button;
using Image = UnityEngine.UI.Image;

namespace UI.InventoryScripts
{
    public class Inventory : MonoBehaviour
    {
        [SerializeField] private ItemsDB _data;

        [SerializeField] private List<ItemInventory> _items = new();

        [SerializeField] private GameObject _gameObjShow;

        [SerializeField] private GameObject _inventoryMainObject;

        [SerializeField] private EventSystem _es;

        [SerializeField] private int _currentID;
        [SerializeField] private ItemInventory _currentItem;
        
        [SerializeField] private GameObject _backGround;

        [SerializeField] private GameObject _selectItemImage;

        [SerializeField] private Button _useButton;
        [SerializeField] private Button _deleteButton;

        [SerializeField] private TextMeshProUGUI _nameOfItem;
        [SerializeField] private TextMeshProUGUI _descriptionOfItem;
        
        public void Start()
        {
            string json = File.ReadAllText(Application.dataPath + "/items.json");
            _data._items = JsonConvert.DeserializeObject<List<Item>>(json);

            ChangeInventory();
            
            UpdateInventory();
        }

        public void Update()
        {
            UpdateInventory();
        }

        private void ChangeInventory()
        {
            if (_items.Count == 0)
            {
                foreach (var t in _data._items)
                {
                    AddGraphics(t);
                }
            }
            
            for (int i = 0; i < _data._items.Count; i++)
            {
                var item = _data._items[i];
                AddItem(i, item);
            }
        }

        private void AddItem(int id, Item item) //добавляет предмет в лист ItemInventory
        {
            Texture2D itemImage = new Texture2D(60,60);
            byte[] imageData = File.ReadAllBytes(Application.dataPath + item.Img);
            itemImage.LoadImage(imageData);
            Sprite sprite = Sprite.Create(itemImage, new Rect(0, 0, itemImage.width, itemImage.height), Vector2.one * 0.5f);
            
//            _items[id]._id = item.ID;
            _items[id]._name = item.Name;
            _items[id]._count = item.Count;
            _items[id]._itemGameObj.GetComponentInChildren<Image>().sprite =  sprite;
            _items[id]._isUsed = item.IsUsed;
            _items[id]._description = item.Description;
        
            if (item.Count > 1)
            {
                _items[id]._itemGameObj.GetComponentInChildren<TextMeshProUGUI>().text = item.Count.ToString();
            }
            else
            {
                _items[id]._itemGameObj.GetComponentInChildren<TextMeshProUGUI>().text = "";
            }
        }

        private void AddGraphics(Item t) //добавляет кнопку предмета в инвентарь
        {
            var newItem = Instantiate(_gameObjShow, _inventoryMainObject.transform);
                
            newItem.name = t.Name;

            var ii = new ItemInventory
            {
                _itemGameObj = newItem
            };

            var rt = newItem.GetComponent<RectTransform>();
            rt.localPosition = new Vector3(0, 0, 0);
            rt.localScale = new Vector3(1, 1, 1);
            newItem.GetComponentInChildren<RectTransform>().localScale = new Vector3(1, 1, 1);

            Button tempButton = newItem.GetComponent<Button>();
            
            tempButton.onClick.AddListener(SelectObject);

            _items.Add(ii);
            
        }

        // ReSharper disable Unity.PerformanceAnalysis
        public void UpdateInventory()
        {
            for (var i = 0; i < _data._items.Count; i++)
            {
                if (_items[i]._count > 1)
                {
                    _items[i]._itemGameObj.GetComponentInChildren<TextMeshProUGUI>().text = _items[i]._count.ToString();
                }
                else
                {
                    _items[i]._itemGameObj.GetComponentInChildren<TextMeshProUGUI>().text = "";
                }

                _items[i]._itemGameObj.transform.GetChild(1).GetComponent<Image>().enabled = _items[i]._isUsed;
            }
        }

        private void SelectObject()
        {
            if (_currentID == -1)
            {
                _currentItem = _items.Find(x => x._name == _es.currentSelectedGameObject.name);
                
                _selectItemImage.GetComponent<Image>().sprite = _currentItem._itemGameObj.GetComponentInChildren<Image>().sprite;
                DescriptionObject(_currentItem);
                
                _deleteButton.onClick.AddListener(DeleteObject);
                
                _useButton.onClick.AddListener(UseObject);
            }
            UpdateInventory();
        }
        
        private void DeleteObject()
        {
            _data._items.Remove(_data._items.Find(x => x.Name == _currentItem._name));
            _items.Remove(_items.Find(x => x._name == _currentItem._name));
            GameObject childObject = _inventoryMainObject.transform.Find(_currentItem._name).gameObject;
            Destroy(childObject);
            UpdateInventory();
        }

        private void UseObject()
        {
            
        }

        // ReSharper disable Unity.PerformanceAnalysis
        public void AddObject(Item itemForAdd)
        {

            if (_data._items.Find(x => x.Name == itemForAdd.Name) != null)
            {
                _data._items.Find(x => x.Name == itemForAdd.Name).Count++;
                _items.Find(x => x._name == itemForAdd.Name)._count++;
            }
            else
            {
                _data._items.Add(itemForAdd);
                //ChangeInventory();
                AddGraphics(itemForAdd);
                Debug.Log(_items.Count);

                AddItem(_items.Count - 1, itemForAdd);
            }
            
            UpdateInventory();
        }

        private void DescriptionObject(ItemInventory currentItem)
        {
            _nameOfItem.text = currentItem._name;
            _descriptionOfItem.text = currentItem._description;
        }

        private void OnApplicationQuit()
        {
            string path = Application.dataPath + "/items.json";
            
            File.WriteAllText(path, JsonConvert.SerializeObject(_data._items));
        }

        
    }
    

    [Serializable]
    public class ItemInventory
    {
        //public int _id;
        public string _name;
        public GameObject _itemGameObj;
        public int _count;
        public bool _isUsed;
        public string _description;
    }
}
The question is how to make the dialogue system always keep track of the number of items in the inventory. For example, I have 2 torches and 1 cloth. The dialog has 2 nodes

1 - always shown
2 - appears if the inventory has 1 torch and 1 rag.

After the dialogue through the 2nd node, we remove items from the inventory

Re: accessing global variables in a project

Posted: Tue Aug 29, 2023 10:33 am
by Tony Li
Hi,

First write a C# method that returns the amount of an item that's in the player's inventory. Rough example:

Code: Select all

public class Inventory : MonoBehaviour
{
    ...
    public double GetItemAmount(string itemName)
    {
        var item = _items.Find(x => x.name == itemName);
        return (item != null) ? item._count : 0;
    }
}
Then register it with Lua so you can use it in the dialogue entry's Conditions field.

Re: accessing global variables in a project

Posted: Tue Aug 29, 2023 11:58 am
by Smoky
At the moment I have 3 variables registered with this code

Code: Select all

 [SerializeField] private double _physicalAbilities = 1; // физические способности
    [SerializeField] private double _perception = 1;        // восприятие
    [SerializeField] private double _intellect  = 0;        // интеллект 
    // private double _physicalAbilitiesDouble;
    // private double _perceptionDouble;
    // private double _intellectDouble;
    //
    // private void Update()
    // {
    //     _physicalAbilitiesDouble = (Int32)_physicalAbilities;
    //     _perceptionDouble = (Int32)_perception;
    //     _intellectDouble = (Int32)_intellect;
    // }

    private void OnEnable()
    {
        // Lua.RegisterFunction("PhysicalAbilities", this, SymbolExtensions.GetMethodInfo(() => _physicalAbilities((int)0)));
        Lua.RegisterFunction("PhysicalAbilities", this, SymbolExtensions.GetMethodInfo(() => GetPhysicalAbilities(1)));
        Lua.RegisterFunction("Perception", this, SymbolExtensions.GetMethodInfo(() => GetPerception(1)));
        Lua.RegisterFunction("Intellect", this, SymbolExtensions.GetMethodInfo(() => GetIntellect(1)));
    }

    private void OnDisable()
    {
        Lua.UnregisterFunction("PhysicalAbilities");
        Lua.UnregisterFunction("Perception");
        Lua.UnregisterFunction("Intellect");
    }

If I have more than 100 variables, will I have to register them all this way, or can lists, sheets, etc. be registered at once?

Re: accessing global variables in a project

Posted: Tue Aug 29, 2023 12:17 pm
by Tony Li
Hi,

You could register a single C# method that accepts the variable name as a parameter:

Code: Select all

public double GetSkill(string skillName)
{
    switch (skillName)
    {
        case "PhysicalAbilities": return _physicalAbilities;
        case "Perception": return _perception;
        case "Intellect": return _intellect;
        ...
        default: 
            Debug.Log($"GetSkill('{skillName}') is not a valid skill name.");
            return 0;
}

Code: Select all

Lua.RegisterFunction("GetSkill", this, SymbolExtensions.GetMethodInfo(() => GetSkill("")));

Re: accessing global variables in a project

Posted: Tue Aug 29, 2023 12:38 pm
by Smoky
And one more small question. Is there a problem with the scrollbar setting. And it turns out that I create a vertical scrollbar in the prefab and it appears during the dialogue. When scrolling the dialog with the mouse, the slider on the scrollbar changes its position, but it is not possible to grab the slider itself and scroll through the dialog. Maybe I'm doing something wrong.

Re: accessing global variables in a project

Posted: Tue Aug 29, 2023 7:50 pm
by Tony Li
Hi,

Try assigning the Scroll Content GameObject to the Scrollbar Vertical's Viewport field.