Hero image

Mẹo tối ưu hóa Unity UI

Hãy tìm hiểu cách tối ưu hóa hoàn toàn giao diện người dùng của bạn, với các mẹo về cách chia Canvas và Nhóm bố cục, gộp các đối tượng giao diện người dùng, và hơn thế nữa.

Trang web này đã được dịch bằng máy để thuận tiện cho bạn. Chúng tôi không thể đảm bảo tính chính xác hoặc độ tin cậy của nội dung được dịch. Nếu bạn có thắc mắc về tính chính xác của nội dung được dịch, vui lòng tham khảo phiên bản tiếng Anh chính thức của trang web.

Đây là một trong số nhiều trang cung cấp hướng dẫn chi tiết về cách tối ưu hóa trò chơi trên PC và máy chơi game console. Bạn có thể tìm thấy toàn bộ bộ sưu tập trong cuốn sách điện tử miễn phí " Tối ưu hóa hiệu năng trò chơi trên máy chơi game và PC" , với hơn 80 mẹo và phương pháp thực hành hữu ích để tối ưu hóa hiệu năng.

Chia nhỏ các khung vẽ của bạn

Vấn đề: Khi một phần tử duy nhất thay đổi trên UI Canvas, toàn bộ Canvas sẽ bị thay đổi.

Canvas là thành phần cơ bản của Unity UI. Nó tạo ra các lưới đại diện cho các phần tử giao diện người dùng được đặt trên đó, tạo lại các lưới khi các phần tử giao diện người dùng thay đổi và gửi các lệnh vẽ đến GPU để giao diện người dùng được hiển thị.

Việc tạo ra các mô hình lưới này có thể tốn kém. Các phần tử giao diện người dùng cần được nhóm lại thành từng lô để có thể vẽ chúng chỉ với càng ít lệnh vẽ càng tốt. Vì việc tạo hàng loạt tốn kém, chúng tôi chỉ muốn tạo lại chúng khi cần thiết. Vấn đề là, khi một hoặc nhiều phần tử thay đổi trên Canvas, toàn bộ Canvas phải được phân tích lại một lần nữa để tìm ra cách tối ưu nhất để vẽ các phần tử của nó.

Nhiều người dùng xây dựng toàn bộ giao diện người dùng của trò chơi trên một Canvas duy nhất với hàng ngàn phần tử. Khi thay đổi một thành phần nào đó, họ có thể gặp phải tình trạng CPU tăng đột biến, gây tốn vài mili giây. Để tìm hiểu thêm về lý do tại sao việc xây dựng lại lại tốn kém đến vậy, hãy xem từ phút 24:55 trong buổi hội thảo Unite này .

Giải pháp: Hãy chia nhỏ các bức tranh của bạn.

Mỗi bức tranh là một hòn đảo biệt lập, tách biệt các yếu tố của nó khỏi các bức tranh khác. Hãy tận dụng khả năng hỗ trợ nhiều Canvas của UGUI bằng cách chia nhỏ các Canvas của bạn để giải quyết các vấn đề xử lý hàng loạt với Unity UI.

Bạn cũng có thể lồng các Canvas vào nhau, điều này cho phép các nhà thiết kế tạo giao diện người dùng phân cấp lớn mà không cần phải suy nghĩ về vị trí của các phần tử khác nhau trên màn hình giữa các Canvas. Các Canvas con cũng tách biệt nội dung khỏi cả Canvas cha và Canvas anh chị em của chúng. Chúng duy trì hình dạng hình học riêng và thực hiện việc phân lô riêng. Một cách để quyết định cách phân chia chúng là dựa trên tần suất cần làm mới. Hãy đặt các phần tử giao diện người dùng tĩnh trên một Canvas riêng biệt, và các phần tử động cập nhật đồng thời trên các Canvas con nhỏ hơn. Ngoài ra, hãy đảm bảo rằng tất cả các phần tử giao diện người dùng trên mỗi Canvas đều có cùng giá trị Z, chất liệu và kết cấu.

Giao diện Raycaster đồ họa

