Unity предотвращает редактирование переменной через скрипт - PullRequest
0 голосов
/ 12 июля 2019

Я пытаюсь сделать всплывающую подсказку, когда наведу курсор мыши на кнопку.У меня были некоторые проблемы с вызовом основного потока из отдельного потока, поскольку основной поток - это единственный поток, из которого вы можете редактировать игровые объекты.Поэтому я решил использовать логическое значение и функцию обновления, чтобы получить желаемый результат.Однако я столкнулся с проблемой, которую никогда не видел прежде.Я устанавливаю для моего логического showToolTip значение true, которое должно вызывать всплывающую функцию создания.Однако к тому времени, когда моя функция обновления запускается, showTooltip всегда имеет значение false.Я знаю, когда я устанавливаю его в true, оно становится истинным, потому что я использовал операторы отладки в функции requestShowTooltip, чтобы увидеть это.Тем не менее, это всегда ложь при запуске функции обновления.Я провел несколько тестов, изменив showToolTip и removeToolTip на общедоступные логические значения.Я могу изменить их в редакторе во время работы приложения, и когда я вручную изменяю их через редактор, они работают на 100%, как и ожидалось, и всплывающая подсказка будет отображаться и скрываться при изменении соответствующих логических значений.Однако, когда они изменяются из сценария, они сохраняются как ложные.Я также попытался оставить их унифицированными и инициализировать их как false в начале, и у меня все еще была та же проблема.Я даже пытался взять "showTooltip = true;"из потока и просто наличие функции сделать это немедленно, и у меня все еще была та же проблема.showTooltip всегда ложно, когда вызывается функция обновления.Я определил это, добавив оператор отладки в функцию обновления, которая сообщает значение логических значений showTootip и removeTooltip.Более того, несмотря ни на что, «вызов вызова всплывающей подсказки» никогда не появляется в консоли.За исключением случаев, когда я обнародовал булевы значения и изменил их через редактор.

Некоторое дальнейшее объяснение того, как я это настроил.Я создал игровой объект всплывающей подсказки, который является дочерним элементом холста, содержащего кнопки, для которых требуется всплывающая подсказка.Я добавил сценарий подсказок к объекту подсказки.Я создал триггеры событий в кнопке Game Objects.триггер Pointer Enter вызывает функцию requestShowTooltip (), а триггер Pointer Exit вызывает функцию requestHideTooltip ().

Объекты фонового изображения всплывающей подсказки и текста всплывающей подсказки также являются дочерними элементами этого же холста.

public class Tooltips : MonoBehaviour
{
     private GameObject toolTipBackground;
     private GameObject toolTipText;
     private GameObject inButtonObject;

     private bool showTooltip = false;
     private bool removeTooltip = false;

     void Start()
     {
          toolTipBackground = GameObject.Find("Tooltip background");
          toolTipText = GameObject.Find("Tooltip Text");
          //inButton = GameObject.Find("Aft Button");

          toolTipBackground.SetActive(false);
          toolTipText.SetActive(false);

          //Debug.Log("Tool Tip Start");
     }

     void Update()
     {
          // show the tooltip when the appropriate boolean has been set 
          // to true
          if(removeTooltip)
          {
               hideTooltip();
          }
          // this if statement is always false, because showTooltip is 
          // always false when the update function is called??
          if(showTooltip)
          {

               Debug.Log("Calling create tooltip");
               createTooltip();
          }
     }

     // A timed request for a tooltip to show.  The tooltip should 
     // currently show one second after the request has been made.  The 
     // text of the tooltip will be equal to the passed object's name
     public void requestShowTooltip(GameObject inButtonObject)
     {
          Thread thread = new Thread(delegate ()
          { 
               System.Threading.Thread.Sleep(1000);
               this.inButtonObject = inButtonObject;

               // I know this runs, but showTooltip is always returning 
               // to false when the update function is called??
               showTooltip = true;

               removeTooltip = false;
               Debug.Log("Request function completed");
          });

          thread.start();
     }

     public void createTooltip()
     {
          toolTipText.SetActive(true);
          toolTipBackground.SetActive(true);

          string labelString = inButtonObject.name;

          Button inButton = inButtonObject.GetComponent<Button>();

          int width = labelString.Length * 10;
          int height = 35;

          Vector2 size = new Vector2(width, height);
          Vector3 position = new Vector3(inButton.transform.x, 
                                     inButton.transform.position.y,
                                     inButton.transform.position.z + 1);

          toolTipBackground.GetComponent<RectTransform>().
          sizeDelta = size;

          toolTipText.GetComponent<RectTransform>().sizeDelta = size;

          toolTipBackground.transform.position = position;
          toolTipText.transform.position = position;

          toolTipText.GetComponent<Text>().text = labelString;

          showTooltip = false;
     }

     public void requestHideTooltip()
     {
          removeTooltip = true;
          showTooltip = false;
     }

     public void hideTooltip()
     {
          Vector2 hide = new Vector2(0, 0);
          toolTipBackground.GetComponent<RectTransform>().
          sizeDelta = hide;
          toolTipText.GetComponent<RectTransform>().sizeDelta = hide;

          toolTipText.setActive(false);
          toolTopBackground.SetActive(false);

          removeTooltip = false;
          showTooltip = false;
     }

}

1 Ответ

0 голосов
/ 12 июля 2019

Так как в основном все в Unity нужно вызывать в главном потоке (за очень немногими исключениями), я бы предложил изменить ваш код, используя ConcurrentQueue<Action> и TryDequeue чтобы основной поток работал через все ответы из любого потока.

// a queue for storing actions that shall be handled by the main thread
// a ConcurrentQueue in specific is thread-save
private ConcurrentQueue<Action> actions = new ConcurrentQueue<Action>();

private void Update()
{
    // invoke all actions from the threads in the main thread
    while(!actions.IsEmpty)
    {
        // TryDequeue writes the first entry to currentAction
        // and at the same time removes it from the queue
        // if it was successfull invoke the action otherwise do nothing
        if(actions.TryDequeue(out var currentAction))
        {
            currentAction?.Invoke();
        } 
    }

    if(removeTooltip)
    {
         hideTooltip();
    }

    if(showTooltip)
    {
         Debug.Log("Calling create tooltip");
         createTooltip();
    }
}

Тогда в вашем Thread вместо того, чтобы заставить поток непосредственно выполнять сам материал, скорее передайте его обратно в основной поток, используя очередь actions, и добавьте новый Action в конец, используя Enqueue

public void requestShowTooltip(GameObject inButtonObject)
{
     Thread thread = new Thread(delegate()
     { 
          System.Threading.Thread.Sleep(1000);

          // add an Action to the end of the queue
          // e.g. as lambda-expression
          actions.Enqueue(()=>
          {
              this.inButtonObject = inButtonObject;

              // I know this runs, but showTooltip is always returning 
              // to false when the update function is called??
              showTooltip = true;

              removeTooltip = false;
              Debug.Log("Request function completed");
          });
     });

     thread.start();
}

Возможно, вы захотите сделать btw inButtonObject типа Button - во-первых, чтобы убедиться, что переданный объект всегда имеет / является Button, а во-вторых, вы можете избавиться от высокой производительности GetComponent вызов.

Точно так же, как я бы предпочел хранить

RectTransform toolTipBackgroundRectTransform;
Text toolTipText;
RectTransform toolTipTextrectTransform;

, так как это компоненты, которые вы можете получить уже один раз в Start, а затем вы можете повторно использовать одни и те же ссылки и избавиться от всех последующих вызовов GetComponent.

...