Spawning Script Not Working

I have a collectable that I am trying to spawn on terrain. I have 2 Vector3s which are the bounds of the spawning (they make the collectable always within the terrain), and then when I pick a random x and z coordinate within those boundaries (with a y coordinate that is above all terrain). Then, I shoot a raycast directly down and set the collectable’s y coordinate to y of the point that was hit.

However, it seems like the raycast never hits anything because the Debug.Log isn’t printing out into the console. I don’t know why it doesn’t hit though, since the collectables always spawn within the terrain (the terrain has a terrain collider, it doesn’t have a physics material if that is important)

using UnityEngine;

public class CollectableSpawner : MonoBehaviour
{
    public int spawnedCollectables;

    [SerializeField] private Vector3 corner;
    [SerializeField] private Vector3 oppositeCorner;

    [SerializeField] private LayerMask prohibitedSpawnAreaLayer;
    [SerializeField] private GameObject collectable;

    private int collectables;

    private void Awake() => collectables = Random.Range(PlayerCollectableManager.MinCollectables, PlayerCollectableManager.MaxCollectables + 1);

    private void Start()
    {
        while (spawnedCollectables != collectables)
        {
            Vector3 _spawnPosition = new Vector3(Random.Range(corner.x, oppositeCorner.x), 100, Random.Range(corner.z, oppositeCorner.z));

            Transform _collectableTransform = Instantiate(collectable).GetComponent<Transform>();
            _collectableTransform.position = _spawnPosition;

            if (Physics.OverlapBox(_collectableTransform.position, _collectableTransform.localScale / 2,
                Quaternion.identity, prohibitedSpawnAreaLayer).Length > 0)
            {
                Destroy(_collectableTransform.gameObject);
                continue;
            }

            //following code should bring collectable down
            Ray _downRay = new Ray(_collectableTransform.position, new Vector3(_collectableTransform.position.x,
                Mathf.NegativeInfinity, _collectableTransform.position.z));

            //placing spawnedCollectables += 1; inside the if makes an infinite loop
            if (Physics.Raycast(_downRay, out RaycastHit _hitInfo))
            {
                Debug.Log($"Raycast point y: {_hitInfo.point.y}");
                _collectableTransform.position = new Vector3(_collectableTransform.position.x, _hitInfo.point.y, _collectableTransform.position.z);
                _collectableTransform.rotation = Random.rotation;
            }

            spawnedCollectables += 1;
        }
    }
}

You either have a layer problem, or the terrain doesn’t have a appropriate collider. For one, raycast’s are expensive performance wise, so if you have these spawners spawning above terrain and they fall to the ground, I would just use a standard collision check. if hit terrain = ready for business!

I tried adding a rigidbody and activating gravity when needed, but it falls really slowly even when I make the mass super high. Is there a better way for me to do it? Also, what do you mean by a layer problem?

If the terrain isn’t set to the terrain layer, or if your ray does layer masking(which it doesn’t look like it does).

But you don’t need physics, just do transform.Translate(0, -speed, 0) . After finding a desired speed. Just don’t go too fast, because it can “skip” pass terrain if the movement is too high.

Unless you have trees and such that it might clip through, then true, it’s better to use a rigidbody and keep bouncing until it hits terrain. But not sure why gravity won’t pull it down faster, if I ever set gravity just a smidge too high it’ll fly through the map. Unless you set drag immensely high? drag should be non-existent or at least very low.

Also, I just noticed you have all this running in your Start() method, the checks should be in Update() or FixedUpdate() if using physics. As your “while” method might be cutting off too short for anything to finish thinking.