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