Giới hạn số lượng Graphic Raycaster và vô hiệu hóa Raycast Target.

Vấn đề: Sử dụng không hiệu quả Graphic Raycaster

Graphic Raycaster là thành phần chuyển đổi dữ liệu đầu vào của bạn thành các sự kiện giao diện người dùng. Cụ thể hơn, nó chuyển đổi các lần nhấp chuột hoặc thao tác chạm trên màn hình thành các Sự kiện giao diện người dùng, sau đó gửi chúng đến các Phần tử giao diện người dùng có liên quan. Bạn cần có Graphic Raycaster trên mọi Canvas cần nhập dữ liệu, bao gồm cả các Sub-Canvas. Tuy nhiên, nó cũng lặp qua mọi điểm nhập liệu trên màn hình và kiểm tra xem chúng có nằm trong RectTransform của giao diện người dùng hay không, dẫn đến khả năng phát sinh chi phí không cần thiết.

Mặc dù tên gọi là vậy, Graphic Raycaster thực chất không phải là một raycaster. Theo mặc định, nó chỉ kiểm tra đồ họa giao diện người dùng. Nó lấy tập hợp các phần tử giao diện người dùng (UI Elements) quan tâm đến việc nhận đầu vào trên một Canvas nhất định và thực hiện kiểm tra sự giao nhau. Ví dụ, nó kiểm tra xem điểm mà sự kiện đầu vào xảy ra so với RectTransform của mỗi UI Element trên Canvas của Graphic Raycaster có được đánh dấu là tương tác hay không.

Thách thức nằm ở chỗ không phải tất cả các thành phần giao diện người dùng đều muốn nhận cập nhật.

Giải pháp: Hãy xóa các Graphic Raycaster khỏi các UI Canvas không tương tác và tắt Raycast Target cho các phần tử tĩnh hoặc không tương tác.

Cụ thể, văn bản trên nút tắt Raycast Target sẽ trực tiếp giảm số lượng kiểm tra giao điểm mà Graphic Raycaster phải thực hiện trên mỗi khung hình.

Vấn đề: Đôi khi Graphic Raycaster hoạt động như một raycaster.

Nếu bạn đặt chế độ hiển thị trên Canvas của mình thành Worldspace Camera hoặc Screen Space Camera, bạn có thể thêm mặt nạ chặn. Mặt nạ chặn xác định xem Raycaster sẽ chiếu tia thông qua vật lý 2D hay 3D , để xác định xem có đối tượng vật lý nào đang cản trở khả năng tương tác của người dùng với giao diện người dùng hay không.

Giải pháp: Việc chiếu tia sáng thông qua vật lý 2D hoặc 3D có thể tốn kém, vì vậy hãy sử dụng tính năng này một cách tiết kiệm.

Giảm thiểu số lượng Graphic Raycaster bằng cách loại trừ chúng khỏi các UI Canvas không tương tác, vì trong trường hợp này, không có lý do gì để kiểm tra các sự kiện tương tác.

Tìm hiểu thêm về Graphic Raycaster trong tài liệu này .

Giao diện lưới

Tránh sử dụng các yếu tố giao diện người dùng đắt tiền.

Vấn đề: Danh sách lớn, chế độ xem dạng lưới và nhiều thành phần giao diện người dùng chồng lên nhau rất tốn kém.

Các chế độ xem dạng danh sách và lưới lớn rất tốn tài nguyên, và việc xếp chồng nhiều phần tử giao diện người dùng (ví dụ: các lá bài xếp chồng lên nhau trong trò chơi đấu bài) sẽ gây ra hiện tượng vẽ quá tải.

Giải pháp: Tránh chồng chéo quá nhiều yếu tố giao diện người dùng.

Tùy chỉnh mã của bạn để hợp nhất các phần tử giao diện người dùng nhiều lớp trong thời gian chạy thành ít phần tử và nhóm hơn.

