Search Unity

Resolved Terrain Leveling

Discussion in 'Scripting' started by sjameselvis, Jul 6, 2020.

  1. sjameselvis

    sjameselvis

    Joined:
    Aug 28, 2019
    Posts:
    50
    Hello guys,

    I am trying to make a script that would flatten the terrain under a building when i place it ingame. I had a very hard time translating the world coordinates to the terrain coordinates and now when I have finally got it right, but I can not get it to flatten the right amount of terrain and at the right height -> I don't know how to translate the world y coords in terrain height value.
    Here is how I tried to do it:
    I got the x/y buildings' sizes in an array and then tried to flatten it out. (Buildings' sizes are in the image)

    What I need help with:
    figuring out the values i need on the lines 7,8 and 11

    This is the code I use:
    Code (CSharp):
    1.  void LevelTerrain(int x1, int y1, int yLevel)
    2.     {
    3.         // gets selected building's                      conversion to terrain coordinates
    4.         //                           size                I typed 100f because 513 was way too big  
    5.         //                              ↓↓↓↓↓↓                 ↓↓↓↓↓↓↓
    6.         //              |                               |  |           |
    7.         int xRes = (int)(buildingsSizex[selectedBuilding] / 1000f * 100f);  Debug.Log(xRes + "xRes");    
    8.         int yRes = (int)(buildingsSizey[selectedBuilding] / 1000f * 100f);  Debug.Log(yRes + "yRes");
    9.         //I have no idea what this variable should be
    10.         //                      ↓↓↓↓↓
    11.         float y_Level = yLevel / 200f; //y level where the building should be
    12.  
    13.         //world coordinates         conversion to
    14.         //of where I want           terrain coordinates
    15.         // the building   ↓↓       ↓↓↓↓
    16.         //                ↓↓   |          |                        
    17.         int xBase = (int)(x1 / 1000f * 513f); Debug.Log(xBase + "xBase");   //xBase -> the point x where the Height map starts
    18.         int yBase = (int)(y1 / 1000f * 513f); Debug.Log(yBase + "yBase");   //yBase -> the point y where the Height map starts
    19.  
    20.         float[,] heights = terrain.terrainData.GetHeights(yBase, xBase, xRes, yRes); // Heigth Map
    21.  
    22.         for (int i = 0; i < xRes; i++)           // flatten the terrain
    23.         {
    24.             for (int j = 0; j < yRes; j++)
    25.             {
    26.                 heights[j , i] = y_Level;
    27.             }
    28.         }
    29.         terrain.terrainData.SetHeights(yBase, xBase, heights); //update the heigth map
    Images: sorry because of the links. Pelase look at them.
    https://imgur.com/rUa7hVm
    https://imgur.com/w4HIQZt
    https://imgur.com/BxijtuW


    If you have any ideas how to do it better please let me know. =)
     
  2. sjameselvis

    sjameselvis

    Joined:
    Aug 28, 2019
    Posts:
    50
    Awsome Thanks
     
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    I did something like this a few years ago... it was in Unity5 so I don't know how well it will behave in modern Unity with the new terrain system, but I went and extracted a .unitypackage for you and attached it.

    @Zer0Cool apologies for jumping your train but I still would LOVE to see your example code too!!!!!!
     

    Attached Files:

    sjameselvis and Zer0Cool like this.
  4. Zer0Cool

    Zer0Cool

    Joined:
    Oct 24, 2014
    Posts:
    203
    So finally here's my example code.;) Simply drag this script on the terrain and assign a primitive cube to the script that sits ontop of the terrain. The code will raise the terrain up to the height of the cube. You can even scale the cube as you like to get rectangular areas.


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. /// <summary>
    6. /// Terrain example for forum.unity.com by Zer0Cool
    7. /// </summary>
    8. public class ModifyTerrain : MonoBehaviour
    9. {
    10.  
    11.     [Tooltip("Assign a cube primitive here placed on the Unity terrain. You can even scale the cube if you like.")]
    12.     public Transform cube;
    13.  
    14.     [Tooltip("Resets the terrain under the cube to zero high.")]
    15.     public bool resetTerrainToZero;
    16.  
    17.     private Vector3 rectCenter;
    18.     private float rectSizeX;
    19.     private float rectSizeY;
    20.  
    21.     private Vector2 rectCenterMap = Vector2.zero;
    22.     private int rectSizeXMap;
    23.     private int rectSizeYMap;
    24.     private float rectSizeHMap;
    25.  
    26.     private float[,] heightMap;
    27.  
    28.     void Start()
    29.     {
    30.         FlattenTerrain();
    31.     }
    32.  
    33.     void FlattenTerrain()
    34.     {
    35.         rectCenter = cube.transform.position;
    36.         rectSizeX = cube.transform.localScale.x;
    37.         rectSizeY = cube.transform.localScale.z;
    38.  
    39.         Terrain ter = GetComponent<Terrain>();
    40.         TerrainData terData = ter.terrainData;
    41.         int Tw = terData.heightmapResolution;
    42.         int Th = terData.heightmapResolution;
    43.         heightMap = terData.GetHeights(0, 0, Tw, Th);
    44.  
    45.         // Determine the world coordinates
    46.         float scalex = terData.heightmapResolution / terData.size.x;
    47.         float scaley = terData.heightmapResolution / terData.size.z;
    48.         rectCenterMap = new Vector2((int)(rectCenter.x * scalex), (int)(rectCenter.z * scaley));
    49.  
    50.         rectSizeXMap = (int)((rectSizeX * scalex) / 2f);
    51.         rectSizeYMap = (int)((rectSizeY * scaley) / 2f);
    52.         rectSizeHMap = rectCenter.y / terData.size.y;
    53.  
    54.         for (int Ty = 0; Ty < Th; Ty++)
    55.         {
    56.             for (int Tx = 0; Tx < Tw; Tx++)
    57.             {
    58.                 PunchOutRectangle(Ty, Tx);
    59.             }
    60.         }
    61.  
    62.         terData.SetHeights(0, 0, heightMap);
    63.     }
    64.  
    65.     public void PunchOutRectangle(int xrow, int yrow)
    66.     {
    67.         if ((xrow <= (rectCenterMap.x + rectSizeXMap)) && (xrow >= (rectCenterMap.x - rectSizeXMap)) &&
    68.            (yrow <= (rectCenterMap.y + rectSizeYMap)) && (yrow >= (rectCenterMap.y - rectSizeYMap)))
    69.         {
    70.             // Raise the terrain to center of the cube
    71.             heightMap[yrow, xrow] = rectSizeHMap;
    72.             if (resetTerrainToZero) heightMap[yrow, xrow] = 0f;
    73.         }
    74.     }
    75. }
     
    Last edited: Jul 6, 2020
    GoliathAT and Kurt-Dekker like this.
  5. sjameselvis

    sjameselvis

    Joined:
    Aug 28, 2019
    Posts:
    50
    Thank you for the code, it really helped me =)