private void EnableOnFrameLoading()
 {
     generateTerrainTree = true;
     loadingTextPanel.SetActive(true);
     currentBuildStep = TerrainBuildStep.forcePasses;
     loadingText.text = "Loading...\nArranging Nodes\n0%";
 }
    //used to generate terrain trees at run time without crashing the app on android (guaranteed not to make the app hang for too long)
    public void Update()
    {
        if (generateTerrainTree)
        {
            switch (currentBuildStep)
            {
            case TerrainBuildStep.forcePasses:
                TreeForceApplicator.Pass(leafNodes);
                numForceLayoutPassesPerformed++;
                if (numForceLayoutPassesPerformed >= TreeForceApplicator.numPasses)
                {
                    currentBuildStep = TerrainBuildStep.checkForCachedHeights;
                    loadingText.text = "Loading...\nChecking for cached heights";
                    numForceLayoutPassesPerformed = 0;
                }
                else
                {
                    loadingText.text = "Loading...\nArranging Nodes\n" +
                                       (float)numForceLayoutPassesPerformed / TreeForceApplicator.numPasses * 100 + "%";
                }
                break;

            case TerrainBuildStep.checkForCachedHeights:
                //here we check to see if the terrain has already been generated and cached
                if (TreeTerrainBehaviour.instance.TryLoadFromCache())
                {     //if it has we can skip over raising and smoothing
                    currentBuildStep = TerrainBuildStep.nodeRaising;
                    loadingText.text = "Loading...\nRaising Nodes";
                }
                else
                {
                    currentBuildStep = TerrainBuildStep.terrainRasing;
                    loadingText.text = "Loading...\nRaising Terrain\n0%";
                }
                break;

            case TerrainBuildStep.terrainRasing:
                //create a queue to store nodes in if one doesn't already exist
                if (bfsQueue == null)
                {
                    bfsQueue = new Queue <GameObject>();
                    //enqueue the root node - the first game object in the hierachy beneath the tree container
                    bfsQueue.Enqueue(treeContainer.transform.GetChild(0).gameObject);
                }

                //breadth first raise terrain at leaf nodes in chunks of 10
                for (int numReps = 0; numReps < 10; numReps++)
                {
                    if (bfsQueue.Count != 0)
                    {
                        GameObject node = bfsQueue.Dequeue();
                        Node       info = node.GetComponent <BasicNodeBehaviour>().getAttachedNodeInfo();

                        if (info.getNumberOfChildren() == 0)
                        {
                            for (int i = 0; i <= info.nodeDepth; i++)
                            {
                                TreeTerrainBehaviour.instance.RaiseTerrainTo(node, i, info.nodeDepth);
                            }
                            numLeafNodeTerrainRaised++;
                        }

                        foreach (Transform child in node.transform)
                        {
                            if (child.gameObject.tag == "NodeObject")
                            {
                                bfsQueue.Enqueue(child.gameObject);
                            }
                        }
                    }
                    else
                    {
                        currentBuildStep         = TerrainBuildStep.terrainSmoothing;
                        numLeafNodeTerrainRaised = 0;
                        loadingText.text         = "Loading...\nSmoothing Terrain";
                        break;
                    }

                    if (currentBuildStep == TerrainBuildStep.terrainRasing)
                    {
                        loadingText.text = "Loading...\nRaising Terrain\n" +
                                           (float)numLeafNodeTerrainRaised / leafNodes.Length * 100 + "%";
                    }
                }
                break;

            case TerrainBuildStep.terrainSmoothing:
                TreeTerrainBehaviour.instance.SmoothTerrain();
                //here we cache the terrain heights so we don't have to do these computations again
                TreeTerrainBehaviour.instance.CacheTerrainHeights();
                currentBuildStep = TerrainBuildStep.nodeRaising;
                loadingText.text = "Loading...\nRaising Nodes";
                break;

            case TerrainBuildStep.nodeRaising:
                bfsQueue = new Queue <GameObject>();
                //enqueue the root node bring nodes above the terrain
                bfsQueue.Enqueue(treeContainer.transform.GetChild(0).gameObject);

                //scale is the scale of the sphere renderer component of each node -> identical to the sphere's diameter
                //hierachy:
                //                   0        0             0       1       1       2           n-1       n
                //TreeContainer -> Node -> {Renderer -> {Label, Sphere}, Child1, Child2 ... Child n-1, Child n}
                float scale  = treeContainer.transform.GetChild(0).transform.GetChild(0).GetChild(1).localScale.y;
                float radius = scale / 2;

                //do the bfs again, this time raise all the non leaf nodes to a height above the terrain
                // raise all the parent nodes just above the terrain so the tree remains clear
                float parentNodeHeight = TreeTerrainBehaviour.instance.maxTerrainHeight + 0.5f + radius;

                while (bfsQueue.Count != 0)
                {
                    GameObject node = bfsQueue.Dequeue();
                    Node       info = node.GetComponent <BasicNodeBehaviour>().getAttachedNodeInfo();
                    if (info.getNumberOfChildren() > 0)
                    {
                        Vector3 pos = node.transform.position;
                        pos.y = parentNodeHeight;
                        node.transform.position = pos;
                    }
                    else
                    {
                        Vector3 pos = node.transform.position;
                        pos.y = TreeTerrainBehaviour.instance.GlobalHeightAt(node.transform.position) + radius;
                        node.transform.position = pos;
                    }

                    foreach (Transform child in node.transform)
                    {
                        if (child.gameObject.tag == "NodeObject")
                        {
                            bfsQueue.Enqueue(child.gameObject);
                        }
                    }
                }

                //put the player nice and high in the air so they don't end up inside the terrain
                Vector3 playerPos = player.transform.position;
                playerPos.y = parentNodeHeight + 1f;
                player.transform.position = playerPos;
                currentBuildStep          = TerrainBuildStep.terrainColouring;
                bfsQueue = null;
                break;

            case TerrainBuildStep.terrainColouring:
                TreeTerrainBehaviour.instance.ColourTerrain();
                DisableOnFrameLoading();
                break;
            }
        }
    }