Search Unity

Swapping terrain prefabs and textures during runtime through scripts?

Discussion in 'Scripting' started by Revontuli, Jun 7, 2011.

  1. Revontuli

    Revontuli

    Joined:
    May 12, 2011
    Posts:
    29
    Continuing the delving into terrain - I need to implement seasonal changes to the terrain, and it seems best to be able to switch out the current textures and trees with different ones (say "grass" with "snow" and "summerTree" with "winterTree"). I've tried a number of different things but the terrain doesn't seems to update, even after calling Flush().

    Code (csharp):
    1. Terrain.activeTerrain.terrainData.treePrototypes[0].prefab = GameObject.Find("WinterTree");
    2. Terrain.activeTerrain.terrainData.splatPrototypes[0].texture = Resources.Load("snow", Texture2D);
    3.  
    4. //I'm not sure if RefreshPrototypes() should be called or not, the terrain doesn't update either way
    5. Terrain.activeTerrain.terrainData.RefreshPrototypes();
    6.  
    7. //I know this _should_ be called, and it takes a while to run, but the terrain has no obvious change
    8. Terrain.activeTerrain.Flush();
    I basically just need to run an asset swap during gameplay, and the change is basically cosmetic (the tree and detail locations aren't changing, for instance). I've trawled the forums and found a fair amount of info on the terrain structure (which has been very handy), but I couldn't find anything definitive on this particular problem. I'm hoping it's just a matter of updating the terrain properly in-script, but any advice on how to change around the assets in the scripting would be appreciated as well.
     
    Knarhoi likes this.
  2. Antitheory

    Antitheory

    Joined:
    Nov 14, 2010
    Posts:
    549
    I'm guessing your problem is that you are trying to change individual prototypes and not the prototype array itself.
    Code (csharp):
    1.  
    2. TreePrototype[] tps = terrainData.treePrototypes;
    3. tps[0].prefab = Resources.Load(...)
    4. terrainData.treePrototypes = tps;
    5.  
    should work... There's no need to call RefreshPrototypes or Flush.

    There's probably some logic inside the Set accessor of those arrays that refreshes the terrain for you.
     
    Knarhoi likes this.
  3. Revontuli

    Revontuli

    Joined:
    May 12, 2011
    Posts:
    29
    That did it!

    To those who might also be trying this, the changes you make are permanent, unlike other script variables during runtime - I have a big scene that was authored by a separate artist, so I'll need to be careful I don't overwrite anything (and rely on source control when I do...). That might seem obvious, but could also come as a surprise if you're not prepared. I'm going to have to be very careful with name parsing for the next stage...

    Thanks again!
     
  4. rafaelfigueroa

    rafaelfigueroa

    Joined:
    Aug 24, 2011
    Posts:
    23
    TreePrototype[] tps = terrainData.treePrototypes;
    tps[0].prefab = Resources.Load("prefabx"); // Error here
    terrainData.treePrototypes = tps;

    Hi,
    When testing the code above, I got the error below in the second line.


    Assets/arvores.cs(25,8): error CS0266: Cannot implicitly convert type `UnityEngine.Object' to `UnityEngine.GameObject'. An explicit conversion exists (are you missing a cast?)

    Any ideas?
    Thanks.
     
  5. rafaelfigueroa

    rafaelfigueroa

    Joined:
    Aug 24, 2011
    Posts:
    23
    Hi again, already solve the matter... thanks anyway :)
     
  6. rafaelfigueroa

    rafaelfigueroa

    Joined:
    Aug 24, 2011
    Posts:
    23
    hello,
    Running this code under editor, if I load a prefab in line #2 ( tps[0].prefab=....), ok. If I load an AssetBundle, ok too while running, but when I stop, the editor crashes.
    Any idea?
    Thanks
     
  7. KEMBL

    KEMBL

    Joined:
    Apr 16, 2009
    Posts:
    181
    Try to unload Assetbundle before exit from application.
     
  8. 230000751

    230000751

    Joined:
    Jul 30, 2015
    Posts:
    12
    I realize this post is very old, but to anyone who may come across this, the changes made are only permanent if you do not cache your original arrays before the changes are made, and revert back to them when the application is ended. For example, here is my code for changing trees in runtime.
    _____________________________________________________________________________________________
    using UnityEngine;
    using System.Collections;

    public class TerrainTreeChanger : MonoBehaviour {

    private TreePrototype[] cache; //This is where your original trees are going to be saved!

    TreePrototype[] treeType;
    public GameObject swapwith;

    void Start()
    {
    cache = Terrain.activeTerrain.terrainData.treePrototypes;//IMPORTANT, if this cache is not assigned to the original array, then your changes will be permanent.
    treeType = Terrain.activeTerrain.terrainData.treePrototypes;
    }

    void Update () {

    if(Input.GetKeyDown("a")){

    treeType[0].prefab = swapwith;
    Terrain.activeTerrain.terrainData.treePrototypes = treeType;
    }
    }

    void OnApplicationQuit()
    {
    Terrain.activeTerrain.terrainData.treePrototypes = cache;//Revert to the original array when the application ends. Or simply call this function when you switch scenes.
    }

    }