Brilliant. I was able to write a script that does exactly what I wanted it to (See Below). It has to be attached to a game object, but then it can be executed from the inspector’s context menu.
I made it such that the overlap capsule used to check for proximity takes its shape from a capsuleCollider2D that you can set in the inspector, alongside a layermask of layers to check against.
In order for the prefabs to check proximity with each other, I had to make this function into a coroutine so that it executes over multiple frames. It does the job. To make it more efficient, what I could have done instead would have been to make it generate the coordinates beforehand, and calculate the proximity numerically, then instantiate all the prefabs on the same frame. The original method can be used to check for proximity to other pre-existing game objects.
Tilemap composite collider geometry must be set to polygons instead of outlines for the proximity detection to work properly with them. They can be changed back afterwards.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class PlantTrees : MonoBehaviour
{
#if UNITY_EDITOR
[SerializeField] GameObject treePrefab;
[SerializeField] Transform parent;
[SerializeField] int number = 1;
[SerializeField] float minX, maxX, minY, maxY;
[SerializeField] AnimationCurve sizeDistribution = AnimationCurve.Constant(0f,1f,1f);
[SerializeField] float minScale =1f;
[SerializeField] float maxScale = 1f;
[SerializeField] Color[] colors;
[SerializeField] LayerMask proximityLayerMask;
[SerializeField] CapsuleCollider2D proximityShape;
[SerializeField] int maxAttempts = 1000;
private void OnValidate() {
if (number<1) number = 1;
}
[ContextMenu("Generate Prefabs")]
void InstantiatePrefabs() {StartCoroutine(InstantiatePrefabsRoutine());}
IEnumerator InstantiatePrefabsRoutine()
{
for(int i =0;i<number;i++){
GameObject tree;
if (parent==null) {tree = PrefabUtility.InstantiatePrefab(treePrefab) as GameObject;}
else {tree = PrefabUtility.InstantiatePrefab(treePrefab,parent) as GameObject;}
Vector2 randomCoordinates = GetRandomCoordinates();
int attempt = 0;
while(ProximityCheck(randomCoordinates)){
randomCoordinates = GetRandomCoordinates();
attempt++;
if(attempt>maxAttempts){
Debug.LogWarning("max attempts have been reached. Prefabs Instantiated: "+ i);
yield break;
}
}
tree.transform.position = randomCoordinates;
tree.transform.localScale = Vector3.one*(minScale+((maxScale-minScale)*sizeDistribution.Evaluate(Random.value)));
if(colors.Length>0){
tree.GetComponent<SpriteRenderer>().color= colors[Random.Range(0,colors.Length-1)];
}
yield return null;
}
Debug.Log("Success!");
}
private Vector2 GetRandomCoordinates(){
return new Vector2(Random.Range(minX,maxX),Random.Range(minY,maxY));
}
private bool ProximityCheck(Vector2 coordinates){
if(proximityShape==null) return false;
return Physics2D.OverlapCapsule(coordinates,proximityShape.size,proximityShape.direction,0,proximityLayerMask);
}
#endif
}