簡體   English   中英

如何檢查以避免游戲對象在層次結構中重復?

[英]How can I check to avoid gameobject duplication in the hierarchy?

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

我只想實例化文本一次。 並且如果運行游戲不再創建相同的文本。

我正在實例化文本游戲對象。

ExecuteAlways屬性上的Unity文檔向您展示了如何根據您是處於編輯器模式還是播放模式來區分邏輯。

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

摘自此處的代碼段: https : //docs.unity3d.com/ScriptReference/ExecuteAlways.html

知道這一點,您有兩個選擇。 您可以選擇在編輯器模式下不實例化文本,也可以在進入“播放”模式時檢查文本是否存在,如果存在,則銷毀該文本。

使用平台相關的編譯,以便只在編輯器中運行的代碼永遠不會編譯到內部版本。 這避免了構建中的膨脹代碼。

然后,使用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

假設在objectsToNumber[i]下沒有其他TextMesh對象,您可以簡單地首先檢查對象是否已經存在,例如

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

否則,因為我們知道您將如何調用該對象,所以您也可以使用Find like

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM