How to add prefabs to the terrain and still retain scripts, colliders, etc.?

I have been working on an old DOS-styled game, and I began work on the trees for my terrain. Here is a group of them:

They, right now, are simply objects in the scene. This works, but is very cumbersome when mass placing them. I want to have them part of the terrain. I tried simply adding them as a detail mesh, but they didn't retain scripts nor colliders. Is there a way to accomplish this?

There’s no way to do it directly because they are no longer GameObjects for performance reasons. However, if you add them as tree objects on the terrain, you can write a script that runs on awake which gets the position of the trees and replaces them all programmatically with an instantiated prefab. Use Terrain.terrainData.treeInstances for this purpose:

(Note: This is untested)

using UnityEngine;

[RequireComponent(typeof(Terrain))]
public class TreeSwapper : MonoBehaviour
{
//Fill this in the inspector with the prefabs to use in place of the tree prototypes defined in the Terrain object.
public GameObject[] TreePrototypes;

void Awake()
{
var data = GetComponent<Terrain>().terrainData;

foreach (var instance in data.treeInstances) {
var tree = Instantiate(TreePrototypes[instance.prototypeIndex], instance.position, Quaternion.euler(0,Mathf.Rad2Deg * instance.rotation,0), transform);
tree.transform.localScale = new Vector3(instance.widthScale, instance.heightScale, instance.widthScale);
}
data.treeInstances = new TreeInstance[0];
}
}


Note to anybody using this: Terrain does what it does for a very good reason: performance. Don’t expect to be able to put down a ton of trees, run this script, and expect continued good performance.

For that matter, having a script on every tree is a very uncommon use case. You may want to re-examine what you’re doing. Does each tree really need to be doing its own thing?

• Would you happen to have a script that does this? Jan 24 '18 at 1:54
• Sample added. See above. It's currently untested though, and there are some optimizations to be made. Jan 24 '18 at 1:59
• Ok, got the position stuff figured out, but the Quaternion.euler still isn't working right. Jan 24 '18 at 2:31
• What's happening? Depending on your needs, simply using Quaternion.identity may be sufficient. Jan 24 '18 at 2:42
• I fixed that and a few more issues (going to edit code once this last issue is solved). Here is my current line 11: GameObject tree = Instantiate(TreePrototypes[instance.prototypeIndex], transform.position, transform.rotation); it tells me: Cannot implicitly convert type 'UnityEngine.Object' to 'UnityEngine.GameObject'. An explicit conversation exists (are you missing a cast?) do you know how to fix this issue? Jan 24 '18 at 2:47