Nếu bạn cần tạo một danh sách hoặc lưới hiển thị lớn, chẳng hạn như màn hình kho hàng với hàng trăm mặt hàng, hãy cân nhắc việc tái sử dụng một nhóm nhỏ các phần tử giao diện người dùng (UI Element) thay vì sử dụng một phần tử UI Element riêng cho mỗi mặt hàng.

Hãy xem dự án GitHub này để tham khảo ví dụ về danh sách cuộn được tối ưu hóa.

Giao diện Nhóm bố cục

Nên tránh sử dụng nhóm bố cục nếu có thể.

Vấn đề: Mỗi phần tử giao diện người dùng (UI Element) cố gắng thay đổi bố cục của nó sẽ thực hiện ít nhất một lệnh gọi GetComponent.

Khi một hoặc nhiều phần tử giao diện người dùng con thay đổi trên hệ thống bố cục, bố cục sẽ trở nên "bẩn". Các phần tử con bị thay đổi sẽ làm mất hiệu lực hệ thống bố cục sở hữu chúng.

Hệ thống bố cục là một tập hợp các nhóm bố cục liền kề nằm ngay phía trên một phần tử bố cục. Một phần tử bố cục không chỉ là thành phần Phần tử bố cục (hình ảnh giao diện người dùng, văn bản và hình chữ nhật cuộn), nó còn bao gồm các phần tử bố cục – giống như các hình chữ nhật cuộn cũng là các nhóm bố cục.

Bây giờ, về vấn đề đang cần giải quyết: Mỗi phần tử giao diện người dùng (UI Element) đánh dấu bố cục của nó là "đã thay đổi" (dirty layout) sẽ thực hiện ít nhất một lệnh gọi GetComponent. Lệnh gọi này tìm kiếm một nhóm bố cục hợp lệ trên phần tử bố cục cha của nó. Nếu tìm thấy một nhóm bố cục phù hợp, nó sẽ tiếp tục duyệt lên theo thứ tự phân cấp Transform cho đến khi ngừng tìm kiếm các nhóm bố cục hoặc đạt đến gốc của thứ tự phân cấp; tùy điều kiện nào xảy ra trước. Do đó, mỗi nhóm bố cục thêm một lệnh GetComponent vào quá trình cập nhật của mỗi phần tử bố cục con, khiến cho các nhóm bố cục lồng nhau hoạt động cực kỳ kém hiệu quả về mặt hiệu năng.

Giải pháp: Nên tránh sử dụng nhóm bố cục nếu có thể.

Sử dụng Anchors để tạo bố cục tỷ lệ thuận. Đối với các giao diện người dùng (UI) có số lượng phần tử UI thay đổi liên tục, hãy cân nhắc tự viết mã để tính toán bố cục. Hãy nhớ chỉ sử dụng chức năng này khi cần thiết, chứ không phải cho mỗi lần thay đổi.

Tìm hiểu thêm về các nhóm bố cục trong tài liệu của chúng tôi.

Giao diện nhóm đối tượng

Cách thông minh để sử dụng các đối tượng UI trong Pool

Vấn đề: Sắp xếp các đối tượng UI theo thứ tự ngược lại.

Mọi người thường gộp các đối tượng giao diện người dùng bằng cách thay đổi đối tượng cha rồi vô hiệu hóa chúng, điều này gây ra sự thay đổi không cần thiết.

Giải pháp: Trước tiên hãy vô hiệu hóa đối tượng, sau đó chuyển nó vào nhóm đối tượng cha.

Bạn sẽ làm thay đổi cấu trúc phân cấp cũ một lần, nhưng một khi bạn thiết lập lại cấu trúc cha cho nó, bạn sẽ tránh được việc làm thay đổi cấu trúc phân cấp cũ lần thứ hai – và bạn sẽ không làm thay đổi cấu trúc phân cấp mới chút nào. Nếu bạn muốn xóa một đối tượng khỏi nhóm, trước tiên hãy thay đổi đối tượng cha của nó, cập nhật dữ liệu, rồi mới kích hoạt lại.

Tìm hiểu thêm về các khái niệm cơ bản về Object Pooling trong Unity .

