String.Format displaying old instanced data from SerializeField data - How to fix?

Viewed 83

I am trying to display a tooltip in Unity at runtime that contains the following information:

Spell Name (string)
Cast Time (float)
Damage (int)
Description (string)

I have everything setup properly in the scripts and the tooltip GetDescription() function is properly pulling the information it needs for Spell Name, Cast Time, and Damage from serialized fields that has the information it needs. However, the Description serialized field, despite being populated, is not displaying in the tooltip.

When I put a Debug.Log(description) line into the function, the console shows that the contents of description is empty. I have the description stored in a string called "description" and it is a [SerializeField] so that the description can be set in the Unity Inspector. This is the same approach to how I am storing the other spell information (spell name, cast time, and damage).

When I run the game build and goto the hierarchy where the tooltip text field is located, I can visually confirm that the contents of the "description" string is not being appended to the text field (I am using a Rich Text enabled field).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

[Serializable]
public class Spell : IUseable, IMoveable, IDescribable
{
    [SerializeField]
    private string name;

    [SerializeField]
    private int damage;

    [SerializeField]
    private float castTime;

    [SerializeField]
    private string description;

    public string GetDescription()
    {
        return string.Format("{0}\n Cast time: {1} second(s) 
            \n Damage:{2} \n {3}", name, castTime, damage, description);
    }
}

When I run the build and try the tooltip, I get something like this:

Explosion
Cast Time: 2.5 second(s)
Damage: 5

It should be displaying something like this, though:

Explosion
Cast Time: 2.5 second(s)
Damage: 5
Creates a powerful explosion, injuring those caught in its blast.

Update:

private void Awake()
{
    toolTipTitle = toolTip.GetComponentInChildren<Text>();
}

public void ShowTooltip(Vector3 position, IDescribable description)
{
    toolTip.SetActive(true);
    toolTip.transform.position = position;
    toolTipTitle.text = description.GetDescription();
}

Update:

I attached a Debug.Log to the ShowTooltip() function to see the contents of description.GetDescription() and it is indeed referring to an old instance of the data in the serialized field (which I changed to FireTest with a 10 second cast time).

Explosion
Cast time: 2.5 second(s)
Damage:5

UnityEngine.Debug:Log(Object)
UIManager:ShowTooltip(Vector3, IDescribable) (at Assets/Scripts/Managers/UIManager.cs:179)
ActionButton:OnPointerEnter(PointerEventData) (at Assets/Scripts/Buttons/ActionButton.cs:151)
UnityEngine.EventSystems.EventSystem:Update()

Update:

After attaching some Debug.Log commands, it looks like the code is referencing an old instance of the data contained within the SerializeFields for name, castTime, and damage. This old instance doesn't have a description field, which explains why it is not being added to the tooltip. Looking for advice on how to force the code to reacquire the data it needs from the SerializeFields instead of relying on what appears to be cached data values (not sure how that is even possible, to be honest... but this cached data is also appearing in other places that should be pulling data from these fields such as a Casting Bar that displays the spell name and counts down the casting time and testing shows the casting bar using old instanced data and not data from the spellbook. Attaching the code from the spellbook as well as the actionbutton below for reference:

CODE: ActionButton.cs

public class ActionButton : MonoBehaviour, IPointerClickHandler, IClickable, IPointerEnterHandler, IPointerExitHandler
{

    public IUseable MyUseable { get; set; }

    [SerializeField]
    private Text stackSize;

    private Stack<IUseable> useables = new Stack<IUseable>();

    private int count;

    public Button MyButton { get; private set; }

    public Image MyIcon
    {
        get
        {
            return icon;
        }

        set
        {
            icon = value;
        }
    }

    public int MyCount
    {
        get
        {
            return count;
        }
    }

    public Text MyStackText
    {
        get
        {
            return stackSize;
        }
    }    

    [SerializeField]
    private Image icon;

    // Use this for initialization
    void Start ()
    {
        MyButton = GetComponent<Button>();
        MyButton.onClick.AddListener(OnClick);
        InventoryScript.MyInstance.itemCountChangedEvent += new ItemCountChanged(UpdateItemCount);
    }

    // Update is called once per frame
    void Update ()
    {

    }

    public void OnClick()
    {
        if (HandScript.MyInstance.MyMoveable == null)
        {
            if (MyUseable != null)
            {
                MyUseable.Use();
            }
            if (useables != null && useables.Count > 0)
            {
                useables.Peek().Use();
            }
        }        
    }

