Reputation: 5
I have mountains, valleys and hills. But objects only spawn near valleys and in lower areas, not on hills:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ResourceGenerator : MonoBehaviour
{
[Header("Spawn settings")]
public GameObject resourcePrefab;
public float spawnChance;
[Header("Raycast setup")]
public float distanceBetweenCheck;
public float heightOfCheck = 1000f, rangeOfCheck = 30f;
public LayerMask layerMask;
public Vector2 positivePosition, negativePosition;
private void Start()
{
SpawnResources();
}
void SpawnResources()
{
for(float x = negativePosition.x; x < positivePosition.x; x += distanceBetweenCheck)
{
for(float z = negativePosition.y; z < positivePosition.y; z += distanceBetweenCheck)
{
RaycastHit hit;
if(Physics.Raycast(new Vector3(x, heightOfCheck, z), Vector3.down, out hit, rangeOfCheck, layerMask))
{
if(spawnChance > Random.Range(0f, 101f))
{
Instantiate(resourcePrefab, hit.point, Quaternion.Euler(new Vector3(0, Random.Range(0, 360), 0)), transform);
}
}
}
}
}
}
Upvotes: 0
Views: 66
Reputation: 90813
Well
your raycast is checking from a certain heightOfCheck
downwards whether it hits your terrain / ground.
Further it is limited to only check at a maximum distance of rangeOfCheck
from that heightOfCheck
.
=> For rangeOfCheck
you should make sure it can even reach far enough down to hit your surface -> rangeOfCheck
should be at least >= heightOfCheck
depending whether your terrain can also have ground levels < 0
.
So for instance it can only hit the ground at places where ground level < heightOfCheck
and at the same time where the rangeOfCheck
is big enough to reach down to the ground.
So assuming your terrain has only positive ground levels with a maximum height of 200
I would use something slightly bigger like e.g. heightOfCheck = 205
and then ensure that rangeOfCheck
can actually again reach 0
so I would again add a little buffer like e.g. rangeOfCheck = heightOfCheck + 5;
.
The 5
is completely arbitrary - could be any positive value that ensures you start high enough and also end low enough, so you could use a single variable field and do e.g.
const float raycastBuffer = 5f;
public float maxTerrainHeight = 1000f;
void SpawnResources()
{
...
var startPoint = new Vector3(x, maxTerrainHeight + raycastBuffer, z);
if(Physics.Raycast(startPoint, Vector3.down, out var hit, maxTerrainHeight + 2 * raycastBuffer, layerMask))
...
}
Upvotes: 0