Thành phần UI Canvas

Cách ẩn một Canvas

Vấn đề: Tôi không chắc làm thế nào để ẩn một Canvas

Đôi khi việc ẩn các phần tử giao diện người dùng và khung vẽ là hữu ích. Nhưng làm thế nào để thực hiện điều này một cách hiệu quả?

Giải pháp: Vô hiệu hóa thành phần Canvas.

Việc vô hiệu hóa thành phần Canvas sẽ ngăn Canvas gửi các lệnh vẽ đến GPU. Như vậy, khung vẽ sẽ không còn hiển thị nữa. Tuy nhiên, Canvas sẽ không loại bỏ bộ đệm đỉnh của nó, mà sẽ giữ lại tất cả các lưới và đỉnh. Sau đó, khi bạn kích hoạt lại nó, nó sẽ không kích hoạt quá trình xây dựng lại – mà chỉ bắt đầu vẽ lại chúng.

Ngoài ra, việc vô hiệu hóa thành phần Canvas không kích hoạt lệnh gọi lại OnDisable/OnEnable tốn kém thông qua hệ thống phân cấp Canvas. Hãy cẩn thận vô hiệu hóa các thành phần con chạy mã tốn nhiều tài nguyên trên mỗi khung hình.

Tìm hiểu thêm về thành phần Canvas tại đây .

Tối ưu hóa việc sử dụng hoạt ảnh trên các phần tử giao diện người dùng.

Vấn đề: Sử dụng hoạt ảnh trên giao diện người dùng của bạn

Các nhà làm phim hoạt hình sẽ làm biến dạng các phần tử giao diện người dùng (UI Elements) trên mỗi khung hình, ngay cả khi giá trị trong hoạt ảnh không thay đổi.

Giải pháp: Sử dụng mã lập trình cho hoạt ảnh giao diện người dùng.

Chỉ nên sử dụng hoạt ảnh cho các phần tử giao diện người dùng động luôn thay đổi. Đối với các phần tử hiếm khi thay đổi hoặc thay đổi tạm thời để phản ứng với các sự kiện, hãy tự viết mã hoặc sử dụng hệ thống tạo hiệu ứng chuyển động mượt mà (tweening system). Có rất nhiều giải pháp tuyệt vời cho vấn đề này trên Asset Store .

Khi sử dụng giao diện toàn màn hình, hãy ẩn tất cả các yếu tố khác.

Vấn đề: Hiệu năng kém khi sử dụng giao diện toàn màn hình.

Nếu trò chơi của bạn hiển thị màn hình tạm dừng hoặc màn hình khởi động che khuất toàn bộ khung cảnh, phần còn lại của trò chơi vẫn đang được xử lý ở chế độ nền, điều này có thể ảnh hưởng đến hiệu năng.

Giải pháp: Hãy giấu hết những thứ khác đi.

Nếu màn hình của bạn che khuất mọi thứ khác trong khung cảnh, hãy tắt tính năng hiển thị khung cảnh 3D của Camera. Tương tự, hãy vô hiệu hóa các phần tử Canvas bị ẩn phía sau Canvas trên cùng.

Hãy cân nhắc giảm giá trị Application.targetFrameRate khi sử dụng giao diện toàn màn hình, vì bạn không cần phải cập nhật ở tốc độ 60 khung hình/giây.

Thêm tài nguyên

Tối ưu hóa hiệu suất trò chơi

Tải ebook miễn phí để biết thêm chi tiết.

Mang đến cho người chơi trải nghiệm chơi game tốt nhất có thể. Với hơn 80 lời khuyên và kinh nghiệm thực tiễn từ các kỹ sư chuyên gia của Unity, bạn có thể tối ưu hóa các trò chơi PC và console của mình.

Được tạo ra bởi các nhóm Success và Unity Studio Productions của Unity, cụ thể hơn, những phương pháp chi tiết này – được đúc kết từ kinh nghiệm thực tế với các studio hàng đầu – sẽ giúp nâng cao hiệu suất tổng thể của trò chơi của bạn.