    public void OnPointerClick(PointerEventData eventData)
    {
        if (eventData.button == PointerEventData.InputButton.Left)
        {
            if (HandScript.MyInstance.MyMoveable != null && HandScript.MyInstance.MyMoveable is IUseable)
            {
                SetUseable(HandScript.MyInstance.MyMoveable as IUseable);
            }
        }
    }

    public void SetUseable(IUseable useable)
    {
        if (useable is Item)
        {
            useables = InventoryScript.MyInstance.GetUseables(useable);
            count = useables.Count;
            InventoryScript.MyInstance.FromSlot.MyIcon.color = Color.white;
            InventoryScript.MyInstance.FromSlot = null;
        }
        else
        {
            this.MyUseable = useable;
        }        

        UpdateVisual();
    }

    public void UpdateVisual()
    {
        MyIcon.sprite = HandScript.MyInstance.Put().MyIcon;
        MyIcon.color = Color.white;

        if (count > 1)
        {
            UIManager.MyInstance.UpdateStackSize(this);
        }
    }

    public void UpdateItemCount(Item item)
    {
        if (item is IUseable && useables.Count > 0)
        {
            if (useables.Peek().GetType() == item.GetType())
            {
                useables = InventoryScript.MyInstance.GetUseables(item as IUseable);

                count = useables.Count;

                UIManager.MyInstance.UpdateStackSize(this);
            }
        }
    }

    public void OnPointerEnter(PointerEventData eventData)
    {
        IDescribable tmp = null;

        if (MyUseable != null && MyUseable is IDescribable)
        {
            tmp = (IDescribable)MyUseable;
            // Need to implement!
            // UIManager.MyInstance.ShowTooltip(transform.position);
        }
        else if (useables.Count > 0)
        {
            // Need to implement!
            // UIManager.MyInstance.ShowTooltip(transform.position);
        }
        if (tmp != null)
        {
            UIManager.MyInstance.ShowTooltip(transform.position, tmp);
        }
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        UIManager.MyInstance.HideTooltip();
    }
}

CODE: SpellBook.cs

public class SpellBook : MonoBehaviour
{

    private static SpellBook instance;

    public static SpellBook MyInstance
    {
        get
        {
            if (instance == null)
            {
                instance = FindObjectOfType<SpellBook>();
            }

            return instance;
        }
    }

    [SerializeField]
    private Image castingBar;

    [SerializeField]
    private Text currentSpell;

    [SerializeField]
    private Text castTime;

    [SerializeField]
    private Image icon;

    [SerializeField]
    private CanvasGroup canvasGroup;

    [SerializeField]
    private Spell[] spells;

    private Coroutine spellRoutine;

    private Coroutine fadeRoutine;


    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }

    public Spell CastSpell(string spellName)
    {
        Spell spell = Array.Find(spells, x => x.MyName == spellName);

        castingBar.fillAmount = 0;

        castingBar.color = spell.MyBarColor;

        currentSpell.text = spell.MyName;

        icon.sprite = spell.MyIcon;

        spellRoutine = StartCoroutine(Progress(spell));

        fadeRoutine = StartCoroutine(FadeBar());

        return spell;
    }

    private IEnumerator Progress(Spell spell)
    {
        float timePassed = Time.deltaTime;

        float rate = 1.0f / spell.MyCastTime;

        float progress = 0.0f;

        while (progress <= 1.0)
        {
            castingBar.fillAmount = Mathf.Lerp(0, 1, progress);

            progress += rate * Time.deltaTime;

            timePassed += Time.deltaTime;

            castTime.text = (spell.MyCastTime - timePassed).ToString("F2");

            if (spell.MyCastTime - timePassed < 0)
            {
                castTime.text = "0.00";
            }

            yield return null;
        }

        StopCasting();
    }

    private IEnumerator FadeBar()
    {
        float rate = 1.0f / 0.50f;

        float progress = 0.0f;

        while (progress <= 1.0)
        {
            canvasGroup.alpha = Mathf.Lerp(0, 1, progress);

            progress += rate * Time.deltaTime;

            yield return null;
        }
    }

    public void StopCasting()
    {
        if (fadeRoutine != null)
        {
            StopCoroutine(fadeRoutine);
            canvasGroup.alpha = 0;
            fadeRoutine = null;
        }
        if (spellRoutine != null)
        {
            StopCoroutine(spellRoutine);
            spellRoutine = null;
        }
    }

    public Spell GetSpell(string spellName)
    {
        Spell spell = Array.Find(spells, x => x.MyName == spellName);

        return spell;
    }
}
1 Answers

Figured it out - I had accidentally created a clone of the script field data in another game object and the game was using that instead. Closing this out as answered - thank you so much for the help! =)

Related