【问题标题】:Coroutine function isnt called in edit mode unity在统一编辑模式下不调用协程函数
【发布时间】:2018-11-24 15:29:38
【问题描述】:

我有一个生成自定义复合网格的脚本。但是当用户编辑生成复合网格的脚本的属性时,我想删除以前创建的网格。我必须遵循脚本来完成此操作:

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

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

【问题讨论】:

  • 如果将日志语句放在yield前面会发生什么,它会显示吗?如果您将日志语句放在OnValidate 的foreach 循环中,会不会被调用?
  • 我已经尝试将日志放在它被调用的foreach循环中,我现在会在yield之前尝试日志,如果它被调用会通知你!
  • 是的,它在yield 语句之前调用
  • 不完全确定原因,但显然问题出在WaitForEndOfFrame。我的猜测是没有“框架”,因为 OnValidate 发生在编辑器模式下,因此没有框架。如果你改用yield return null;,它应该可以工作
  • 太棒了,如果你把它作为答案发布,我肯定会接受它:)

标签: c# oop unity3d coroutine


【解决方案1】:

问题来自WaitForEndOfFrame。不完全确定原因,但似乎在编辑器模式下此操作不会返回,而不是在播放模式下。

如果你改用yield return null,应该可以达到同样的效果。

执行顺序图中的其他人可能很清楚答案: https://docs.unity3d.com/uploads/Main/monobehaviour_flowchart.svg

【讨论】:

    猜你喜欢
    • 2015-12-17
    • 2022-08-03
    • 1970-01-01
    • 2012-12-18
    • 1970-01-01
    • 2020-04-13
    • 1970-01-01
    • 2013-10-19
    • 1970-01-01
    相关资源
    最近更新 更多