130 lines
4.4 KiB
C#
130 lines
4.4 KiB
C#
using UnityEngine;
|
|
using Unity.Collections;
|
|
using Unity.Jobs;
|
|
using UnityEngine.Jobs;
|
|
using Unity.Burst;
|
|
|
|
namespace Elbyss.Optimization
|
|
{
|
|
/// <summary>
|
|
/// Manages 10,000+ objects using C# Job System and Burst Compiler.
|
|
/// This avoids the overhead of 10,000 individual Update() calls.
|
|
/// </summary>
|
|
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<Vector3> 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<Vector3>(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<Animator>(out var anim)) anim.enabled = false;
|
|
if (go.TryGetComponent<CharacterController>(out var cc)) cc.enabled = false;
|
|
|
|
// Disable all other custom scripts
|
|
MonoBehaviour[] scripts = go.GetComponents<MonoBehaviour>();
|
|
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<Vector3> Directions;
|
|
|
|
public void Execute(int index, TransformAccess transform)
|
|
{
|
|
// Directly modify the transform position in parallel
|
|
transform.position += Directions[index] * Speed * DeltaTime;
|
|
}
|
|
}
|
|
}
|
|
}
|