🧩Unity Performance Optimization (NATV)
I. Giảm DrawCall
️ Dùng SRP Batcher của URP
Gom nhiều mesh có cùng shader vào 1 batch drawcall, giúp giảm đáng kể chi phí CPU khi render nhiều object như monster hoặc vật cản.
Bật trong Project Settings → Graphics → SRP Batcher

🧱 Dùng chung Shader / Material / Layer
- Chuyển các vật cản, nơi đứng của monster thành Spine Animation (shader:
Universal Render Pipeline/2D/Spine/Skeleton)
- Dùng Layer giống nhau giữa monster và vật cản để SRP gom vào chung batch
- Việc biến
SpriteRenderer thành Spine Animation rất đơn giản – tham khảo CreateSpineAnimForTextureExtensions.cs

Vòng tròn đỏ: Skeleton Animation
🟢 Vòng tròn xanh: Sprite Renderer
🧩 Sprite Renderer – Dùng chung Material & Atlas
Khi vẫn dùng SpriteRenderer, cần dùng chung material và chung atlas để Unity nhóm các sprite lại thành 1 drawcall.

GPU Instancing
Dùng cho các object giống nhau:
Ví dụ: cỏ, hiệu ứng vòng tròn tấn công, đá nhỏ, lá rơi, …
→ Giúp giảm drawcall mà vẫn giữ hiệu ứng động.
🧭 Sắp xếp Layer hợp lý
- Layer 1: Mặt đất, cây cỏ, rác, đá sỏi, các vật có thể bị đạp lên.
- Layer 2: Monster, hero, effect, dog, base, obstacle – nơi các vật thể có thể che nhau.

II. Optimize CPU
Giảm đối tượng cần vẽ / tính toán
Monster nằm ngoài camera chỉ cần cập nhật logic, không cần render.
→ Trong SkeletonAnimation, bật:
Advanced → Update When Invisible → Only Event Timelines

Loại bỏ Collider / Rigidbody không cần thiết
Dùng hệ thống va chạm logic tự tính thay cho vật lý thật:
- Tính khoảng cách giữa tâm hero và monster.
- Nếu nhỏ hơn bán kính kỹ năng → trong phạm vi tấn công.
→ Tham khảo: DetectCollideManager.cs.
III. Optimize Addressables
Tổ chức theo Chapter
Mỗi chapter là 1 group riêng, chọn Pack Together để Unity build thành 1 bundle duy nhất → gọn nhẹ, dễ load/unload.

Không bỏ Scene vào Addressable
Scene luôn bị build dạng Pack Separately, dễ bị duplicate asset → tăng size bundle và memory.
🧾 Config chỉ chứa data cơ bản
- Chỉ nên chứa text, number, config JSON.
- Không chứa sprite, texture, sound để tránh trùng atlas.
- Nếu buộc phải có sprite → bỏ tích Include in Build trong atlas và dùng
SpriteAtlasManager để load thủ công.

Tham khảo: SpriteAtlasAddressableLoader.cs
Tài liệu: Unity SpriteAtlasManager
️ Giải phóng tài nguyên đúng cách
Mọi handle async của Addressables (LoadAssetAsync, InstantiateAsync, …)
→ Phải gọi Addressables.Release(handle) khi không dùng nữa.
IV. Optimize Memory
Không tạo object mới mỗi frame
Không new string, new List, new Dictionary... trong Update → gây GC Alloc liên tục.
→ Dùng biến cache hoặc List.Clear() để tái sử dụng.

🧹 Dọn dẹp bộ nhớ
Khi đổi scene, gọi:
Addressables.ReleaseUnusedAssets();
Resources.UnloadUnusedAssets();
Có thể thêm GC.Collect() trong màn hình loading để thu hồi managed memory.
🧱 Giảm phân mảnh bộ nhớ
- Dùng
List, Queue, Stack, Dictionary có capacity cố định.
- Tính trước kích thước hợp lý ngay từ đầu để tránh
reallocate.
- Tham khảo code gốc của .NET
List<T>:
List.cs#L198
- Dùng Object Pooling cho object tạo–hủy thường xuyên (đạn, hiệu ứng, popup...).
V. Optimize Spine Animation
- Gom tất cả monster cùng chapter vào 1 atlas duy nhất
→ ví dụ: Chapter_01_Monsters.atlas, Chapter_02_Monsters.atlas.
- Nếu vùng sprite là hình lồi, cắt lồi để giảm vertices/triangle.
- Bật Triangulate Low Detail hoặc giảm precision vùng mesh.
- Tránh sprite có alpha phức tạp hoặc chi tiết biên thừa.
- Giảm bone, attachment, slot không cần thiết.
- Gộp nhiều attachment tĩnh thành 1 sprite duy nhất.
- Xóa bone test, placeholder, slot không render.
- Animation đơn giản (vd: idle) chỉ cần 2 keyframe đầu/cuối (Spine tự nội suy).
- Xóa keyframe dư và animation không dùng runtime.
VI. Optimize Texture
- Dùng ASTC thay vì RGBA32 để giảm kích thước build và RAM.
- Dùng ASTC 10×10 hoặc 12×12 nếu chất lượng hình ảnh vẫn ổn.
- Gom sprite hợp lý vào atlas để giảm texture switch.
VII. Optimize UIToolkit
- Dùng
usageHints:
Giúp Unity xác định cách tối ưu layout và render cho UI element.
- Giảm thay đổi transform:
Không thay đổi position, rotation, scale thường xuyên — vì sẽ rebuild layout gây tốn CPU.
VIII. Optimize Âm Thanh
- Decompress On Load:
Cho âm thanh phát liên tục (bắn, hit, bước chân).
- Streaming:
Cho âm thanh dài (nhạc nền, voice, cutscene).
- Compress In Memory:
Cho âm thanh ngắn, ít khi phát (click UI, hiệu ứng nhỏ).
- Load In Background:
Dùng cho các âm thanh không yêu cầu độ chính xác cao để không chặn luồng chính.
IX. Optimize Script
-
Cache các giá trị dùng nhiều:
Animator.StringToHash (trigger animation).
LayerMask.GetMask, LayerMask.NameToLayer.
Camera.main (vì gọi lại sẽ FindGameObjectWithTag).
-
Tạo collection có capacity cụ thể:
new List<int>(64) hoặc new Dictionary<string, int>(32) để tránh mở rộng mảng.
-
Dùng HashSet thay List:
Nếu chỉ cần kiểm tra Contains, Add, Remove – tốc độ nhanh hơn nhiều.
-
Local Function:
Đặt ở lớp ngoài cùng, truyền tham số rõ ràng để tránh GC capture closure.
- Xoá các hàm Update() hoặc FixedUpdate() nếu không dùng đến