How do I create random game objects on a terrain, but only inside the terrain area?

I have the following code that generates game objects, in my game. The problem with it is that some game objects are out of the terrain area. I want to place them at random, but also make sure they will be inside the terrain area.

I know that I get the terrain size with terrain.terrainData.size, but I'm not sure how to use it. How do I create random game objects on a terrain, but only inside the terrain area?

Here is my current script:

using UnityEngine;

public class Teleport : MonoBehaviour
{
public Vector3 terrainArea;
public float spinSpeed = 2.0f;
public int cloneTeleportations;
public GameObject prefab;

private bool rotate = false;
private bool exited = false;
private Transform[] teleportations;
private Random rnd = new Random();

private void Start()
{
GameObject go = GameObject.Find("Terrain");
Terrain terrain = go.GetComponent(Terrain);
terrainArea = terrain.terrainData.size;

for (int i = 0; i < cloneTeleportations; i++)
{
GameObject Teleportaion = Instantiate(prefab,
new Vector3(Random.Range(i * 10.0F, i * 50.0F), 0,
Random.Range(i * 10.0F, i * 50.0F)), Quaternion.identity);
Teleportaion.transform.parent = this.transform;
Teleportaion.transform.tag = "Teleportation";
}
}
}

• So if you want the random to be within the terrain, then maybe plug the terrain size into the random function? At which point you just need to add the terrain's position. – Draco18s no longer trusts SE May 16 '17 at 1:36

In order to restrict your instantiated objects to the confines of the terrain; you need to use the measurements of the terrain during the randomise method used to determine the position of each instantiated object. Your pretty much already there - we just need to implement a bit more little maths. Specifically, the boundary of the terrain.

Determining the boundary of the Terrain

We already find the size of the terrain with Terrain.terrainSize.size; this gives us the measurements of the terrain, in world space. You will also notice that the terrain appears, in your scene view, to expand outwards from the core game object. That is, your "origin" is at the bottom left corner. We can thus use transform.position to find our complete boundary.

The boundary of the terrain can thus be described as transform.position.x to transform.position.x + terrain.terrainSize.size.x, along the x axis, and transform.position.z to transform.position.z + terrain.terrainSize.size.z, along the z axis.

Using the Terrain boundary to limit object placement

Now that we have the boundary, all we need to do is provide this boundary when we randomly place instantiated objects. At this point, we do not really have much use for the i indexor, so I have moved instantiate into its own method. All i does, in the functionality you provide, is extrapolate the range of our instantiated position. As such, it works against us for setting the game objects to the confines of the terrain.

private float xMinimum, xMaximum, zMinimum, yMinimum;

private void Start()
{
// ... Get Terrain reference and terrainArea

xMinimum = transform.position.x;
zMinimum = transform.position.z;
xMaximum = xMinimum + terrainArea.x;
zMaximum = zMinimum + terrainArea.z;

for (int i = 0; i < cloneTeleportations; i++)
{
InstantiateGameObject();
}
}

private void InstantiateGameObject()
{
GameObject newGameObject = Instantiate(prefab,
new Vector3(Random.Range(xMinimum, xMaximum), 0,
Random.Range(zMinimum, zMaximum)), Quaternion.identity);

newGameObject.transform.parent = this.transform;
newGameObject.transform.tag = "Teleportation";
}