在编辑模式下统一调用协程函数

时间:2018-11-24 15:29:38

标签: c# oop unity3d coroutine

我有一个生成自定义复合网格的脚本。但是,当用户编辑生成复合网格的脚本的属性时,我要删除先前创建的网格。我必须遵循以下脚本才能完成此任务:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]
public class BasicVoidVisualizationProperties : MonoBehaviour {

    public Vector3 Dimensions;
    public float Thickness;
    public float Spacing;

    private GameObject[] Corners = new GameObject[8];
    private EdgeBuilder[] Edges = new EdgeBuilder[12];

    // Use this for initialization
    void Start () {
        for (int i = 0; i < Corners.Length; i++)
        {
            Corners[i] = Instantiate(Resources.Load("cube") as GameObject);
            Corners[i].transform.SetParent(this.transform);
        }
        RebuildCorners(Corners, Dimensions, Thickness);
        for (int i = 0; i < Edges.Length; i++)
        {
            Edges[i] = new EdgeBuilder(this.transform);
        }
        RebuildEdges(Edges, Corners);
    }

    // Update is called once per frame
    void Update () {

    }

    private void RebuildCorners(GameObject[] Corners, Vector3 Dimensions, float Thickness)
    {
        Corners[0].transform.localScale = new Vector3(Thickness, Thickness, Thickness);
        Corners[0].transform.position = this.transform.position + new Vector3(Thickness/2, Thickness /2, Thickness/2);
        Corners[1].transform.localScale = new Vector3(Thickness, Thickness, Thickness);
        Corners[1].transform.position = this.transform.position + new Vector3(Dimensions.x - Thickness /2, Thickness /2, Thickness/2);
        Corners[2].transform.localScale = new Vector3(Thickness, Thickness, Thickness);
        Corners[2].transform.position = this.transform.position + new Vector3(Dimensions.x - Thickness /2, Thickness/2, Dimensions.z - Thickness /2);
        Corners[3].transform.localScale = new Vector3(Thickness, Thickness, Thickness);
        Corners[3].transform.position = this.transform.position + new Vector3(Thickness/2, Thickness/2, Dimensions.z - Thickness /2);
        Corners[4].transform.localScale = new Vector3(Thickness, Thickness, Thickness);
        Corners[4].transform.position = this.transform.position + new Vector3(Thickness/2, Dimensions.y - Thickness/2, Thickness/2);
        Corners[5].transform.localScale = new Vector3(Thickness, Thickness, Thickness);
        Corners[5].transform.position = this.transform.position + new Vector3(Dimensions.x - Thickness /2, Dimensions.y - Thickness/2, Thickness/2);
        Corners[6].transform.localScale = new Vector3(Thickness, Thickness, Thickness);
        Corners[6].transform.position = this.transform.position + new Vector3(Dimensions.x - Thickness /2, Dimensions.y - Thickness/2, Dimensions.z - Thickness /2);
        Corners[7].transform.localScale = new Vector3(Thickness, Thickness, Thickness);
        Corners[7].transform.position = this.transform.position + new Vector3(Thickness/2, Dimensions.y - Thickness/2, Dimensions.z - Thickness /2);
    }

    private void RebuildEdges(EdgeBuilder[] Edges, GameObject[] Corners)
    {
        Edges[0].RebuildEdge(Corners[0].transform.position, Corners[1].transform.position, Thickness, Spacing, Direction.right);
        Edges[1].RebuildEdge(Corners[3].transform.position, Corners[2].transform.position, Thickness, Spacing, Direction.right);
        Edges[2].RebuildEdge(Corners[4].transform.position, Corners[5].transform.position, Thickness, Spacing, Direction.right);
        Edges[3].RebuildEdge(Corners[7].transform.position, Corners[6].transform.position, Thickness, Spacing, Direction.right);

        Edges[4].RebuildEdge(Corners[0].transform.position, Corners[4].transform.position, Thickness, Spacing, Direction.up);
        Edges[5].RebuildEdge(Corners[1].transform.position, Corners[5].transform.position, Thickness, Spacing, Direction.up);
        Edges[6].RebuildEdge(Corners[2].transform.position, Corners[6].transform.position, Thickness, Spacing, Direction.up);
        Edges[7].RebuildEdge(Corners[3].transform.position, Corners[7].transform.position, Thickness, Spacing, Direction.up);

        Edges[8].RebuildEdge(Corners[0].transform.position, Corners[3].transform.position, Thickness, Spacing, Direction.forward);
        Edges[9].RebuildEdge(Corners[1].transform.position, Corners[2].transform.position, Thickness, Spacing, Direction.forward);
        Edges[10].RebuildEdge(Corners[4].transform.position, Corners[7].transform.position, Thickness, Spacing, Direction.forward);
        Edges[11].RebuildEdge(Corners[5].transform.position, Corners[6].transform.position, Thickness, Spacing, Direction.forward);
    }

