I’m trying to build the basis for a simple point-and-click 3D game, where you control a character that picks up randomly spawned objects. It was working fine until I switched my ground plane from the standard 3D plane to an imported, slightly more complicated ground object that I made in blender.
The control script for the player works fine - it casts a ray that hits the mesh collider on the ground object, and moves the player to that spot.
I also have a script that spawns new objects for the player to pick up, at random locations on the ground object. It does this also by raycasting. It generates a random point above the ground, and then raycasts directly down and is supposed to spawn a random object at that location. However, it keeps failing the raycast. And I can’t figure out why. I’ve check the tags and layers, and everything should match up OK.
TLDR: The code below works perfectly if the ground is a standard plane (or cube) from the Unity 3D object menu, but the raycast fails whenever the ground plane is a mesh collider on slightly more complex object:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
public class PickupSpawner : MonoBehaviour
{
[SerializeField]
public List <GameObject> pickupObjects;
public Vector2 minMaxSecondsBetweenSpawns;
public float maxObjectsInScene = 5f;
private GameObject groundPlane;
private List<GameObject> activePickupsInScene;
private GameObject[] objectTypeHolder;
private bool currentlySpawning = false;
LayerMask layerMask;
private void Start()
{
layerMask = LayerMask.GetMask("Ground");
groundPlane = GameObject.FindGameObjectWithTag("GroundPlane");
}
void Update()
{
activePickupsInScene = GameObject.FindGameObjectsWithTag("Type0").ToList();
activePickupsInScene.AddRange(GameObject.FindGameObjectsWithTag("Type1"));
activePickupsInScene.AddRange(GameObject.FindGameObjectsWithTag("Type2"));
//add more types as necessary
if (activePickupsInScene.Count < maxObjectsInScene && !currentlySpawning)
{
StartCoroutine (spawnNewPickup());
}
}
IEnumerator spawnNewPickup()
{
currentlySpawning = true;
int randomItemIndex = Random.Range(0, pickupObjects.Count);
GameObject newPickup = Instantiate(pickupObjects[randomItemIndex], pickRandomLocation(), Quaternion.identity) as GameObject;
Debug.Log("Instantiating pickup at " + newPickup.transform.position);
newPickup.tag = PickupObjects.setPickupType(pickupObjects[randomItemIndex].name);
newPickup.transform.parent = gameObject.transform;
float waitCount = Random.Range(minMaxSecondsBetweenSpawns.x, minMaxSecondsBetweenSpawns.y);
yield return new WaitForSeconds(waitCount);
currentlySpawning = false;
}
private Vector3 pickRandomLocation()
{
float terrainScaleX = groundPlane.transform.localScale.x * 0.5f;
float terrainScaleZ = groundPlane.transform.localScale.z * 0.5f;
Vector3 randomLocation = new Vector3(Random.Range(-terrainScaleX, terrainScaleX), 25f, Random.Range(-terrainScaleZ, terrainScaleZ));
Debug.Log("Random location at " + randomLocation);
Ray ray = new Ray(randomLocation, Vector3.down);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 5000f, layerMask))
{
Debug.Log("Raycast hit at " + hit.point);
return hit.point;
}
else
{
Debug.Log("Pickup spawn raycast failed!");
return Vector3.zero;
}
}
}