I’d like to add a bit of seasonal flare to my trees which are not placed gameObjects in the hierachy, they are trees added via the Terrain paint widget. I created a gameObject test tree that pingpongs between red and green via script, added that tree into the terrain tree painter and put a few down but at runtime they don’t change. I had a feeling it wouldn’t be that easy
Is there a method to access a TERRAIN tree and modify it via script/C#?
Putting together parts I found on UA, forums, general Google search etc I have came up with the following. I’m not sure if I should post it given the warnings associated with changing TerrainData but it does what I wanted and could be extended to do much more. On the other hand, if a moderator thinks it should be deleted that’s ok.
using UnityEngine;
using System.Collections;
// WARNING WARNING WARNING: The sources I found to assist with this indicate these were/might still be undocumented APIs,
// and there's no undoing the changes made to your tree and terrain - it WILL NOT SNAP BACK when you click Stop in the Editor.
// There could be other complications as well. Use at your risk.
// Step 1. Create a tree/prefab and put it into the Terrain Tree Painter
// Step 2. Create the same tree/model/etc but change the color to simulate a Fall color scheme and add it to Terrain Tree Painter
// Step 3. Attach this to something
public class QM_TreeSeasons : MonoBehaviour
{
public TerrainData terrain; // drag the Terrain Data in Editor
public int treeCount;
public int treeTypes;
public TreeInstance[] currentTreeList;
private bool season;
// These values are the prefab/prototype index value spat out by Start()
public int springTreeIndex;
public int fallTreeIndex;
void Awake ()
{
treeCount = 0;
treeTypes = 0;
springTreeIndex = -1;
fallTreeIndex = -1;
}
void Start ()
{
//Set active terrain
terrain = Terrain.activeTerrain.terrainData;
// Setup a holding array
currentTreeList = new TreeInstance[terrain.treeInstances.Length];
// Get some numbers
treeTypes = terrain.treePrototypes.Length;
treeCount = terrain.treeInstances.Length;
// Displays some numbers
Debug.Log ("Tree types (i.e # of prefabs in Terrain tree painter: " + treeTypes);
Debug.Log ("They are: ");
// Search the trees and print the name and index
for (int cnt=0; cnt < terrain.treePrototypes.Length; cnt++) {
Debug.Log ("name: " + terrain.treePrototypes [cnt].prefab.name + " @ prototype index " + cnt);
}
}
// STOP STOP STOP:
// ChangeSeasons() changes your TerrainData and there's no going back.
// If you run this next block you will be changing, permanently,
// your TerrainData trees. Don't press "X" unless you are sure.
void ChangeSeasons ()
{
// Copy existing TreeInstances array contents into holding array
System.Array.Copy (terrain.treeInstances, currentTreeList, terrain.treeInstances.Length);
if (terrain.treeInstances.Length == currentTreeList.Length) {
for (int tcnt=0; tcnt < currentTreeList.Length; tcnt++) {
if (season) {
if (currentTreeList [tcnt].prototypeIndex == springTreeIndex) {
currentTreeList [tcnt].prototypeIndex = fallTreeIndex;
}
}
if (!season) {
if (currentTreeList [tcnt].prototypeIndex == fallTreeIndex) {
currentTreeList [tcnt].prototypeIndex = springTreeIndex;
}
}
}
terrain.treeInstances = currentTreeList;
season = !season;
}
}
// Having giving all the warnings above, if you want to toggle your trees, press X again
// I don't know if other stuff in your terrain data might be affected. Use at your own risk.
void Update ()
{
if (Input.GetKeyUp (KeyCode.X)) {
if (springTreeIndex == -1 || fallTreeIndex == -1) {
Debug.Log ("You have to set these values matching the desired models");
Debug.Log ("prefab index values shown in Debug.Log");
} else {
ChangeSeasons ();
}
}
}
}