#nullable enable using System.Collections.Generic; using Demo2.Domain; using Demo2.ECS; using Unity.Collections; using UnityEngine; namespace Demo2.Runtime { public sealed class Demo2ItemBatchRenderer : MonoBehaviour { [SerializeField] private Texture2D? itemTexture; private readonly List[] _matrices = { new(), new(), new(), new(), new(), new() }; private readonly Material[] _materials = new Material[6]; private Mesh? _quad; private Demo2EcsWorld? _world; public void Bind(Demo2EcsWorld? world) => _world = world; public void SetTexture(Texture2D texture) { itemTexture = texture; RebuildMaterials(); } private void Awake() { if (Application.isBatchMode) { enabled = false; return; } _quad = CreateQuad(); RebuildMaterials(); } private void LateUpdate() { if (_world == null || _quad == null) return; for (var i = 0; i < _matrices.Length; i++) _matrices[i].Clear(); var manager = _world.EntityManager; var query = manager.CreateEntityQuery(typeof(Demo2GridPosition), typeof(Demo2MaterialState)); using var entities = query.ToEntityArray(Allocator.Temp); using var positions = query.ToComponentDataArray(Allocator.Temp); using var materials = query.ToComponentDataArray(Allocator.Temp); for (var i = 0; i < entities.Length; i++) { var material = materials[i]; var x = positions[i].X + 0.5f; var y = Demo2Protocol.GridHeight - positions[i].Y - 0.5f; var offset = material.SubCellProgress / 1000f; switch (material.Direction & 3) { case 0: x += offset; break; case 1: y += offset; break; case 2: x -= offset; break; case 3: y -= offset; break; } var kind = Mathf.Clamp((int)material.Kind, 0, _matrices.Length - 1); if (_matrices[kind].Count < 1023) _matrices[kind].Add(Matrix4x4.TRS(new Vector3(x, y, -0.2f), Quaternion.identity, Vector3.one * 0.34f)); } for (var i = 0; i < _matrices.Length; i++) if (_materials[i] != null && _matrices[i].Count > 0) Graphics.DrawMeshInstanced(_quad, 0, _materials[i], _matrices[i]); } private void OnDestroy() { if (_quad != null) Destroy(_quad); for (var i = 0; i < _materials.Length; i++) if (_materials[i] != null) Destroy(_materials[i]); } private void RebuildMaterials() { var colors = new[] { new Color(0.52f, 0.66f, 0.78f), new Color(0.42f, 0.32f, 0.28f), new Color(0.82f, 0.82f, 0.76f), new Color(0.86f, 0.68f, 0.22f), new Color(0.84f, 0.23f, 0.18f), new Color(0.16f, 0.82f, 0.88f) }; var shader = Shader.Find("Universal Render Pipeline/Unlit") ?? Shader.Find("Unlit/Texture"); if (shader == null) { enabled = false; return; } for (var i = 0; i < _materials.Length; i++) { if (_materials[i] == null) _materials[i] = new Material(shader) { enableInstancing = true }; _materials[i].mainTexture = itemTexture; _materials[i].color = colors[i]; } } private static Mesh CreateQuad() { var mesh = new Mesh { name = "Demo2 Item Quad" }; mesh.SetVertices(new[] { new Vector3(-.5f, -.5f), new Vector3(-.5f, .5f), new Vector3(.5f, .5f), new Vector3(.5f, -.5f) }); mesh.SetUVs(0, new[] { new Vector2(0, 0), new Vector2(0, 1), new Vector2(1, 1), new Vector2(1, 0) }); mesh.SetTriangles(new[] { 0, 1, 2, 0, 2, 3 }, 0); mesh.RecalculateBounds(); return mesh; } } }