Search Unity

Question How to properly update UI when the value this UI is showing is changed ?

Discussion in 'Scripting' started by serjeq, Feb 8, 2024.

  1. serjeq

    serjeq

    Joined:
    May 23, 2017
    Posts:
    24
    At first i put it in Update().
    But value only changes when "item" is equipped/taked off, so its seems wasteful.
    I tried to change UI value from the sourse of a change and use Canvas.ForceUpdateCanvases(); Doesnt work.
    May be some method ?

    By the way i did not using methods almost at all in my game. My code is just bunch of IF-statemants and varibales.
    Something like this where i create my ""Dynamic UI""

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using TMPro;
    4. using Unity.VisualScripting;
    5. using UnityEngine;
    6. using UnityEngine.UI;
    7.  
    8. public class OnHoverItemDescription : MonoBehaviour
    9. {
    10.  
    11.     private void OnMouseEnter()
    12.     {
    13.         if (gameObject.GetComponent<IsItem>())
    14.         {
    15.             GameObject obj = new(gameObject.name + "_Parent");
    16.  
    17.             obj.transform.SetParent(transform, true);
    18.  
    19.  
    20.             obj.AddComponent<RectTransform>();
    21.             obj.AddComponent<Canvas>();
    22.             obj.AddComponent<SpriteRenderer>();
    23.             obj.AddComponent<CanvasRenderer>();
    24.             obj.AddComponent<GridLayoutGroup>();
    25.  
    26.             obj.GetComponent<RectTransform>().sizeDelta = new Vector2(5, 5);
    27.             obj.GetComponent<RectTransform>().localPosition = new Vector3(-1, 0, 0);
    28.             obj.GetComponent<Canvas>().renderMode = RenderMode.WorldSpace;
    29.             obj.GetComponent<Canvas>().worldCamera = Camera.main;
    30.             obj.GetComponent<Canvas>().sortingOrder = 15;
    31.             obj.GetComponent<GridLayoutGroup>().cellSize = new Vector2(4, 1);
    32.             obj.GetComponent<GridLayoutGroup>().constraint = GridLayoutGroup.Constraint.FixedColumnCount;
    33.             obj.GetComponent<GridLayoutGroup>().constraintCount = 1;
    34.             obj.GetComponent<GridLayoutGroup>().spacing = new Vector2(0, -0.5f);
    35.  
    36.             for (int i = 0; i < gameObject.GetComponent<IsItem>().props.Count; i++)
    37.             {
    38.                 if (transform.GetChild(0))
    39.                 {
    40.                     _ = new GameObject(i.ToString());
    41.                     GameObject.Find(i.ToString()).transform.SetParent(transform.GetChild(0), true);
    42.                     transform.GetChild(0).GetChild(i).AddComponent<TextMeshProUGUI>();
    43.                     transform.GetChild(0).GetChild(i).GetComponent<TextMeshProUGUI>().text = gameObject.GetComponent<IsItem>().props[i].ToString();
    44.                     transform.GetChild(0).GetChild(i).GetComponent<TextMeshProUGUI>().fontSize = 0.3f;
    45.                 }
    46.             }
    47.         }
    48.     }
    49.  
    50.     private void OnMouseOver()
    51.     {
    52.         if (transform.childCount > 0)
    53.         {
    54.             if (Input.GetMouseButton(0))
    55.             {
    56.                 transform.GetChild(0).gameObject.SetActive(false);
    57.             }
    58.             else
    59.             {
    60.                 transform.GetChild(0).gameObject.SetActive(true);
    61.             }
    62.  
    63.             LayerMask mask = LayerMask.GetMask("Wrapper");
    64.  
    65.             if (Physics2D.Raycast(transform.position, Vector2.left, 5f, mask))
    66.             {
    67.                 transform.GetChild(0).localPosition = new Vector3(6, 0, 0);
    68.             }
    69.             else
    70.             {
    71.                 transform.GetChild(0).localPosition = new Vector3(-1, 0, 0);
    72.             }
    73.         }
    74.     }
    75.     private void OnMouseExit()
    76.     {
    77.         if (transform.childCount > 0)
    78.         {
    79.             transform.GetChild(0).gameObject.SetActive(false);
    80.             Destroy(transform.GetChild(0).gameObject);
    81.         }
    82.     }
    83. }
    84.  
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,656
    Wow... my goodness! You really are wasting a huge resource by not using the editor for stuff like this.

    This will make your game EXTREMELY hard to work with over time, until it solidifies into a solid black glass slag pile that you have no idea what is safe to touch.

    If you want to do it properly, checkout the attached example of a dynamic UI that can have arbitrary counts of things in a grid, with each having custom data.
     

    Attached Files:

    CodeSmile likes this.
  3. serjeq

    serjeq

    Joined:
    May 23, 2017
    Posts:
    24
    I will try. Its very hard for me to understand others people code.
    And by "dynamic" i mean my definition of it (which is misleading and wrong).
    My code simply show pop-up of item properties (which may differ if it is a armor or weapon .. etc) . Its working at least lol.

    Here is the code: (Not for a pop-up code. Its for my "static" always onscreen UI)
    I want remove text.text from Update() but if Health is changed, show updated value


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using TMPro;
    4. using Unity.VisualScripting.Antlr3.Runtime.Misc;
    5. using UnityEngine;
    6.  
    7. public class HealthUI : MonoBehaviour
    8. {
    9.     public PlayerManager playerManager;
    10.     TextMeshProUGUI text;
    11.  
    12.     public int Health;
    13.  
    14.  
    15.  
    16.     private void Start()
    17.     {
    18.         text = GetComponent<TextMeshProUGUI>();
    19.     }
    20.  
    21.     private void Update()
    22.     {
    23.         Health = playerManager.Health;
    24.         text.text = "Health   " + Health;
    25.     }
    26. }
    27.  
    I want remove it from Update()
     
  4. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,798
    I would recommend stepping away from legacy GameObject based UGUI. There's UI Toolkit, which has a visual UI Builder, and connecting things in code is almost trivial and if you take it one step further you even get bindings that automatically update values to and from the UI.
     
  5. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,797
    Question is, why do you want to remove it? Does it work? Is it creating too much overhead? If not, no need to overcomplicate the matter.

    But to answer your question, you just need to give some means for the UI to listen to the player. As a basic example the player could have an
    public event Action<int> OnHealthChanged;
    delegate that the UI hooks into.

    Then you have systems like UI Tookit which has a runtime bindings API on 2023.2 and beyond.
     
    Ryiah and CodeRonnie like this.