Search Unity

'remove' trees with SetHeights? (Solved)

Discussion in 'Scripting' started by Lunix46, Jul 27, 2019.

  1. Lunix46

    Lunix46

    Joined:
    Sep 27, 2016
    Posts:
    26
    Hello people!

    Today i bring something i cant get my head around. I cant understand why it wont work. So i have trees in my scene that i want to delete from the TerrainData and spawn a prefab which can be chopped down. It spawns the prefab no problem and all but it just wont remove the treeinstance from the terrain? Any help is appreciated! Thanks in advance!

    Code (CSharp):
    1.        if (Input.GetKeyDown(KeyCode.L)) //Change cloesest tree to prefab
    2.         {
    3.  
    4.             RaycastHit hit;
    5.             if(Physics.Raycast(Player.transform.position, Vector3.down,out hit)) //Shoot a raycast under the player and get the collider of the terrain and assign it underneath
    6.             {
    7.                ActiveTerrain = hit.collider.gameObject.GetComponent<Terrain>(); //Assign the terrain that is under the player to Active Terrain (For smoother operation)
    8.             }
    9.  
    10.  
    11.             TreeInstance[] trees = ActiveTerrain.terrainData.treeInstances; //Take current terrain and assign all trees to that array
    12.             var data = ActiveTerrain.terrainData; //Data = current terrainData function on that terrain
    13.             if (trees.Length > 0) //If there is more then 1 tree in that map
    14.             {
    15.                 TreeInstance Nearest = trees[0]; //Nearest = 0 (Latest tree in the list)
    16.                 treeSave = data.treeInstances; //save current terrain trees will be changed later
    17.                 float width = (float)data.heightmapWidth; //Take width
    18.                 float height = (float)data.heightmapHeight; // take height (this is where the map is)
    19.                 Vector3 NearPosition = Vector3.Scale(Nearest.position, data.size) + ActiveTerrain.transform.position; //We make it in to a vector3 and call it near pos
    20.                 foreach (TreeInstance Location in trees) //For each treeinstance in the tree list
    21.                 {
    22.                     Vector3 position = Vector3.Scale(Location.position, data.size) + ActiveTerrain.transform.position; //Take pos
    23.                     if (Vector3.Distance(position, Player.transform.position) < Vector3.Distance(NearPosition, Player.transform.position)) //Compare tree pos to player pos and get closest!
    24.                     {
    25.                         Nearest = Location;
    26.                         NearPosition = position;
    27.                     }
    28.                 }
    29.  
    30.                 NearPosition.y = ActiveTerrain.SampleHeight(NearPosition);
    31.                 Instantiate(TreeId[Nearest.prototypeIndex], NearPosition, Quaternion.identity, ParentHolder.transform); //ParentHolder is where they are made
    32.  
    33.  
    34.                 var CurTrees = new List<TreeInstance>(trees);
    35.                 data.treeInstances = CurTrees.ToArray();
    36.                 float[,] heights = data.GetHeights(0, 0, 0, 0);
    37.                 data.SetHeights(0, 0, heights);
    38.                 CurTrees.RemoveAt(0);
    39.  
    40.  
    41.             }
    42.         }
    43.     }
     
  2. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,913
  3. Lunix46

    Lunix46

    Joined:
    Sep 27, 2016
    Posts:
    26
    when i change

    Code (CSharp):
    1. data.treeInstances = CurTrees.ToArray();
    to
    Code (CSharp):
    1. data.treeInstances = new TreeInstance[];
    it will remove all the trees in the terrain. which wont work. I want only the closest tree to the player to be removed from the terrain and replaced. My problem must lay within these lines which is what i cant figure out why it wont work. It should be noted that we are talking about a lot of trees, hence why I dont want to make them all to prefabs but just the ones the player will interact with


    Code (CSharp):
    1.                 var CurTrees = new List<TreeInstance>(trees);
    2.                 data.treeInstances = CurTrees.ToArray();
    3.                 float[,] heights = data.GetHeights(0, 0, 0, 0);
    4.                 data.SetHeights(0, 0, heights);
    5.                 CurTrees.RemoveAt(0);

    //edit
    I changed
    data.SetHeights(0, 0, heights);
    to
    trees[0].heightScale 0.0f; since the data changes all trees on the map
     
    Last edited: Jul 28, 2019
  4. Lunix46

    Lunix46

    Joined:
    Sep 27, 2016
    Posts:
    26
    So I think i've done some progress. I have changed some of the code and i can now acess what tree in the array needs to be removed and it those all that but how do i overwrite the treeinstance with the new one that has that tree removed?

    Code (CSharp):
    1.             if (trees.Length > 0) //If there is more then 1 tree in that map
    2.             {
    3.                 TreeInstance Nearest = trees[0]; //Nearest = 0 (Latest tree in the list)
    4.                 treeSave = data.treeInstances; //save current terrain trees will be changed later
    5.                 float width = (float)data.heightmapWidth; //Take width
    6.                 float height = (float)data.heightmapHeight; // take height (this is where the map is)
    7.                 Vector3 NearPosition = Vector3.Scale(Nearest.position, data.size) + ActiveTerrain.transform.position; //We make it in to a vector3 and call it near pos
    8.                 TreeInstance Location = trees[0]; //Get the location for the tree
    9.                 int ClosestNumber = 0; //Save the array int from closest tree
    10.                 //  foreach (TreeInstance Location in trees) //For each treeinstance in the tree list
    11.                 for (int i = 0; i < trees.Length; i++) //Loop it
    12.                 {
    13.                     Location = trees[i]; //Change the location every iteration
    14.                     Vector3 position = Vector3.Scale(Location.position, data.size) + ActiveTerrain.transform.position; //Take pos
    15.                     if (Vector3.Distance(position, Player.transform.position) < Vector3.Distance(NearPosition, Player.transform.position)) //Compare tree pos to player pos and get closest!
    16.                     {
    17.                         Nearest = Location;
    18.                         NearPosition = position;
    19.                         ClosestNumber = i; //If the player is close to a tree change the number, Latest change = closest tree
    20.                     }
    21.                 }
    22.                 Debug.Log(ClosestNumber);
    23.                 NearPosition.y = ActiveTerrain.SampleHeight(NearPosition);
    24.                 Instantiate(TreeId[Nearest.prototypeIndex], NearPosition, Quaternion.identity, ParentHolder.transform); //ParentHolder is where they are made
    25.  
    26.                 var newtree = new List<TreeInstance>(trees); //<-- so how do i overwrite the treeinstance with this?
    27.                 newtree.RemoveAt(ClosestNumber);
    28.                 trees[ClosestNumber].widthScale = 0.0f;
    29.                 trees[ClosestNumber].heightScale = 0.0f;
    30.             }
     
  5. Lunix46

    Lunix46

    Joined:
    Sep 27, 2016
    Posts:
    26
    I have solved it! I have no clue why it dident work the first few times but i've gotten it to work every time with this code, I will leave it here for people to see.

    Code (CSharp):
    1. if (Input.GetKeyDown(KeyCode.L)) //Change cloesest tree to prefab
    2.         {
    3.  
    4.             RaycastHit hit;
    5.             if(Physics.Raycast(Player.transform.position, Vector3.down,out hit)) //Shoot a raycast under the player and get the collider of the terrain and assign it underneath
    6.             {
    7.                ActiveTerrain = hit.collider.gameObject.GetComponent<Terrain>(); //Assign the terrain that is under the player to Active Terrain (For smoother operation)
    8.             }
    9.  
    10.  
    11.             // TreeInstance[] trees = Maps[3].GetComponent<Terrain>().terrainData.treeInstances; //Grab all trees Deprecated
    12.  
    13.             TreeInstance[] trees = ActiveTerrain.terrainData.treeInstances; //Take current terrain and assign all trees to that array
    14.             var data = ActiveTerrain.terrainData; //Data = current terrainData function on that terrain
    15.  
    16.  
    17.             if (trees.Length > 0) //If there is more then 1 tree in that map
    18.             {
    19.                 TreeInstance Nearest = trees[0]; //Nearest = 0 (Latest tree in the list)
    20.                 treeSave = data.treeInstances; //Make a backup of all the trees and apply when app is quit (Will be deleted in full version)
    21.                 TempTree = data.treeInstances; //This makes a new instance that we later remove from and apply to the current instance
    22.                 float width = (float)data.heightmapWidth; //Take width
    23.                 float height = (float)data.heightmapHeight; // take height (this is where the map is)
    24.                 Vector3 NearPosition = Vector3.Scale(Nearest.position, data.size) + ActiveTerrain.transform.position; //We make it in to a vector3 and call it near pos
    25.                 TreeInstance Location = trees[0]; //Get the location for the tree
    26.                 int ClosestNumber = 0; //Save the array int from closest tree
    27.                 //  foreach (TreeInstance Location in trees) //For each treeinstance in the tree list
    28.                 for (int i = 0; i < trees.Length; i++) //Loop it
    29.                 {
    30.                     Location = trees[i]; //Change the location every iteration
    31.                     Vector3 position = Vector3.Scale(Location.position, data.size) + ActiveTerrain.transform.position; //Take pos
    32.                     if (Vector3.Distance(position, Player.transform.position) < Vector3.Distance(NearPosition, Player.transform.position)) //Compare tree pos to player pos and get closest!
    33.                     {
    34.                         Nearest = Location;
    35.                         NearPosition = position;
    36.                         ClosestNumber = i; //If the player is close to a tree change the number, Latest change = closest tree
    37.                     }
    38.                 }
    39.                 Debug.Log(ClosestNumber); //index number on closest tree
    40.                 Instantiate(TreeId[Nearest.prototypeIndex], NearPosition, Quaternion.identity, ParentHolder.transform); //ParentHolder is where they are made
    41.  
    42.  
    43.                 var newtreeInstance = new List<TreeInstance>(TempTree); //We make the temptree instance in to a list so we can remove the closest tree
    44.                 newtreeInstance.RemoveAt(ClosestNumber); //Delete the tree at the closestnumber int
    45.                 data.treeInstances = newtreeInstance.ToArray(); //Apply the new tree instance to the scene
    46.             }
    47.         }
    48.     }
    49.     private void OnApplicationQuit()
    50.     {
    51.         ActiveTerrain.terrainData.treeInstances = treeSave;
    52.     }

    And to remove the collider from the tree that was instanced you can use this

    Code (CSharp):
    1.  
    2. Terrain.activeTerrain.GetComponent<TerrainCollider>().enabled = false;
    3. Terrain.activeTerrain.GetComponent<TerrainCollider>().enabled = true;
     
    Last edited: Jul 29, 2019
    heartingNinja likes this.