在运行时更改 Unity3D 预制图像
Change Unity3D prefab image during runtime
我有一个游戏中的物品清单,有图片和描述。
为了表示它,我想要一个带有网格的可滚动列表(用 UI canvas 制作,里面有一个滚动视图),网格的每个元素都是一个预制件,由UI 带有图像和文本的面板。
我已经尝试在脚本中以编程方式分配图像和文本的值:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PopulateGrid : MonoBehaviour
{
public GameObject prefab;
public Sprite mySprite;
private void Start()
{
Populate();
}
public void Populate()
{
GameObject newObj;
for (int i = 0; i < 20; i++)
{
newObj = (GameObject)Instantiate(prefab, transform); //prefab has image + text
newObj.GetComponentInChildren<Text>().text = "test" + i;
newObj.GetComponentInChildren<Image>().sprite = mySprite; //I've also tried .overrideSprite
}
}
}
有趣的是,文本得到正确更新,而图像没有。我正在以相同的方式访问它们,但其中一个按照我的意愿行事,而另一个则按照他的方式行事。
这是最终结果:
更新:更多细节!这是运行时的代码,显示图像精灵确实被分配了
这是我的检查员:
您确定 GetComponentInChildren 指向正确的图像组件吗?我会为您的预制件创建一个自定义 MonoBehaviour class,并创建一个指向正确图像的 SetImage() 方法。使用 GetComponentInChildren 时,它将 return 找到第一个组件,这可能会导致意外行为。
您可以在 newObj.GetComponentInChildren<Image>()
上进行调试以验证它是正确的组件。您的代码似乎没问题。
既然你说 Panel
对象本身也有一个 Image
组件你不想使用 GetComponentInChildren
因为它也 returns 任何 Image
附加到 newObj
本身!
您的代码没有抛出异常,而是将 mySprite
分配给 Panel
对象的 Image
组件,而不是其名为 Image
的子组件。
您要么必须使用例如
newObj.transform.GetChild(0).GetComponent<Image>()
或如上所述创建您自己的 class 并将其附加到预制件上,例如
public class TileController : Monobehaviour
{
// Reference these via the Inspector in the prefab
[SerializeField] private Text _text;
[SerializeField] private Image _image;
public void Initialize(Sprite sprite, String text)
{
_image.sprite = sprite;
_text.text = text;
}
}
然后
// using the correct type here makes sure you can only reference a GameObject
// that actually HAS the required component attached
[SerializeField] private TileController _prefab;
public void Populate()
{
TileController newObj;
for (int i = 0; i < 20; i++)
{
// no cast needed since Instantiate returns the type of the prefab anyway
newObj = Instantiate(_prefab, transform);
newObj.Initialize(mySprite, "test" + i);
}
}
我有一个游戏中的物品清单,有图片和描述。
为了表示它,我想要一个带有网格的可滚动列表(用 UI canvas 制作,里面有一个滚动视图),网格的每个元素都是一个预制件,由UI 带有图像和文本的面板。
我已经尝试在脚本中以编程方式分配图像和文本的值:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PopulateGrid : MonoBehaviour
{
public GameObject prefab;
public Sprite mySprite;
private void Start()
{
Populate();
}
public void Populate()
{
GameObject newObj;
for (int i = 0; i < 20; i++)
{
newObj = (GameObject)Instantiate(prefab, transform); //prefab has image + text
newObj.GetComponentInChildren<Text>().text = "test" + i;
newObj.GetComponentInChildren<Image>().sprite = mySprite; //I've also tried .overrideSprite
}
}
}
有趣的是,文本得到正确更新,而图像没有。我正在以相同的方式访问它们,但其中一个按照我的意愿行事,而另一个则按照他的方式行事。
这是最终结果:
更新:更多细节!这是运行时的代码,显示图像精灵确实被分配了
这是我的检查员:
您确定 GetComponentInChildren 指向正确的图像组件吗?我会为您的预制件创建一个自定义 MonoBehaviour class,并创建一个指向正确图像的 SetImage() 方法。使用 GetComponentInChildren 时,它将 return 找到第一个组件,这可能会导致意外行为。
您可以在 newObj.GetComponentInChildren<Image>()
上进行调试以验证它是正确的组件。您的代码似乎没问题。
既然你说 Panel
对象本身也有一个 Image
组件你不想使用 GetComponentInChildren
因为它也 returns 任何 Image
附加到 newObj
本身!
您的代码没有抛出异常,而是将 mySprite
分配给 Panel
对象的 Image
组件,而不是其名为 Image
的子组件。
您要么必须使用例如
newObj.transform.GetChild(0).GetComponent<Image>()
或如上所述创建您自己的 class 并将其附加到预制件上,例如
public class TileController : Monobehaviour
{
// Reference these via the Inspector in the prefab
[SerializeField] private Text _text;
[SerializeField] private Image _image;
public void Initialize(Sprite sprite, String text)
{
_image.sprite = sprite;
_text.text = text;
}
}
然后
// using the correct type here makes sure you can only reference a GameObject
// that actually HAS the required component attached
[SerializeField] private TileController _prefab;
public void Populate()
{
TileController newObj;
for (int i = 0; i < 20; i++)
{
// no cast needed since Instantiate returns the type of the prefab anyway
newObj = Instantiate(_prefab, transform);
newObj.Initialize(mySprite, "test" + i);
}
}