Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/unity3d/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为了打开/关闭游戏对象,这是比较游戏对象名称和输入字段文本的有效方法吗?_C#_Unity3d - Fatal编程技术网

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
简短回答:不!
  • 一般来说,如前所述:在
    更新
    =>每帧中执行而不是
    !(顺便说一句,也不是在
    FixedUpdate
    中运行频率较低,但仍然会添加完全不必要的调用)

    而是让代码由事件驱动。在您的情况下,您可以添加一个侦听器,该侦听器仅在值实际发生更改时才被调用,从而将方法CAL减少到必要的值

  • 然后,我宁愿在开始时将所有对象存储一次(或者根据您的需要,甚至可能是在您希望能够通过按钮名称访问按钮的情况下),这比每次调用该方法时反复检索列表更有效

  • 同样,使用
    FindObjectsWithTag
    是昂贵的,然后使用
    isChildOf
    进行过滤是更昂贵和不必要的,因为它基本上会递归地使
    转换冒泡。父级
    直到它找到给定值或
    null
    Transform
    实现一个
    IEnumerable
    返回所有子
    Transform
    s,这样您就可以使用
    foreach
    简单地迭代所有子对象。因此,相反,只迭代子对象并检查它们是否使用了标记

    当然,这取决于您的设置,因为如果给定对象是嵌套(深)子对象,那么
    isChildOf
    也会返回true。如果您的按钮实际连接了特定组件-就像我想的那样,例如,在本例中猜测一个
    按钮
    -您可以通过使用并迭代该按钮来克服此问题

  • 最后,对于比较字符串,有比简单地使用
    ==
    更有效、更安全的方法(请参阅)

    您可以使用

    或者-我更愿意-通过简单地使用

    或者在您需要的情况下,可以更定制地使用它

    其中对于可选(但推荐)参数
    比较类型
    ,您可以选择一个可用值,例如匹配不区分大小写等

所以我会用

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);