【发布时间】:2018-12-20 00:14:44
【问题描述】:
我正在尝试在运行时在 Unity 中显示一个工具提示,其中包含以下信息:
Spell Name (string)
Cast Time (float)
Damage (int)
Description (string)
我在脚本中正确设置了所有内容,工具提示 GetDescription() 函数正确地从具有所需信息的序列化字段中提取其所需的 Spell Name、Cast Time 和 Damage 信息。但是,尽管已填充描述序列化字段,但未显示在工具提示中。
当我将 Debug.Log(description) 行放入函数时,控制台显示 description 的内容为空。我将描述存储在一个名为“description”的字符串中,它是一个 [SerializeField],以便可以在 Unity Inspector 中设置描述。这与我存储其他法术信息(法术名称、施法时间和伤害)的方法相同。
当我运行游戏构建并转到工具提示文本字段所在的层次结构时,我可以直观地确认“描述”字符串的内容没有附加到文本字段(我使用的是启用富文本字段)。
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);
}
}
当我运行构建并尝试工具提示时,我得到如下内容:
爆炸
施法时间:2.5 秒
伤害:5
不过,它应该显示如下内容:
爆炸
施法时间:2.5 秒
伤害:5
产生强大的爆炸,伤害被爆炸的人。
更新:
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();
}
更新:
我在 ShowTooltip() 函数中附加了一个 Debug.Log 以查看 description.GetDescription() 的内容,它确实指的是序列化字段中数据的旧实例(我将其更改为 FireTest 并使用 10第二次施法时间)。
爆炸
施法时间:2.5 秒
伤害:5UnityEngine.Debug:Log(Object)
UIManager:ShowTooltip(Vector3, IDescribable) (在 Assets/Scripts/Managers/UIManager.cs:179)
ActionButton:OnPointerEnter(PointerEventData) (在 资产/脚本/按钮/ActionButton.cs:151)
UnityEngine.EventSystems.EventSystem:Update()
更新:
附加一些 Debug.Log 命令后,看起来代码正在引用 SerializeFields 中包含的数据的旧实例,以获取名称、castTime 和损坏。这个旧实例没有描述字段,这解释了为什么它没有被添加到工具提示中。寻找有关如何强制代码从 SerializeFields 重新获取所需数据的建议,而不是依赖似乎缓存的数据值(说实话,不知道这怎么可能……但是这个缓存的数据也是出现在应该从这些字段中提取数据的其他地方,例如显示法术名称并倒计时施法时间的施法栏,测试显示施法栏使用旧的实例数据而不是来自法术书的数据。法术书以及下面的操作按钮供参考:
代码: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();
}
}
代码: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;
}
}
【问题讨论】:
-
听起来你的问题不是
String.Format没有显示所有元素,而是你的description字段没有从检查器中持久化。我不知道为什么会有所不同,但出于好奇,您是否尝试过将description重命名为其他名称(例如inspectorTest)? -
是的,我尝试将其重命名为其他名称,但没有任何区别。为了增加谜团,我尝试更改其他字段的值(名称、伤害和施法时间)......并且工具提示继续显示原始值。我运行了所有脚本,这些字段没有硬编码值,工具提示 GetDescription() 专门从这些字段中提取数据,但它没有显示更新的数据,而是坚持显示那里的数据以前(同时也忽略了描述)。
-
你能在工具提示调用
GetDescription()方法的地方添加你的代码吗? -
private void Awake() { toolTipTitle = toolTip.GetComponentInChildren
(); } public void ShowTooltip(Vector3 position, IDescribable description) { toolTip.SetActive(true); toolTip.transform.position = 位置; toolTipTitle.text = description.GetDescription(); -
对代码的显示方式感到抱歉 - 尝试对其进行编辑以使其更具可读性,但不确定如何使其看起来正确。 :(
标签: unity3d serialization string.format