using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using Unity.Collections; using Unity.Burst; using Unity.Jobs; using Unity.Mathematics; public class Game : MonoBehaviour { [SerializeField] private int numBlues; [SerializeField] private int numReds; [SerializeField] private GameObject bluePrefab; [SerializeField] private GameObject redPrefab; [SerializeField] private Rect[] areasOfTheMap; private int maxQuadTreeSize; private Transform[] blueTransforms; private Transform[] redTransforms; private NativeArray bluePositions; private NativeArray redPositions; private NativeArray quadTree; private NativeArray nearestEnemyOfBlueIndex; private NativeArray nearestEnemyOfRedIndex; public void Start() { blueTransforms = new Transform[numBlues]; redTransforms = new Transform[numReds]; int nearestPowerOf2(int n) { int a = (int)(Math.Log(n) / Math.Log(2)); return (int)Math.Pow(2, a) == n ? n : (int)Math.Pow(2, a + 1); } maxQuadTreeSize = nearestPowerOf2(numBlues + numReds); // This is actually the size of the max subdivisions int maxSubDivisions = 5; maxQuadTreeSize = (int)Math.Pow(4, maxSubDivisions); Debug.Log(maxQuadTreeSize); void InstantiatePrefabs(int amount, GameObject prefab, Transform[] transforms, Rect area) { for (int i = 0; i < amount; i++) { var go = GameObject.Instantiate(prefab); transforms[i] = go.transform; float randX = UnityEngine.Random.Range(area.x, area.x + area.width); float randY = UnityEngine.Random.Range(area.y, area.y + area.height); go.transform.localPosition = new Vector3(randX, 0, randY); } }; InstantiatePrefabs(numBlues, bluePrefab, blueTransforms, areasOfTheMap[0]); InstantiatePrefabs(numReds, redPrefab, redTransforms, areasOfTheMap[1]); bluePositions = new NativeArray(numBlues, Allocator.Persistent); redPositions = new NativeArray(numReds, Allocator.Persistent); quadTree = new NativeArray(maxQuadTreeSize, Allocator.Persistent); nearestEnemyOfBlueIndex = new NativeArray(numBlues, Allocator.Persistent); nearestEnemyOfRedIndex = new NativeArray(numReds, Allocator.Persistent); } float2 Vec3ToF2(Vector3 v) => new float2(v.x, v.z); public void Update() { int i = 0; int min = numBlues > numReds ? numBlues : numReds; while (i < min) { bluePositions[i] = Vec3ToF2(blueTransforms[i].localPosition); redPositions[i] = Vec3ToF2(redTransforms[i].localPosition); i++; } while (i < numBlues) { bluePositions[i] = Vec3ToF2(blueTransforms[i].localPosition); i++; } while (i < numReds) { redPositions[i] = Vec3ToF2(redTransforms[i].localPosition); i++; } var constructJob = new ConstructQuadTreeJob { positions = bluePositions, quadTree = quadTree, }; var constructHandle = constructJob.Schedule(maxQuadTreeSize, 100); constructHandle.Complete(); var findEnemyJob = new FindNearestEnemyQuadTreeJob { bluePositions = bluePositions, redPositions = redPositions, quadTree = quadTree, nearestEnemyOfBlueIndex = nearestEnemyOfBlueIndex, nearestEnemyOfRedIndex = nearestEnemyOfRedIndex, }; var findRedsHandle = findEnemyJob.Schedule(numBlues, 100); // We don't have a dependency on findRedsHandle, but we do have to wait for both // findReds and findBlues to finish findRedsHandle.Complete(); var findBluesHandle = findEnemyJob.Schedule(numReds, 100); findBluesHandle.Complete(); } public void OnDestroy() { bluePositions.Dispose(); redPositions.Dispose(); quadTree.Dispose(); } }