using UnityEngine; using Unity.Collections; using Unity.Jobs; using UnityEngine.Jobs; using Unity.Burst; namespace Elbyss.Optimization { /// /// Manages 10,000+ objects using C# Job System and Burst Compiler. /// This avoids the overhead of 10,000 individual Update() calls. /// public class JobsMovementManager : MonoBehaviour { [Header("Spawn Settings")] public GameObject prefab; public int objectCount = 10000; public float spacing = 1.5f; [Header("Movement Settings")] public float speed = 5f; private TransformAccessArray transformAccessArray; private NativeArray directions; private bool isInitialized = false; private void Start() { // Optional: Start automatically or via Context Menu // Setup(objectCount); } [ContextMenu("Setup 10k Objects")] public void InitialSetup() { Setup(objectCount); } public void Setup(int count) { if (isInitialized) Cleanup(); objectCount = count; Transform[] transforms = new Transform[objectCount]; directions = new NativeArray(objectCount, Allocator.Persistent); int rowSize = Mathf.CeilToInt(Mathf.Sqrt(objectCount)); for (int i = 0; i < objectCount; i++) { float x = (i % rowSize) * spacing; float z = (i / rowSize) * spacing; Vector3 pos = transform.position + new Vector3(x, 0, z); GameObject go = Instantiate(prefab, pos, Quaternion.identity, this.transform); transforms[i] = go.transform; // Set alternating directions directions[i] = (i % 2 == 0) ? Vector3.forward : Vector3.back; // CRITICAL OPTIMIZATION: Disable components that are too heavy for 10k objects if (go.TryGetComponent(out var anim)) anim.enabled = false; if (go.TryGetComponent(out var cc)) cc.enabled = false; // Disable all other custom scripts MonoBehaviour[] scripts = go.GetComponents(); foreach (var s in scripts) { if (s != this) s.enabled = false; } } transformAccessArray = new TransformAccessArray(transforms); isInitialized = true; Debug.Log($"Initialized {objectCount} objects with Job System."); } private void Update() { if (!isInitialized) return; // Create the movement job var job = new MovementJob { DeltaTime = Time.deltaTime, Speed = speed, Directions = directions }; // Schedule the job to run in parallel on all available CPU cores // transformAccessArray allows the job to modify Transform data directly JobHandle handle = job.Schedule(transformAccessArray); // This ensures the job is finished before the frame ends // In a real scenario, you might want to call Complete() in LateUpdate or next frame // but for simple movement, scheduling and completing in Update is fine. handle.Complete(); } private void OnDestroy() { Cleanup(); } private void Cleanup() { if (isInitialized) { if (transformAccessArray.isCreated) transformAccessArray.Dispose(); if (directions.IsCreated) directions.Dispose(); isInitialized = false; } } [BurstCompile] // This attribute tells the Burst compiler to optimize this job into machine code struct MovementJob : IJobParallelForTransform { public float DeltaTime; public float Speed; [ReadOnly] public NativeArray Directions; public void Execute(int index, TransformAccess transform) { // Directly modify the transform position in parallel transform.position += Directions[index] * Speed * DeltaTime; } } } }