使用 foreach 循环查找作为其他对象的子对象的游戏对象 (Unity3d)
Using foreach loop to find GameObjects that are children of something else (Unity3d)
我正在制作视频游戏,虽然我有通用 C# 的现有代码,但我现在必须将其移至 Unity。我对通用 C# 有一些基础知识,但我才刚刚开始学习 Unity 编码方式。
首先,我想编写一个代码,将所有游戏区域定位到正确的位置,然后将它们隐藏。是的,不要惊讶,他们需要都在同一个地方。
区域可以有三种尺寸选择,我称之为小、中、大。大小区都得手动写
List <GameObject> SmallAreas = new List<GameObject>();
void DefineSmallAreas()
{
SmallAreas.Add(areaConfirmLoad);
SmallAreas.Add(areaConfirmQuit);
SmallAreas.Add(areaConfirmSave);
SmallAreas.Add(areaGameSaved);
SmallAreas.Add(areaSave);
SmallAreas.Add(areaLoad);
}
大面积也一样
现在其他地区都是中等的,而且数量很多。
所以,我想遍历 "areaContainer" 的所有子游戏对象,检查它们的名称是否以 "area" 开头,如果是,我想将它们添加到 MediumAreas 列表。
我就是这样试的:
void DefineMediumAreas()
{
GameObject areaContainer = GameObject.Find("areaContainer");
foreach (GameObject thisObject in areaContainer)
{
char[] a = thisObject.Name.ToCharArray();
if (a.Length >= 4)
{
char[] b = { a[0], a[1], a[2], a[3] };
string thisObjectType = new string(b);
(if (thisObjectType == "area")&&(!(SmallAreas.Contains(thisObject))
&&(!(LargeAreas.Contains(thisObject)))
{
MediumAreas.Add(thisObject);
}
}
}
然而,这显示了一个错误,即 "areaContainer" 不能那样使用,我现在无法访问 Unity,因此无法复制确切的消息。我认为它类似于 "Gameobject doesn't have IEnumerator".
我确实尝试 google 以获得更好的方法,并找到了一个叫做 "transform" 的东西。
foreach(Transform child in transform)
{
Something(child.gameObject);
}
我不明白的是如何在我的具体情况下使用这个 "transform"。
如果这个问题很傻,请不要生我的气,我是Unity的新手,必须从头开始学习。
还有一个小的第二个问题。这个把对象变成隐形的工作能行吗:
foreach(GameObject thisObject in MediumAreas)
{
thisObject.position = MediumVector;
thisObject.GetComponent<Renderer>().enabled = false;
}
MediumVector 是对象必须移动到的位置,它似乎在工作。
有多种方法可以解决您的问题。其中之一是使用 Tags。只需用一些标签标记您的 MediumArea 预制件,然后您就可以找到所有带有 FindGameObjectsWithTag(string)
(Unity Docs) 标记的游戏对象。然后你可以像这样填充你的collection:
MediumAreas.AddRange(FindGameObjectsWithTag("MediumArea"));
第二种方法可能是找到所有具有相同附加脚本 FindObjectsOfType<T>()
(Unity Docs) 的 objects。这在您搜索相同类型的实例时很有用,例如 Medium Area.
假设您有一个 Area 脚本
public class Area : MonoBehaviour {
public AreaSize Size; // AreaSize is Enum
}
然后您可以简单地找到您的区域,例如:
var allAreas = FindGameObjectsOfType<Area>();
var mediumAreas = allAreas.Where(e => e.Size == AreaSize.Medium); // using System.Linq;
你可以这样做:foreach(Transform child in transform)
因为 Transform
class 实现了 IEnumerable
并且有一些机制可以让您使用 foreach
循环访问子游戏对象。
很遗憾,您不能这样做:foreach (GameObject thisObject in areaContainer)
因为 areaContainer
是 GameObject
并且此实现未针对 GameObject
class 完成。这就是您收到此错误的原因:
foreach statement cannot operate on variables of type
'UnityEngine.GameObject' because 'UnityEngine.GameObject' does not
contain a public definition for 'GetEnumerator'
要修复它,请在找到 GameObject
:
后将循环更改为使用 Transform
GameObject areaContainer = GameObject.Find("areaContainer");
foreach (Transform thisObject in areaContainer.transform){}
完整代码:
List<GameObject> MediumAreas = new List<GameObject>();
void DefineMediumAreas()
{
GameObject areaContainer = GameObject.Find("areaContainer");
foreach (Transform thisObject in areaContainer.transform)
{
//Check if it contains area
if (thisObject.name.StartsWith("area"))
{
//Add to MediumAreas List
MediumAreas.Add(thisObject.gameObject);
}
}
}
您想访问 "areaContainer"
的所有子游戏对象
在void DefineMediumAreas()
函数中,需要Transform[]
得到子数组。使用这个:
Transform[] areaContainer = GameObject.Find("areaContainer").GetComponentsInChildren<Transform>();
foreach(Transform thisTransform in areaContainer)
{
...
}
希望对你有帮助
我创建了一个项目来回答你的问题,最终结果是这样的:
如您所见,我创建了一个名为 "areaContainer" 的游戏 object 并添加了 3 个 children,其名称分别为:"area01"、"area02" 和"anotherObject".
设法获取所有以 "area" 开头的 "areaContainer" children 的脚本如下所示:
public GameObject areaContainer;
public List<GameObject> MediumAreas = new List<GameObject>();
private void Start()
{
DefineMediumAreas();
}
void DefineMediumAreas()
{
for (int i = 0; i < areaContainer.transform.childCount; i++)
{
var childGameObject = areaContainer.transform.GetChild(i).gameObject;
if (childGameObject.name.StartsWith("area"))
MediumAreas.Add(childGameObject);
}
}
1- 我最终在脚本中引用了 areaContainer object 而不是使用 GameObject.Find,因为它的性能更高。
2- 要获得游戏 object 的 child,您需要访问其转换并调用 GetChild(index)。因此,通过迭代 parent 容器,即 "areaContainer",我们得到它的 childCount.
3- 要检查名称是否以 "area" 开头,只需使用 .StartsWith("area") 其中 return true 或 false.
对于第二个问题,您可以隐藏 object 禁用渲染器或停用它 (thisObject.SetActive(false);
希望对您有所帮助;编码愉快!
我正在制作视频游戏,虽然我有通用 C# 的现有代码,但我现在必须将其移至 Unity。我对通用 C# 有一些基础知识,但我才刚刚开始学习 Unity 编码方式。
首先,我想编写一个代码,将所有游戏区域定位到正确的位置,然后将它们隐藏。是的,不要惊讶,他们需要都在同一个地方。
区域可以有三种尺寸选择,我称之为小、中、大。大小区都得手动写
List <GameObject> SmallAreas = new List<GameObject>();
void DefineSmallAreas()
{
SmallAreas.Add(areaConfirmLoad);
SmallAreas.Add(areaConfirmQuit);
SmallAreas.Add(areaConfirmSave);
SmallAreas.Add(areaGameSaved);
SmallAreas.Add(areaSave);
SmallAreas.Add(areaLoad);
}
大面积也一样
现在其他地区都是中等的,而且数量很多。
所以,我想遍历 "areaContainer" 的所有子游戏对象,检查它们的名称是否以 "area" 开头,如果是,我想将它们添加到 MediumAreas 列表。
我就是这样试的:
void DefineMediumAreas()
{
GameObject areaContainer = GameObject.Find("areaContainer");
foreach (GameObject thisObject in areaContainer)
{
char[] a = thisObject.Name.ToCharArray();
if (a.Length >= 4)
{
char[] b = { a[0], a[1], a[2], a[3] };
string thisObjectType = new string(b);
(if (thisObjectType == "area")&&(!(SmallAreas.Contains(thisObject))
&&(!(LargeAreas.Contains(thisObject)))
{
MediumAreas.Add(thisObject);
}
}
}
然而,这显示了一个错误,即 "areaContainer" 不能那样使用,我现在无法访问 Unity,因此无法复制确切的消息。我认为它类似于 "Gameobject doesn't have IEnumerator".
我确实尝试 google 以获得更好的方法,并找到了一个叫做 "transform" 的东西。
foreach(Transform child in transform)
{
Something(child.gameObject);
}
我不明白的是如何在我的具体情况下使用这个 "transform"。
如果这个问题很傻,请不要生我的气,我是Unity的新手,必须从头开始学习。
还有一个小的第二个问题。这个把对象变成隐形的工作能行吗:
foreach(GameObject thisObject in MediumAreas)
{
thisObject.position = MediumVector;
thisObject.GetComponent<Renderer>().enabled = false;
}
MediumVector 是对象必须移动到的位置,它似乎在工作。
有多种方法可以解决您的问题。其中之一是使用 Tags。只需用一些标签标记您的 MediumArea 预制件,然后您就可以找到所有带有 FindGameObjectsWithTag(string)
(Unity Docs) 标记的游戏对象。然后你可以像这样填充你的collection:
MediumAreas.AddRange(FindGameObjectsWithTag("MediumArea"));
第二种方法可能是找到所有具有相同附加脚本 FindObjectsOfType<T>()
(Unity Docs) 的 objects。这在您搜索相同类型的实例时很有用,例如 Medium Area.
假设您有一个 Area 脚本
public class Area : MonoBehaviour {
public AreaSize Size; // AreaSize is Enum
}
然后您可以简单地找到您的区域,例如:
var allAreas = FindGameObjectsOfType<Area>();
var mediumAreas = allAreas.Where(e => e.Size == AreaSize.Medium); // using System.Linq;
你可以这样做:foreach(Transform child in transform)
因为 Transform
class 实现了 IEnumerable
并且有一些机制可以让您使用 foreach
循环访问子游戏对象。
很遗憾,您不能这样做:foreach (GameObject thisObject in areaContainer)
因为 areaContainer
是 GameObject
并且此实现未针对 GameObject
class 完成。这就是您收到此错误的原因:
foreach statement cannot operate on variables of type 'UnityEngine.GameObject' because 'UnityEngine.GameObject' does not contain a public definition for 'GetEnumerator'
要修复它,请在找到 GameObject
:
Transform
GameObject areaContainer = GameObject.Find("areaContainer");
foreach (Transform thisObject in areaContainer.transform){}
完整代码:
List<GameObject> MediumAreas = new List<GameObject>();
void DefineMediumAreas()
{
GameObject areaContainer = GameObject.Find("areaContainer");
foreach (Transform thisObject in areaContainer.transform)
{
//Check if it contains area
if (thisObject.name.StartsWith("area"))
{
//Add to MediumAreas List
MediumAreas.Add(thisObject.gameObject);
}
}
}
您想访问 "areaContainer"
的所有子游戏对象在void DefineMediumAreas()
函数中,需要Transform[]
得到子数组。使用这个:
Transform[] areaContainer = GameObject.Find("areaContainer").GetComponentsInChildren<Transform>();
foreach(Transform thisTransform in areaContainer)
{
...
}
希望对你有帮助
我创建了一个项目来回答你的问题,最终结果是这样的:
如您所见,我创建了一个名为 "areaContainer" 的游戏 object 并添加了 3 个 children,其名称分别为:"area01"、"area02" 和"anotherObject".
设法获取所有以 "area" 开头的 "areaContainer" children 的脚本如下所示:
public GameObject areaContainer;
public List<GameObject> MediumAreas = new List<GameObject>();
private void Start()
{
DefineMediumAreas();
}
void DefineMediumAreas()
{
for (int i = 0; i < areaContainer.transform.childCount; i++)
{
var childGameObject = areaContainer.transform.GetChild(i).gameObject;
if (childGameObject.name.StartsWith("area"))
MediumAreas.Add(childGameObject);
}
}
1- 我最终在脚本中引用了 areaContainer object 而不是使用 GameObject.Find,因为它的性能更高。
2- 要获得游戏 object 的 child,您需要访问其转换并调用 GetChild(index)。因此,通过迭代 parent 容器,即 "areaContainer",我们得到它的 childCount.
3- 要检查名称是否以 "area" 开头,只需使用 .StartsWith("area") 其中 return true 或 false.
对于第二个问题,您可以隐藏 object 禁用渲染器或停用它 (thisObject.SetActive(false);
希望对您有所帮助;编码愉快!