- Home /
How can i spawn new gameobjects to be inside the terrain area ?
I have two problems.
First I'm cloning objects inside the terrain area only. The problem is when i change the objects size for example to 50 some of them if they are near the terrain edge half of them inside the terrain half outside. And i want to make sure that all the objects in this case cubes will be inside the terrain area. How can i fix it ?
Second problem, How can i make a new variable to set the minimum space between each cubes ? Since i spawn them in random position the space between them is also random but i want to be able to change and set the minimum space that should be between them. For example if the minimum space is 10 then the random space between the cubes should be 10 and above. Random of course since i spawn them in random positions but the spaces between each cubes should be minimum 10 or what ever i will set.
This is the script i'm using:
using System;
using UnityEngine;
using Random = UnityEngine.Random;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class CloneObjects : MonoBehaviour {
public GameObject objectToClone;
public int objectsStartingHeight = 20;
[HideInInspector]
public GameObject[] objects;
// for tracking properties change
private Vector3 _extents;
private int _objectCount;
private float _objectSize;
/// <summary>
/// How far to place spheres randomly.
/// </summary>
public Vector3 Extents;
/// <summary>
/// How many spheres wanted.
/// </summary>
public int ObjectCount;
public float ObjectSize;
// Use this for initialization
void Start () {
Clone();
objects = GameObject.FindGameObjectsWithTag("objectToClone");
}
private void OnValidate()
{
// prevent wrong values to be entered
Extents = new Vector3(Mathf.Max(0.0f, Extents.x), Mathf.Max(0.0f, Extents.y), Mathf.Max(0.0f, Extents.z));
ObjectCount = Mathf.Max(0, ObjectCount);
ObjectSize = Mathf.Max(0.0f, ObjectSize);
}
private void Reset()
{
Extents = new Vector3(250.0f, 20.0f, 250.0f);
ObjectCount = 100;
ObjectSize = 20.0f;
}
// Update is called once per frame
void Update () {
}
private void Clone()
{
if (Extents == _extents && ObjectCount == _objectCount && Mathf.Approximately(ObjectSize, _objectSize))
return;
// cleanup
var ObjectToDestroy = GameObject.FindGameObjectsWithTag("ClonedObject");
foreach (var t in ObjectToDestroy)
{
if (Application.isEditor)
{
DestroyImmediate(t);
}
else
{
Destroy(t);
}
}
var withTag = GameObject.FindWithTag("Terrain");
if (withTag == null)
throw new InvalidOperationException("Terrain not found");
for (var i = 0; i < ObjectCount; i++)
{
var o = Instantiate(objectToClone);
o.tag = "ClonedObject";
o.transform.SetParent(base.gameObject.transform);
o.transform.localScale = new Vector3(ObjectSize, ObjectSize, ObjectSize);
// get random position
var x = Random.Range(-Extents.x, Extents.x);
var y = Extents.y; // sphere altitude relative to terrain below
var z = Random.Range(-Extents.z, Extents.z);
// now send a ray down terrain to adjust Y according terrain below
var height = 10000.0f; // should be higher than highest terrain altitude
var origin = new Vector3(x, height, z);
var ray = new Ray(origin, Vector3.down);
RaycastHit hit;
var maxDistance = 20000.0f;
var nameToLayer = LayerMask.NameToLayer("Terrain");
var layerMask = 1 << nameToLayer;
if (Physics.Raycast(ray, out hit, maxDistance, layerMask))
{
var distance = hit.distance;
y = height - distance + y; // adjust
}
else
{
Debug.LogWarning("Terrain not hit, using default height !");
}
//o.transform.Rotate(0.0f,randomNumbers[i],0.0f);
// place !
o.transform.position = new Vector3(x, y+objectsStartingHeight, z);
}
_extents = Extents;
_objectCount = ObjectCount;
_objectSize = ObjectSize;
}
}
And this is when i set the size to 50 in some places the cubes half in half out the terrain:
And this is a screenshot show the script settings in the inspector: Y is set to 0.5 and creating 10 objects and the size of each object is 50. All the objects have the same size.
And last the terrain position is X = -250 Y = 0 and Z = -250 The terrain size is Width = 500 Length = 500 Height = 600
Answer by Rhombuster · Mar 29, 2017 at 11:23 PM
I was helping you on the other site, but I didn't have an account so it wouldn't let me comment on your other question. You're working with randomness, so if you really want to avoid clipping and keeping it in bounds.
1) Do a raycast from the corner of each cube (4 raycasts per cube).
2) if any of the rays don't hit the terrain OR hit another cube, reject this position and rerun this iteration of the loop
This will be slow, but you aren't doing it at run time so you should be ok.
I added more 3 lines:
var ray1 = new Ray(origin, Vector3.up);
var ray2 = new Ray(origin, Vector3.left);
var ray3 = new Ray(origin, Vector3.right);
Is that right ? And the rest i'm not sure yet how to do it.
Answer by UnityCoach · Mar 30, 2017 at 11:57 AM
Here are a few things to consider :
1) you don't need to parent objects to work with a local position, you can use Transform.InverseTransformPoint() and Transform.TransformPoint() to get an object's position in another's space.
2) you can access the Object Mesh via the MeshFilter, and get its bounds to know how far off the terrain edge it should land. This will be useful if/when you need to rotate objects.
3) I would only use RayCasting to locate the terrain height/normal and align objects.
Your answer
Follow this Question
Related Questions
How can i make the spaceship to land/take off with physics vertical ? 2 Answers
To pass a variable between scenes should I use scriptableobject or static ? 1 Answer
How can i prevent from mouse to collide with thirdpersoncontroller ? 0 Answers
How can i lock the mouse cursor in the middle of the screen ? 1 Answer