    void OnValidate()
    {
        if(Corners[0] != null) RebuildCorners(Corners, Dimensions, Thickness);
        if(Corners[0] != null && Edges[0] != null)
        {
            foreach (var edge in Edges)
            {
                foreach (var eb in edge.EdgeBlocks)
                {
                    StartCoroutine(DestroyEdgeElement(eb));
                }
            }
            RebuildEdges(Edges, Corners);
        }
    }

    private IEnumerator DestroyEdgeElement(GameObject go)
    {
        yield return new WaitForEndOfFrame();
        Debug.Log("DESTROYED");           // IS NEVER CALLED (never logs to console)
        DestroyImmediate(go);
    }

    private class EdgeBuilder
    {
        private Transform Parent;
        public List<GameObject> EdgeBlocks = new List<GameObject>();

        public EdgeBuilder(Transform parent)
        {
            Parent = parent;
        }

        private List<GameObject> CalculateEdgeBlocks(Vector3 origin, Vector3 end, float thickness, float spacing)
        {
            List<GameObject> elements = new List<GameObject>();
            var dist = Vector3.Distance(origin, end) - thickness;
            var blocks = (int)Mathf.Round((dist - (thickness + spacing * 2)) / (thickness + spacing));
            for (int i = 0; i < blocks; i++)
            {
                var el = Instantiate(Resources.Load("cube") as GameObject);
                el.transform.localScale = new Vector3(thickness, thickness, thickness);
                el.transform.SetParent(Parent);
                elements.Add(el);
            }

            return elements;
        }

        public void RebuildEdge(Vector3 origin, Vector3 end, float thickness, float spacing, Direction dir)
        {
            // if(EdgeBlocks.Count > 0) ClearEdge(); 
            EdgeBlocks = CalculateEdgeBlocks(origin, end, thickness, spacing);

            if (dir == Direction.up)
            {
                var firstEl = new Vector3(origin.x, origin.y + thickness + spacing, origin.z);
                foreach (var el in EdgeBlocks)
                {
                    el.transform.position = firstEl;
                    firstEl += new Vector3(0, thickness + spacing, 0);
                }
            }
            else if(dir == Direction.right)
            {
                var firstEl = new Vector3(origin.x + thickness + spacing, origin.y, origin.z);
                foreach (var el in EdgeBlocks)
                {
                    el.transform.position = firstEl;
                    firstEl += new Vector3(thickness + spacing, 0, 0);
                }
            }
            else if(dir == Direction.forward)
            {
                var firstEl = new Vector3(origin.x, origin.y, origin.z + thickness + spacing);
                foreach (var el in EdgeBlocks)
                {
                    el.transform.position = firstEl;
                    firstEl += new Vector3(0, 0, thickness + spacing);
                }
            }
        }

        // private void ClearEdge()
        // {
        //  foreach (var eb in EdgeBlocks)
        //  {
        //      DestroyImmediate(eb, true);
        //  }
        //  EdgeBlocks.Clear();
        // }
    }

    private enum Direction
    {
        up,
        right,
        forward 
    }
}

我一直遇到的问题是从未调用过Debug.log("Destroyed");(我看不到Debug.log的执行)。为什么会这样呢?

您可能会问为什么要使用协程,请参见以下链接,了解我为何使用协程: Coroutine to destroy object from editor event

如果需要更多信息,请告诉我,以便我澄清!

1 个答案:

答案 0 :(得分:1)

问题来自WaitForEndOfFrame。对此并不完全有把握,但似乎该操作在编辑器模式下不会返回,而在播放模式下不会返回。

如果您改用yield return null,则应达到相同的效果。

答案对执行顺序图中的其他人可能是显而易见的: https://docs.unity3d.com/uploads/Main/monobehaviour_flowchart.svg