【问题标题】:How can I check to avoid gameobject duplication in the hierarchy?如何检查以避免层次结构中的游戏对象重复?
【发布时间】:2019-08-27 17:50:44
【问题描述】:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;

[ExecuteAlways]
public class AddTextToObject : MonoBehaviour
{
    public UnityEngine.GameObject[] objectsToNumber;
    public UnityEngine.GameObject text;
    public float yPadding;
    public bool rotateNumbers = false;
    public float rotationSpeed = 10f;
    public bool textAbove = false;
    public bool textInFront = false;
    public bool textOnFaces = false;

    private List<GameObject> newTexts = new List<GameObject>();
    private MeshRenderer[] renderer;
    private Vector3 newPos;

    private void Start()
    {
        renderer = new MeshRenderer[objectsToNumber.Length];

        for (int i = 0; i < objectsToNumber.Length; i++)
        {
            GameObject newText = Instantiate(text);
            renderer[i] = newText.GetComponent<MeshRenderer>();

            if (textAbove == true)
            {
                newPos = new Vector3
                (
                 objectsToNumber[i].transform.position.x,
                 ((objectsToNumber[i].transform.position.y + renderer[i].bounds.extents.y) + yPadding),
                   objectsToNumber[i].transform.position.z
                 );
            }

            if (textInFront == true)
            {
                newPos = new Vector3
                (
                 ((objectsToNumber[i].transform.position.x + renderer[i].bounds.extents.x) + yPadding),
                 objectsToNumber[i].transform.position.y,
                   objectsToNumber[i].transform.position.z
                 );
            }

            newText.transform.position = newPos;
            newText.transform.parent = objectsToNumber[i].transform;
            newText.name = objectsToNumber[i].name + " Text";
            newText.tag = "ObjectToAddText";
            newTexts.Add(newText);
            var textmesh = newText.GetComponent<TextMesh>();
            //textmesh.transform.localRotation = Quaternion.Euler(0, -90, 0);

            if (textAbove == true)
            {
                textmesh.text = i.ToString();
            }

            if (textInFront == true)
            {
                textmesh.text = objectsToNumber[i].name;
            }
        }
    }

    private void Update()
    {
        if (rotateNumbers == true)
        {
            for (int i = 0; i < newTexts.Count; i++)
            {
                newTexts[i].transform.Rotate(Vector3.up, 10 * rotationSpeed * Time.deltaTime);
            }
        }
    }
}

问题是它在编辑器模式下进行实例化,但如果我正在运行游戏,它会再次实例化文本,然后出现双倍文本。

GameObject newText = Instantiate(text);

我只想实例化文本一次。如果运行游戏不再创建相同的文本。

我正在实例化文本游戏对象。

【问题讨论】:

    标签: c# unity3d


    【解决方案1】:

    关于 ExecuteAlways 属性的 Unity 文档向您展示了如何根据您是处于编辑器模式还是播放模式来区分逻辑。

    void Start()
    {
        if (Application.IsPlaying(gameObject))
        {
            // Play logic
        }
        else
        {
            // Editor logic
        }
    }
    

    摘自此处:https://docs.unity3d.com/ScriptReference/ExecuteAlways.html

    了解这一点后,您有两个选择。您可以选择在编辑器模式下不实例化文本,也可以在进入播放模式时检查文本是否存在,如果存在则销毁它。

    【讨论】:

    • 这将在构建中留下垃圾/膨胀代码。编辑模式检查也可以简化。请参阅my answer 以获得更好的选择。
    【解决方案2】:

    使用Platform Dependent Compilation 以便仅在编辑器中运行的代码永远不会编译为构建。这避免了构建中的臃肿代码。

    然后,使用EditorApplication.isPlaying 确保仅在编辑模式下运行的代码不会在播放模式下运行。

    #if UNITY_EDITOR //Avoid garbage in the builds
        //Editor logic
        if(!EditorApplication.isPlaying) //If NOT in play mode
            GameObject newText = Instantiate(text);
    #endif
    

    【讨论】:

      【解决方案3】:

      假设objectsToNumber[i] 下没有其他TextMesh 对象,您可以简单地先检查该对象是否已经存在,例如

      renderer[i] = GetComponentInChildren<TextMesh>();
      if(!renderer[i]) renderer[i] = Instantiate(text).GetComponent<TextMesh>();
      

      否则,既然我们知道您将如何调用该对象,您也可以使用 Find 之类的

      var child = !objectsToNumber[i].transform.Find(renderer[i].name + " Text");
      renderer[i] = child !=null ? child.GetComponnet<TextMesh>() : Instantiate(text).GetComponent<TextMesh>();
      

      我会更改类型以匹配您的目标类型,例如如果你的类型是text

      public TextMesh text;
      

      那么您可以省略 GetComponent 并简单地使用

      renderer[i] = Instantiate(text);
      

      它还确保您只能引用附加了所需组件的预制件/对象。


      为了性能我也宁愿使用

      public enum TextPosition
      {
          Above,
          InFront,
          OnFaces
      }
      
      public TextPosition textPosition;
      
      // and make this a list
      private List<MeshRenderer> renderer = new List<MeshRenderer>();
      

      然后使用

      private void Start()
      {
          foreach(var parent in objectsToNumber)
          {
              var newText = GetComponentInChildren<TextMesh>();
              if(!newText) newText = Instantiate(text).GetComponent<TextMesh>();
      
              renderer.Add(newText);
      
              switch(textPosition)
              {
                  case TextPosition.Above:
                      newPos = parent.transform.position + Vector3.up * (renderer[i].bounds.extents.y + yPadding);
                      break;
      
                  case TextPosition.InFront:
                      newPos = parent.transform.position + Vector3.up * (renderer[i].bounds.extents.x + yPadding);
                      break;
              }
      
              newText.transform.position = newPos;
              newText.transform.parent = parent.transform;
              newText.name = parent.name + " Text";
              newText.tag = "ObjectToAddText";
              newTexts.Add(newText);
      
              switch(textPosition)
              {
                  case TextPosition.Above:
                      newText.text = renderer.Count.ToString();
                      break;
      
                  case TextPosition.InFront:
                      newText.text = parent.name;
                      break;
              }
          }
      }
      
      and
      
          private void Update()
          {
              if (rotateNumbers)
              {
                  foreach (var text in newTexts)
                  {
                      // I would rather assign the correct value to rotationSpeed 
                      // instead of multiplying it by 10 afterwards ...
                      text.transform.Rotate(Vector3.up, 10 * rotationSpeed * Time.deltaTime);
                  }
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-05
        • 1970-01-01
        • 2022-07-17
        • 2011-01-22
        相关资源
        最近更新 更多