C# 为了打开/关闭游戏对象,这是比较游戏对象名称和输入字段文本的有效方法吗?
我试图做一个简单的搜索,并显示一个库存,不知道是否有更好的方法来做到这一点?这将附加到父游戏对象,并与输入字段一起使用,以比较字段中的文本和游戏对象的名称,以便显示和显示它们C# 为了打开/关闭游戏对象,这是比较游戏对象名称和输入字段文本的有效方法吗?,c#,unity3d,C#,Unity3d,我试图做一个简单的搜索,并显示一个库存,不知道是否有更好的方法来做到这一点?这将附加到父游戏对象,并与输入字段一起使用,以比较字段中的文本和游戏对象的名称,以便显示和显示它们 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using System.Linq; public class findFrame : MonoBehaviour {
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Linq;
public class findFrame : MonoBehaviour
{
public InputField searchText;
void Find()
{
var found = new List<GameObject>(GameObject.FindGameObjectsWithTag("Button")).Where(g => g.transform.IsChildOf(this.transform));
foreach (GameObject g in found)
{
Debug.Log("hello");
if (g.transform.name != searchText.text)
{
gameObject.SetActive(false);
}
else
{
gameObject.SetActive(true);
}
}
}
void Update()
{
Find();
}
}
使用系统集合;
使用System.Collections.Generic;
使用UnityEngine;
使用UnityEngine.UI;
使用System.Linq;
公共类findFrame:单行为
{
公共输入字段搜索文本;
void Find()
{
var found=新列表(GameObject.FindGameObjectsWithTag(“按钮”))。其中(g=>g.transform.IsChildOf(this.transform));
foreach(找到游戏对象g)
{
Log(“hello”);
if(g.transform.name!=searchText.text)
{
gameObject.SetActive(false);
}
其他的
{
gameObject.SetActive(true);
}
}
}
无效更新()
{
查找();
}
}
在Unity中,更新功能每一帧运行一次
因此,在这里进行字符串比较可能不是最好的主意
您可能希望在更新中获取用户输入,然后在以固定帧速率执行的FixeUpdate中执行一些计算
除此之外。。。在Unity中,使用CompareTag方法可以更好地完成您正在做的事情
Unity编译器以“特殊”方式编译此方法,以避免字符串分配等。。基本上是针对性能进行优化的
以下是一些可能有助于您清理水域的链接:
在本示例中,在浏览器中搜索CompareTag以准确查看您的情况:
最后,如果您真的需要比较两个字符串。。。最快的方法很可能是这样:
string.CompareOrdinal(myString1, myString2) == 0 //this means equals
string.CompareOrdinal(myString1, myString2) != 0 //this means not equals
简短回答:不!
- 一般来说,如前所述:在
更新
=>每帧中执行而不是
!(顺便说一句,也不是在
中运行频率较低,但仍然会添加完全不必要的调用) 而是让代码由事件驱动。在您的情况下,您可以添加一个侦听器,该侦听器仅在值实际发生更改时才被调用,从而将方法CAL减少到必要的值FixedUpdate
- 然后,我宁愿在开始时将所有对象存储一次(或者根据您的需要,甚至可能是在您希望能够通过按钮名称访问按钮的情况下),这比每次调用该方法时反复检索列表更有效
- 同样,使用
是昂贵的,然后使用FindObjectsWithTag
进行过滤是更昂贵和不必要的,因为它基本上会递归地使isChildOf
直到它找到给定值或转换冒泡。父级
null
实现一个Transform
返回所有子IEnumerable
s,这样您就可以使用Transform
简单地迭代所有子对象。因此,相反,只迭代子对象并检查它们是否使用了标记 当然,这取决于您的设置,因为如果给定对象是嵌套(深)子对象,那么foreach
也会返回true。如果您的按钮实际连接了特定组件-就像我想的那样,例如,在本例中猜测一个isChildOf
-您可以通过使用并迭代该按钮来克服此问题按钮
- 最后,对于比较字符串,有比简单地使用
更有效、更安全的方法(请参阅) 您可以使用 或者-我更愿意-通过简单地使用 或者在您需要的情况下,可以更定制地使用它 其中对于可选(但推荐)参数==
,您可以选择一个可用值,例如匹配不区分大小写等比较类型
public class findFrame : MonoBehaviour
{
public InputField searchText;
// A HashSet is basically a list but makes sure every element is unique
// I would make this rather a Dictionary<string, GameObject> in case
// you also plan to access a specific button by name
// otherwise a HashSet does it
private HashSet<GameObject> childButtons = new HashSet<GameObject>();
public void Awake()
{
//Adds a listener to the input field and invokes a method when the value changes.
searchText.onValueChanged.AddListener(OnValueChanged);
// Run through all children GameObjects of this GameObject and check the tag
foreach(Transform child in transform)
// or as said if possible/necessary for nested children you could use
//foreach(var child in GetComponentsInChildren<Button>())
{
// check if this child has the correct tag
if(!child.CompareTag("Button")) continue;
// If the tag matches add it to the HashSet
childButtons.Add(child.gameObject);
}
}
// Invoked when the value of the text field changes.
public void OnValueChanged()
{
Debug.Log("Value Changed");
// Get the search value
var searchString = searchTexxt.text;
// Simply run through the HashSet and set the matching object(s) active, the others inactive
foreach(var button in childButtons)
{
// Skip null entries
if(!button) continue;
var name = button.name;
// Here as said you can either check for an exact match
//var isMatch = name.Equals(searchString, COMPARISONTYPE);
// Or you could also check for partial matches - I would prefer this
// (required if you want to see objects also while the user didn't type out the full name yet)
// either by simply using Contains
//var isMatch = name.Contains(searchString);
// or if you need it more customized
var isMatch = string.Compare(name, searchString, COMPARISONTYPE) == 0;
button.SetActive(isMatch);
if(isMatch) Debug.Log($"Found match for {searchString} in button ${name} ");
}
}
// When creating the buttons on runtime call this to also add them to the HashSet
public void AddButton(GameObject button)
{
if(childButtons.Contains(button)) return;
childButtons.Add(button);
}
}
一般来说,如果您的代码正常工作,并且您正在找人查看它,那么您会希望继续询问。如果你选择这样做,请在发帖前阅读它们。我不同意@TiesonT。。。。。当涉及到游戏引擎时,代码可能不像人们预期的那样“表现”。不,这可能不是比较不断执行的Update函数中字符串的最佳方法。。。。在Unity中,您可能希望使用objects标记进行比较,因为Unity在编译期间对Component.CompareTag或GameObject.CompareTag方法执行它的“魔力”,以避免不必要的内存分配。。。。如果你真的要比较两个字符串,最快的方法就是使用string.CompareOrdinal(g.transform.name,searchText.text)!=0但通常在Unity中,最快的方法是使用objects标记和CompareTag方法。。。。所以如果我是你。。。我会设置要比较的对象的标记,并可能使用类似于g.CompareTag(searchText.text)@JonathanAlfaro的标记。如果您不同意这样做更适合代码审查的建议,请添加一个答案,解释代码的错误以及应该如何纠正它。@TiesonT。完成。。。这是团结中的一个众所周知的问题。谢谢!我一直在思考如何在运行时添加按钮,因为这实际上就是我正在做的。你有没有可能建议这样做的方法?每个按钮都需要能够访问hashset yes?作为参考,只是为了测试我将Awake改为Update,它可以工作(当然,场景会变得很慢)。也许我需要把“/”放在这个游戏对象的所有子游戏对象上,然后检查标签“等等”。。在函数中,然后调用
var isMatch = name.Contains(searchString);
var isMatch = string.Compare(name, searchString, COMPARISONTYPE)
public class findFrame : MonoBehaviour
{
public InputField searchText;
// A HashSet is basically a list but makes sure every element is unique
// I would make this rather a Dictionary<string, GameObject> in case
// you also plan to access a specific button by name
// otherwise a HashSet does it
private HashSet<GameObject> childButtons = new HashSet<GameObject>();
public void Awake()
{
//Adds a listener to the input field and invokes a method when the value changes.
searchText.onValueChanged.AddListener(OnValueChanged);
// Run through all children GameObjects of this GameObject and check the tag
foreach(Transform child in transform)
// or as said if possible/necessary for nested children you could use
//foreach(var child in GetComponentsInChildren<Button>())
{
// check if this child has the correct tag
if(!child.CompareTag("Button")) continue;
// If the tag matches add it to the HashSet
childButtons.Add(child.gameObject);
}
}
// Invoked when the value of the text field changes.
public void OnValueChanged()
{
Debug.Log("Value Changed");
// Get the search value
var searchString = searchTexxt.text;
// Simply run through the HashSet and set the matching object(s) active, the others inactive
foreach(var button in childButtons)
{
// Skip null entries
if(!button) continue;
var name = button.name;
// Here as said you can either check for an exact match
//var isMatch = name.Equals(searchString, COMPARISONTYPE);
// Or you could also check for partial matches - I would prefer this
// (required if you want to see objects also while the user didn't type out the full name yet)
// either by simply using Contains
//var isMatch = name.Contains(searchString);
// or if you need it more customized
var isMatch = string.Compare(name, searchString, COMPARISONTYPE) == 0;
button.SetActive(isMatch);
if(isMatch) Debug.Log($"Found match for {searchString} in button ${name} ");
}
}
// When creating the buttons on runtime call this to also add them to the HashSet
public void AddButton(GameObject button)
{
if(childButtons.Contains(button)) return;
childButtons.Add(button);
}
}
// In another script you need the reference to the `findFrame` component
// Drag it in here via the Inspector
[SerializeField] findFrame findFrameReference;
// As fallback find it on runtime (in case there is only one in the scene
private void Awake ()
{
if(! findFrameReference) findFrameReference = FindObjectOfType<findFrame>();
}
var button = Instantiate(buttonPrefab, ...);
findFrameReference.AddButton(button.gameObject);