Cải thiện hiệu suất

*Nội dung này được dịch bằng AI (Beta) và có thể có lỗi. Để xem trang này bằng tiếng Anh, hãy nhấp vào đây.

Trang này mô tả các vấn đề hiệu suất phổ biến và các phương pháp tốt nhất để giảm thiểu chúng.

Tính toán kịch bản

Các hoạt động tốn kém trong mã Luau mất nhiều thời gian để xử lý và do đó có thể ảnh hưởng đến tốc độ khung hình. Trừ khi nó được thực thi song song, mã Luau chạy đồng bộ và chặn luồng chính cho đến khi gặp một hàm trả về luồng.

Vấn đề phổ biến

  • Các hoạt động cường độ cao trên cấu trúc bảng - Các hoạt động phức tạp như tuần tự hóa, giải tuần tự, và sao chép sâu phát sinh chi phí hiệu suất cao, đặc biệt là trên các cấu trúc bảng lớn. Điều này đặc biệt đúng nếu các hoạt động này là đệ quy hoặc liên quan đến việc lặp qua các cấu trúc dữ liệu rất lớn.

  • Sự kiện có tần suất cao - Liên kết các hoạt động tốn kém với các sự kiện dựa trên khung của RunService mà không giới hạn tần suất nghĩa là các hoạt động này sẽ được lặp lại mỗi khung hình, điều này thường dẫn đến sự gia tăng không cần thiết về thời gian tính toán. Các sự kiện này bao gồm:

Giảm thiểu

  • Thực thi mã trên các sự kiện của RunService một cách tiết kiệm, giới hạn việc sử dụng vào các trường hợp mà việc gọi tần suất cao là cần thiết (ví dụ: cập nhật camera). Bạn có thể thực thi hầu hết các mã khác trong các sự kiện khác hoặc ít thường xuyên hơn trong một vòng lặp.
  • Chia nhỏ các tác vụ lớn hoặc tốn kém bằng cách sử dụng task.wait() để phân tán công việc qua nhiều khung hình.
  • Xác định và tối ưu hóa các hoạt động không cần thiết tốn kém và sử dụng đa luồng cho các tác vụ tính toán tốn kém mà không cần truy cập vào mô hình dữ liệu.
  • Một số kịch bản phía máy chủ có thể hưởng lợi từ native code generation, một cờ đơn giản biên dịch mã thành mã máy thay vì bytecode.

Phạm vi MicroProfiler

Phạm viTính toán liên quan
RunService.PreRenderMã thực thi trên sự kiện PreRender
RunService.PreSimulationMã thực thi trên sự kiện Stepped
RunService.PostSimulationMã thực thi trên sự kiện Heartbeat
RunService.HeartbeatMã thực thi trên sự kiện Heartbeat

Để biết thêm thông tin về việc gỡ lỗi kịch bản sử dụng MicroProfiler, xem thư viện debug, bao gồm các hàm để gán thẻ cho mã cụ thể và tăng cường độ cụ thể, như debug.profilebegindebug.profileend. Nhiều phương pháp API Roblox được gọi bởi các kịch bản cũng có các thẻ MicroProfiler liên quan có thể cung cấp tín hiệu hữu ích.

Sử dụng bộ nhớ kịch bản

Rò rỉ bộ nhớ có thể xảy ra khi bạn viết các kịch bản tiêu thụ bộ nhớ mà bộ thu gom rác không thể giải phóng đúng cách khi không còn sử dụng. Rò rỉ đặc biệt phổ biến trên máy chủ, vì chúng có thể trực tuyến liên tục trong nhiều ngày, trong khi phiên client thì ngắn hơn nhiều.

Các giá trị bộ nhớ sau đây trong Developer Console có thể chỉ ra một vấn đề cần điều tra thêm:

  • LuaHeap - Mức tiêu thụ cao hoặc tăng trưởng cho thấy một rò rỉ bộ nhớ.
  • InstanceCount - Số lượng các thể hiện tăng liên tục cho thấy các tham chiếu đến một số thể hiện trong mã của bạn không được thu gom rác.
  • PlaceScriptMemory - Cung cấp phân tích bộ nhớ theo kịch bản.

Vấn đề phổ biến

  • Để lại kết nối còn hoạt động - Bộ máy không bao giờ thu gom rác các sự kiện đã kết nối với một thể hiện và bất kỳ giá trị nào được tham chiếu bên trong callback đã kết nối. Do đó, các kết nối hoạt động của sự kiện và mã bên trong các thể hiện đã kết nối, các hàm đã kết nối, và các giá trị được tham chiếu vẫn ngoài phạm vi của bộ thu gom rác, ngay cả sau khi các sự kiện đã được phát.

    Mặc dù các sự kiện bị ngắt kết nối khi thể hiện mà chúng thuộc về bị hủy diệt, một sai lầm phổ biến là giả định rằng điều này áp dụng cho các đối tượng Player. Sau khi một người dùng rời khỏi một trò chơi, bộ máy không tự động hủy diệt đối tượng Player đại diện của họ và mô hình nhân vật, vì vậy các kết nối đến đối tượng Player và các thể hiện dưới mô hình nhân vật, chẳng hạn như CharacterAdded, vẫn tiêu tốn bộ nhớ nếu bạn không ngắt kết nối chúng trong các kịch bản của mình. Điều này có thể dẫn đến rò rỉ bộ nhớ rất đáng kể theo thời gian trên máy chủ khi hàng trăm người dùng tham gia và rời khỏi trò chơi.

  • Bảng - Chèn các đối tượng vào bảng nhưng không xóa chúng khi không còn cần thiết sẽ gây tiêu thụ bộ nhớ không cần thiết, đặc biệt cho các bảng theo dõi dữ liệu người dùng khi họ tham gia. Ví dụ, đoạn mã sau tạo một bảng thêm thông tin người dùng mỗi khi một người tham gia:

    Ví dụ

    local playerInfo = {}
    Players.PlayerAdded:Connect(function(player)
    playerInfo[player] = {} -- một số thông tin
    end)

    Nếu bạn không xóa các mục này khi chúng không còn cần thiết, bảng sẽ tiếp tục tăng kích thước và tiêu thụ nhiều bộ nhớ khi nhiều người tham gia vào phiên. Mọi mã lặp qua bảng này cũng trở nên tốn kém về tính toán hơn khi bảng lớn lên.

Giảm thiểu

Để dọn dẹp tất cả các giá trị đã sử dụng nhằm ngăn chặn rò rỉ bộ nhớ:

  • Ngắt tất cả các kết nối - Đi qua mã nguồn của bạn và đảm bảo mỗi kết nối được dọn dẹp thông qua một trong những cách sau đây:

    • Ngắt kết nối thủ công bằng cách sử dụng hàm Disconnect().
    • Hủy diệt thể hiện mà sự kiện thuộc về bằng hàm Destroy().
    • Hủy diệt đối tượng kịch bản mà kết nối quay ngược lại.
  • Xóa các đối tượng và nhân vật người chơi sau khi rời đi - Bật Workspace.PlayerCharacterDestroyBehavior để tự động hủy diệt các đối tượng người chơi và mô hình nhân vật sau khi một người dùng rời đi. Nếu bạn thích, bạn có thể thay vào đó dọn dẹp chúng một cách thủ công:

    Ví dụ dọn dẹp người chơi và nhân vật

    local Players = game:GetService("Players")
    Players.PlayerAdded:Connect(function(player)
    player.CharacterRemoving:Connect(function(character)
    task.defer(character.Destroy, character)
    end)
    end)
    Players.PlayerRemoving:Connect(function(player)
    task.defer(player.Destroy, player)
    end)

Tính toán vật lý

Mô phỏng vật lý quá mức có thể là nguyên nhân chính gây ra thời gian tính toán tăng lên cho mỗi khung hình trên cả máy chủ và client.

Vấn đề phổ biến

  • Tần suất bước vật lý quá mức - Mặc định, hành vi bước đi trong chế độ thích ứng, nơi vật lý bước ở 60 Hz, 120 Hz, hoặc 240 Hz, tùy thuộc vào độ phức tạp của cơ chế vật lý.

    Một chế độ cố định với độ chính xác của vật lý được cải thiện cũng có sẵn, điều này buộc tất cả các cụm vật lý bước ở 240 Hz (bốn lần mỗi khung hình). Điều này dẫn đến nhiều tính toán hơn rất nhiều cho mỗi khung hình.

  • Số lượng đối tượng mô phỏng phức tạp quá mức - Càng nhiều cụm 3D được mô phỏng, thời gian tính toán vật lý càng lâu cho mỗi khung hình. Thường thì, các trò chơi sẽ có các đối tượng được mô phỏng mà không cần thiết phải mô phỏng hoặc sẽ có các cơ chế có nhiều ràng buộc và khớp hơn mức cần thiết.

  • Kiểm tra va chạm quá chính xác - Các phần mesh có một thuộc tính CollisionFidelity để phát hiện va chạm cung cấp nhiều chế độ khác nhau với các mức ảnh hưởng hiệu suất khác nhau. Chế độ phát hiện va chạm chính xác cho các phần mesh có chi phí hiệu suất tốn kém nhất và mất nhiều thời gian hơn cho bộ máy để tính toán.

Giảm thiểu

  • Cố định các phần không cần mô phỏng - Cố định tất cả các phần không cần được điều khiển bởi vật lý, chẳng hạn như cho NPC tĩnh.

  • Sử dụng bước vật lý thích ứng - Bước thích ứng tự động điều chỉnh tỷ lệ tính toán vật lý cho các cơ chế vật lý, cho phép cập nhật vật lý diễn ra ít thường xuyên hơn trong một số trường hợp.

  • Giảm độ phức tạp của cơ chế

    • Ở đâu có thể, giảm số lượng ràng buộc vật lý hoặc khớp trong một cụm.
    • Giảm lượng tự va chạm bên trong một cơ chế, chẳng hạn như bằng cách áp dụng giới hạn hoặc không va chạm vào các chi của ragdoll để ngăn chúng va chạm với nhau.
  • Giảm sử dụng độ chính xác va chạm cho các mesh

    • Đối với các đối tượng nhỏ hoặc không tương tác mà người dùng hiếm khi nhận thấy sự khác biệt, hãy sử dụng độ chính xác hộp.

    • Đối với các đối tượng kích thước nhỏ đến trung bình, hãy sử dụng độ chính xác hộp hoặc vỏ, tùy thuộc vào hình dạng.

    • Đối với các đối tượng lớn và rất phức tạp, hãy xây dựng va chạm tùy chỉnh bằng cách sử dụng các phần vô hình khi có thể.

    • Đối với các đối tượng không cần va chạm, hãy tắt va chạm và sử dụng độ chính xác hộp hoặc vỏ, vì hình học va chạm vẫn được lưu trữ trong bộ nhớ.

    • Bạn có thể hiển thị hình học va chạm để kiểm tra trong Studio bằng cách bật Độ chính xác va chạm từ widget Tùy chọn Hiển thị ở góc trên bên phải của cửa sổ 3D.

      Ngoài ra, bạn có thể áp dụng bộ lọc CollisionFidelity=PreciseConvexDecomposition vào Explorer cho phép bạn thấy tổng số tất cả các phần mesh với độ chính xác chính xác và cho phép bạn dễ dàng chọn chúng.

    • Để có một hướng dẫn chi tiết về cách chọn tùy chọn độ chính xác va chạm cân bằng giữa yêu cầu về độ chính xác và hiệu suất của bạn, xem Đặt tham số vật lý và kết xuất.

Phạm vi MicroProfiler

Phạm viTính toán liên quan
physicsSteppedTổng thể tính toán vật lý
worldStepCác bước vật lý rời rạc được thực hiện mỗi khung hình

Sử dụng bộ nhớ vật lý

Chuyển động vật lý và phát hiện va chạm tiêu thụ bộ nhớ. Các phần mesh có thuộc tính CollisionFidelity xác định phương pháp được sử dụng để đánh giá ranh giới va chạm của mesh.

Vấn đề phổ biến

Các chế độ phát hiện va chạm mặc định và chính xác tiêu thụ bộ nhớ cao hơn đáng kể so với hai chế độ khác có hình dạng va chạm độ chính xác thấp hơn.

Nếu bạn thấy mức tiêu thụ bộ nhớ cao dưới PhysicsParts, bạn có thể cần khám phá việc giảm độ chính xác va chạm của các đối tượng trong trò chơi của bạn.

Cách giảm thiểu

Để giảm bộ nhớ sử dụng cho độ chính xác va chạm:

  • Đối với các phần không cần va chạm, hãy tắt va chạm của chúng bằng cách đặt BasePart.CanCollide, BasePart.CanTouchBasePart.CanQuery thành false.
  • Giảm độ chính xác của các va chạm bằng cách sử dụng cài đặt CollisionFidelity. Box có yêu cầu về bộ nhớ thấp nhất, và DefaultPrecise thường tốn kém hơn.
    • Thường thì an toàn khi đặt độ chính xác va chạm của bất kỳ phần cố định nhỏ nào thành Box.
    • Đối với các mesh lớn phức tạp, bạn có thể muốn tự xây dựng mesh va chạm của mình từ các đối tượng nhỏ hơn với độ chính xác va chạm hộp.

Nhân vật

Humanoid là một lớp cung cấp nhiều chức năng cho người chơi và các nhân vật không phải người chơi (NPC). Mặc dù mạnh mẽ, Humanoid đi kèm với một chi phí tính toán đáng kể.

Vấn đề phổ biến

  • Để tất cả HumanoidStateTypes được kích hoạt trên các NPC - Có một chi phí hiệu suất khi duy trì một số HumanoidStateTypes được kích hoạt. Vô hiệu hóa bất kỳ loại nào không cần thiết cho các NPC của bạn. Ví dụ, trừ khi NPC của bạn sẽ leo thang, việc vô hiệu hóa trạng thái Climbing là an toàn.

  • Khởi tạo, sửa đổi và tái sinh mô hình với Humanoids hoặc MeshParts đã được nén thường xuyên

    • Điều này có thể gây áp lực cho bộ máy để xử lý, đặc biệt nếu các mô hình này sử dụng vật liệu nhiều lớp. Điều này cũng có thể đặc biệt vấn đề trong các trò chơi mà nhân vật tái sinh thường xuyên.
    • Trong MicroProfiler, các thẻ dài updateInvalidatedFastClusters (trên 4 ms) thường là một tín hiệu rằng việc khởi tạo/sửa đổi nhân vật đang kích hoạt quá nhiều các xác định không hợp lệ.
  • Sử dụng Humanoids trong các trường hợp không cần thiết - Các NPC tĩnh không di chuyển thường không cần lớp Humanoid.

  • Phát các hoạt ảnh trên một số lượng lớn NPC từ máy chủ - Các hoạt ảnh NPC chạy trên máy chủ cần được mô phỏng trên máy chủ và sao chép lại cho client. Điều này có thể gây ra quá tải không cần thiết.

  • Thực hiện những thay đổi về kích thước và tỷ lệ không cần thiết - Những thay đổi này sẽ khiến FastCluster được tái xây dựng. Hãy cố gắng giảm điều này trong quá trình chơi nếu bạn thấy các vấn đề hiệu suất liên quan đến FastCluster. Tương tự, các thay đổi thuộc tính khác cũng có thể khiến FastCluster được tái xây dựng, vì vậy nói chung hãy giảm thiểu các thay đổi này càng nhiều càng tốt.

Giảm thiểu

  • Phát các hoạt ảnh NPC trên client - Trong các trò chơi với số lượng lớn NPC, hãy xem xét việc tạo Animator trên client và chạy các hoạt ảnh tại chỗ. Điều này giảm tải cho máy chủ và giảm yêu cầu sao chép không cần thiết. Nó cũng giúp có thêm tối ưu hóa có thể (như chỉ phát các hoạt ảnh cho các NPC gần nhân vật).

  • Sử dụng các lựa chọn thân thiện với hiệu suất thay cho Humanoids - Các mô hình NPC không cần phải chứa một đối tượng humanoid.

    • Đối với các NPC tĩnh, hãy sử dụng một AnimationController đơn giản, vì chúng không cần phải di chuyển xung quanh nhưng chỉ cần phát hoạt ảnh.
    • Đối với các NPC di chuyển, hãy xem xét việc triển khai bộ điều khiển chuyển động của riêng bạn và sử dụng một AnimationController cho các hoạt ảnh, tùy thuộc vào độ phức tạp của các NPC của bạn.
  • Vô hiệu hóa các trạng thái humanoid không sử dụng - Sử dụng Humanoid:SetStateEnabled() chỉ kích hoạt các trạng thái cần thiết cho mỗi humanoid.

  • Tạo nhóm các mô hình NPC có tái sinh thường xuyên - Thay vì hủy diệt hoàn toàn một NPC, hãy gửi NPC vào một nhóm các NPC không hoạt động. Bằng cách này, khi cần tái sinh một NPC mới, bạn chỉ cần kích hoạt lại một trong những NPC từ nhóm. Quy trình này được gọi là pooling, giúp giảm số lần cần tái khởi tạo các nhân vật.

  • Chỉ tạo NPC khi người dùng ở gần - Đừng tạo NPC khi người dùng không ở trong phạm vi và cắt giảm khi người dùng rời khỏi phạm vi của họ.

  • Tránh thay đổi cấu trúc nhân vật sau khi nó được tạo - Một số thay đổi đối với cấu trúc của một nhân vật có ảnh hưởng đáng kể đến hiệu suất. Một số tối ưu hóa có sẵn:

    • Đối với các hoạt ảnh quy trình tùy chỉnh, đừng cập nhật các thuộc tính JointInstance.C0JointInstance.C1. Thay vào đó, cập nhật thuộc tính Motor6D.Transform.
    • Nếu bạn cần đính kèm bất kỳ đối tượng BasePart nào vào nhân vật, hãy làm điều này bên ngoài cấu trúc của mô hình nhân vật Model.

Phạm vi MicroProfiler

Phạm viTính toán liên quan
stepHumanoidĐiều khiển và vật lý humanoid
stepAnimationHoạt ảnh humanoid và animator
updateInvalidatedFastClustersLiên quan đến việc tạo hoặc sửa đổi một nhân vật

Kết xuất

Một phần đáng kể thời gian mà client dành cho mỗi khung hình là để kết xuất cảnh trong khung hình hiện tại. Máy chủ không thực hiện bất kỳ kết xuất nào, vì vậy phần này chỉ dành cho client.

Các cuộc gọi vẽ

Một cuộc gọi vẽ là một tập hợp các hướng dẫn từ bộ máy đến GPU để kết xuất một cái gì đó. Các cuộc gọi vẽ có chi phí cao. Nhìn chung, càng ít cuộc gọi vẽ mỗi khung hình, thời gian tính toán cần thiết để kết xuất một khung hình càng ít.

Bạn có thể thấy bao nhiêu cuộc gọi vẽ đang xảy ra hiện tại với mục Render StatsTiming trong Studio. Bạn có thể xem Render Stats trong client bằng cách nhấn ShiftF2.

Càng nhiều đối tượng cần được vẽ trong cảnh của bạn trong một khung hình nhất định, thì càng nhiều cuộc gọi vẽ được thực hiện đến GPU. Tuy nhiên, Bộ máy Roblox sử dụng một quy trình gọi là instancing để hợp nhất các mesh giống hệt nhau với các đặc điểm văn bản giống hệt vào một cuộc gọi vẽ duy nhất. Cụ thể, nhiều mesh có cùng MeshContent được xử lý trong một cuộc gọi vẽ khi:

Các vấn đề phổ biến khác

  • Mật độ đối tượng quá mức - Nếu một số lượng lớn các đối tượng tập trung với mật độ cao, thì việc kết xuất khu vực này của cảnh yêu cầu nhiều cuộc gọi vẽ hơn. Nếu bạn thấy tốc độ khung hình của mình giảm khi nhìn vào một phần nhất định của bản đồ, đây có thể là một dấu hiệu tốt cho thấy mật độ đối tượng ở khu vực này quá cao.

    Các đối tượng như hình nền, văn bản và hạt không được nhóm tốt và giới thiệu thêm các cuộc gọi vẽ. Hãy chú ý đặc biệt đến các loại đối tượng này trong một cảnh. Đặc biệt, sự thay đổi thuộc tính đến ParticleEmitters có thể có một ảnh hưởng mạnh mẽ đến hiệu suất.

  • Bỏ lỡ các cơ hội grouping - Thường thì, một cảnh sẽ bao gồm cùng một mesh được nhân đôi nhiều lần, nhưng mỗi bản sao của mesh có ID tài sản mesh hoặc văn bản khác nhau. Điều này ngăn cản việc grouping và có thể dẫn đến các cuộc gọi vẽ không cần thiết.

    Một nguyên nhân phổ biến của vấn đề này là khi toàn bộ cảnh được nhập cùng một lúc, thay vì từng tài sản một được nhập vào Roblox và sau đó được nhân đôi sau khi nhập để lắp ráp cảnh.

    Ngay cả một kịch bản đơn giản như kịch bản này cũng có thể giúp bạn xác định các phần mesh có cùng tên sử dụng các ID khác nhau:


    for _,descendant in workspace:GetDescendants() do
    if descendant:IsA("MeshPart") then
    print(descendant.Name .. ", " .. descendant.MeshId)
    end
    end

    Đầu ra (với Stack Lines được bật) có thể trông giống như thế này. Các dòng lặp lại cho thấy việc tái sử dụng cùng một mesh, điều này là tốt. Các dòng độc nhất không nhất thiết xấu, nhưng tùy thuộc vào sơ đồ đặt tên của bạn, có thể cho thấy các mesh trùng lặp trong trò chơi của bạn:


    LargeRock, rbxassetid://106420009602747 (x144) -- tốt
    LargeRock, rbxassetid://120109824668127
    LargeRock, rbxassetid://134460273008628
    LargeRock, rbxassetid://139288987285823
    LargeRock, rbxassetid://71302144984955
    LargeRock, rbxassetid://90621205713698
    LargeRock, rbxassetid://113160939160788
    LargeRock, rbxassetid://135944592365226 -- tất cả có thể là trùng lặp
  • Độ phức tạp của đối tượng quá mức - Mặc dù không quan trọng bằng số lượng cuộc gọi vẽ, số lượng tam giác trong một cảnh có ảnh hưởng đến thời gian một khung hình mất để kết xuất. Các cảnh có số lượng lớn rất nhiều mesh phức tạp là một vấn đề phổ biến, cũng như các cảnh có thuộc tính MeshPart.RenderFidelity được đặt thành Precise trên quá nhiều mesh.

  • Bóng đổ quá mức - Quản lý bóng là một quy trình tốn kém, và các bản đồ chứa một số lượng và mật độ cao của các đối tượng ánh sáng tạo bóng (hoặc một số lượng và mật độ cao của các phần nhỏ bị ảnh hưởng bởi bóng) có thể gặp vấn đề về hiệu suất.

  • Overdraw độ trong suốt cao - Đặt các đối tượng với độ trong suốt một phần gần nhau buộc bộ máy phải kết xuất các pixel chồng chéo nhiều lần, điều này có thể ảnh hưởng đến hiệu suất. Để biết thêm thông tin về việc xác định và khắc phục vấn đề này, xem Xóa các độ trong suốt nhiều lớp.

  • Di chuyển MeshPart đã được nén không cần thiết - Các MeshParts đã được nén là một phần của một mô hình không có một Humanoid được nhóm lại bằng các FastClusters tổ chức không gian. Khi những MeshParts này di chuyển, chúng phải liên tục được thêm vào và xóa khỏi các cụm không gian, buộc phải xây dựng lại các cụm và ảnh hưởng đến hiệu suất.

    • Một biện pháp rất hiệu quả là nhúng một Humanoid vào trong Mô hình. Sự hiện diện của một Humanoid vượt qua hành vi nhóm không gian mặc định, yêu cầu sử dụng một FastCluster duy nhất và thống nhất cho toàn bộ Mô hình. Do đó, việc cập nhật vị trí không còn yêu cầu tái xây dựng cụm, do đó giảm thiểu nút thắt cổ chai hiệu suất. Kỹ thuật này nên chỉ được dành riêng cho các MeshParts có dự đoán chuyển động, vì nó có thể gây ra chi phí bộ nhớ và làm giảm lợi ích của tối ưu hóa không gian. Chúng tôi khuyến nghị bạn luôn kiểm tra hiệu suất trò chơi của mình sau khi thực hiện các thay đổi loại này. Xem thêm thông tin tại mẹo hiệu suất humanoid.
  • Quá nhiều phần trong một Model - Quá nhiều phần trong một Mô hình có thể gây ra các bản tái xây dựng thường xuyên hơn do khả năng thuộc tính của một phần thay đổi dẫn đến việc yêu cầu một bản tái xây dựng hoàn chỉnh. Tìm sự cân bằng phù hợp giữa các phần trong một Mô hình khi nó sử dụng FastCluster.

Giảm thiểu

  • Grouping các mesh giống hệt nhau và giảm số lượng mesh độc nhất - Nếu bạn đảm bảo tất cả các mesh giống hệt nhau có các ID tài sản cơ bản giống nhau, bộ máy có thể nhận ra và kết xuất chúng trong một cuộc gọi vẽ duy nhất. Đảm bảo chỉ tải lên mỗi mesh trong bản đồ một lần và sau đó nhân đôi chúng trong Studio để tái sử dụng thay vì nhập các bản đồ lớn như một khối, điều này có thể khiến các mesh giống hệt có các ID nội dung riêng biệt và được bộ máy nhận ra như là các tài sản độc nhất. Gói hàng là một cơ chế hữu ích cho việc tái sử dụng đối tượng.

  • Culling - Culling mô tả quy trình loại bỏ các cuộc gọi vẽ cho các đối tượng không cần thiết trong khung kết xuất cuối cùng. Theo mặc định, bộ máy bỏ qua các cuộc gọi vẽ cho các đối tượng ngoài phạm vi nhìn của camera (frustum culling) và các phần, mesh, và địa hình bị che khuất khỏi tầm nhìn bởi các đối tượng khác (occlusion culling). Trong một số kịch bản, chẳng hạn như môi trường trong nhà, bạn có thể thực hiện một hệ thống phòng hoặc cổng và thủ công culling các đối tượng để giảm thêm cuộc gọi vẽ hoặc tổng tải tính toán.

  • Giảm cấp độ chi tiết cho các mô hình - Bật streaming thể hiện và đặt thuộc tính LevelOfDetail của các mô hình thế giới của bạn thành SLIM để kết xuất các mesh SLIM nhẹ được tối ưu hóa khi khoảng cách từ camera tăng lên.

  • Giảm cấp độ chi tiết cho các nhân vật - Bật streaming thể hiện và đặt thuộc tính Workspace.EnableSLIMAvatars để kết xuất các mô hình nhân vật nền tảng với bất kỳ số lượng phụ kiện hoặc tầng quần áo nào như các đại diện nhân vật nhẹ được tối ưu hóa với hỗ trợ đầy đủ cho các hoạt ảnh khi khoảng cách từ camera tăng lên.

  • Giảm độ chính xác kết xuất - Đặt MeshPart.RenderFidelity thành Automatic hoặc Performance. Điều này cho phép các mesh giảm xuống các lựa chọn ít phức tạp hơn, điều này có thể làm giảm số lượng đa giác cần được vẽ.

  • Tắt việc tạo bóng trên các phần và đối tượng ánh sáng phù hợp - Bộ máy Roblox tự động giảm chất lượng bóng khi mức chất lượng đồ họa client giảm, cuối cùng tắt bóng hoàn toàn ở các mức chất lượng dưới 4. Tuy nhiên, bạn có thể tùy chọn tắt các thuộc tính tạo bóng trên các đối tượng ánh sáng và phần để cải thiện hiệu suất khi bóng được bật và tăng khả năng rằng bóng vẫn được bật. Một số ví dụ về các tối ưu hóa bạn có thể thực hiện cả ở thời điểm sửa đổi hoặc động trong thời gian chạy:

    • Sử dụng thuộc tính BasePart.CastShadow để tắt việc tạo bóng trên các phần nhỏ mà bóng khó có thể nhìn thấy. Chiến lược này đặc biệt hiệu quả khi áp dụng cho các phần ở xa khỏi camera của người dùng.

    • Tắt bóng trên các đối tượng di chuyển khi có thể.

    • Tắt Light.Shadows trên các đối tượng ánh sáng nơi mà đối tượng không cần phải tạo bóng.

    • Giới hạn phạm vi và góc của các đối tượng ánh sáng.

    • Sử dụng ít đối tượng ánh sáng hơn.

    • Cân nhắc tắt ánh sáng nằm ngoài một phạm vi cụ thể hoặc theo từng phòng cho các môi trường trong nhà.

Phạm vi MicroProfiler

Phạm viTính toán liên quan
Prepare and PerformKết xuất tổng thể
Perform/Scene/computeLightingPerformCập nhật lưới ánh sáng và bóng
LightGridCPUCập nhật lưới ánh sáng voxel
ShadowMapSystemÁnh xạ bóng
Perform/Scene/UpdateViewChuẩn bị cho việc kết xuất và cập nhật hạt
Perform/Scene/RenderViewKết xuất và hậu xử lý

Mạng và sao chép

Mạng và sao chép mô tả quy trình mà dữ liệu được gửi giữa máy chủ và các client đã kết nối. Thông tin được gửi giữa client và máy chủ mỗi khung hình, nhưng khối lượng lớn thông tin yêu cầu nhiều thời gian tính toán hơn.

Vấn đề phổ biến

  • Lưu lượng từ xa quá mức - Gửi một lượng lớn dữ liệu thông qua các đối tượng RemoteEvent hoặc RemoteFunction hoặc gọi chúng rất thường xuyên có thể dẫn đến một lượng lớn thời gian CPU được chi tiêu để xử lý các gói dữ liệu đến mỗi khung hình. Những sai lầm phổ biến bao gồm:

    • Sao chép dữ liệu mỗi khung hình mà không cần phải sao chép.
    • Sao chép dữ liệu theo input của người dùng mà không có cơ chế để hạn chế.
    • Phát tán nhiều dữ liệu hơn mức cần thiết. Ví dụ, gửi toàn bộ hàng tồn kho của người chơi khi họ mua một vật phẩm thay vì chỉ thông tin chi tiết của vật phẩm đã mua.
  • Tạo hoặc xóa cây thể hiện phức tạp - Khi có một thay đổi đối với mô hình dữ liệu trên máy chủ, nó được sao chép cho các client đã kết nối. Điều này có nghĩa là việc tạo và phá hủy các phân cấp thể hiện lớn như các bản đồ tại thời gian chạy có thể rất tốn kém về mạng.

    Một thủ phạm phổ biến ở đây là dữ liệu hoạt ảnh phức tạp được lưu bởi các plugin Animation Editor trong các rig. Nếu điều này không được xóa trước khi trò chơi được xuất bản và mô hình đã hoạt ảnh được nhân đôi thường xuyên, một lượng lớn dữ liệu sẽ bị sao chép không cần thiết.

  • TweenService phía máy chủ - Nếu TweenService được sử dụng để tween một đối tượng phía máy chủ, thuộc tính đã tween sẽ được sao chép tới từng client mỗi khung hình. Điều này không chỉ dẫn đến sự chao đảo của tween khi độ trễ của client dao động, mà còn gây ra nhiều lưu lượng mạng không cần thiết.

Giảm thiểu

Bạn có thể sử dụng các chiến thuật sau đây để giảm sao chép không cần thiết:

  • Tránh gửi một lượng lớn dữ liệu cùng một lúc thông qua các sự kiện từ xa. Thay vào đó, chỉ gửi những dữ liệu cần thiết ở tần suất thấp hơn. Ví dụ, đối với trạng thái của một nhân vật, hãy sao chép nó khi có sự thay đổi thay vì mỗi khung hình.
  • Chia nhỏ các cây thể hiện phức tạp như các bản đồ và tải chúng từng phần để phân tán công việc sao chép này qua nhiều khung hình.
  • Dọn dẹp metadata hoạt ảnh, đặc biệt là thư mục hoạt ảnh của các rig, sau khi đã nhập.
  • Giới hạn sự sao chép thể hiện không cần thiết, đặc biệt là trong trường hợp máy chủ không cần phải biết về các thể hiện đang được tạo ra. Điều này bao gồm:
    • Hiệu ứng hình ảnh như một vụ nổ hoặc một vụ nổ ma thuật. Máy chủ chỉ cần biết vị trí để xác định kết quả, trong khi các client có thể tạo hiệu ứng hình ảnh tại địa phương.
    • Các mô hình của предмет đầu tiên.
    • Tween các đối tượng trên client thay vì máy chủ.

Phạm vi MicroProfiler

Phạm viTính toán liên quan
ProcessPacketsXử lý các gói mạng đến, chẳng hạn như việc gọi các sự kiện và thay đổi thuộc tính
Allocate Bandwidth and Run SendersCác sự kiện đầu ra quan trọng trên máy chủ

Sử dụng bộ nhớ tài sản

Cơ chế có ảnh hưởng lớn nhất mà người sáng tạo có để cải thiện việc sử dụng bộ nhớ của client là bật streaming thể hiện.

Streaming thể hiện

Streaming thể hiện chọn lọc tải ra các phần của mô hình dữ liệu không cần thiết, điều này có thể dẫn đến thời gian tải giảm đáng kể và tăng khả năng của client để ngăn ngừa các sự cố khi nó phải chịu áp lực bộ nhớ.

Nếu bạn gặp phải các vấn đề về bộ nhớ và đã tắt streaming thể hiện, hãy xem xét nâng cấp trò chơi của bạn để hỗ trợ nó, đặc biệt nếu thế giới 3D của bạn lớn. Streaming thể hiện dựa trên khoảng cách trong không gian 3D, vì vậy các thế giới lớn hơn tự nhiên được hưởng lợi nhiều hơn từ nó.

Nếu streaming thể hiện đã được bật, bạn có thể tăng cường sự quyết liệt của nó. Ví dụ, hãy xem xét:

  • Giảm sử dụng Enum.ModelStreamingMode.Persistent khi có thể. Bạn có thể cần cập nhật các kịch bản của mình nếu bạn đang sử dụng nó như một biện pháp tương thích.
  • Giảm Workspace.StreamingMinRadiusWorkspace.StreamingTargetRadius.

Để biết thêm thông tin về các tùy chọn streaming và lợi ích của chúng, xem tính chất streaming.

Các vấn đề phổ biến khác

  • Nhân bản tài sản - Một sai lầm phổ biến là tải lên cùng một tài sản nhiều lần dẫn đến các ID tài sản khác nhau. Điều này có thể dẫn đến cùng một nội dung được tải vào bộ nhớ nhiều lần.

  • Khối lượng tài sản quá mức - Ngay cả khi các tài sản không giống hệt nhau, có những trường hợp khi cơ hội tái sử dụng cùng một tài sản và tiết kiệm bộ nhớ bị bỏ lỡ.

  • Tệp âm thanh - Tệp âm thanh có thể là một yếu tố bất ngờ góp phần vào việc sử dụng bộ nhớ, đặc biệt nếu bạn tải tất cả vào client cùng một lúc thay vì chỉ tải những gì bạn cần cho một phần của trò chơi. Để biết thêm chiến lược, xem Thời gian tải.

  • Văn bản có độ phân giải cao - Mức tiêu thụ bộ nhớ đồ họa cho một văn bản không liên quan đến kích thước của văn bản trên đĩa; số lượng pixel trong văn bản xác định mức sử dụng bộ nhớ. Ví dụ, một văn bản 1024x1024 pixel tiêu thụ gấp bốn lần dung lượng bộ nhớ đồ họa so với một văn bản 512x512 pixel.

    Các hình ảnh được tải lên Roblox được chuyển mã sang định dạng cố định, vì vậy không có lợi ích bộ nhớ khi tải lên hình ảnh trong mô hình màu liên quan đến ít byte hơn mỗi pixel. Tương tự, nén các hình ảnh trước khi tải lên hoặc loại bỏ kênh alpha khỏi hình ảnh mà không cần có thể làm giảm kích thước hình ảnh trên đĩa, nhưng không cải thiện mức sử dụng bộ nhớ.

    Khi một trò chơi tải lên, bộ máy tự động bắt đầu với các văn bản chất lượng thấp hơn và sau đó tăng dần chất lượng dựa trên bộ nhớ thiết bị có sẵn, khoảng cách từ camera, số lượng không gian màn hình mà văn bản chiếm đóng và các yếu tố khác. Dù vậy, việc bố trí chiến lược kích thước các văn bản của bạn có thể cải thiện mức sử dụng bộ nhớ trong trò chơi của bạn.

Giảm thiểu

  • Chỉ tải lên tài sản một lần - Tái sử dụng cùng một ID tài sản cho nhiều đối tượng và đảm bảo các tài sản giống nhau, đặc biệt là các mesh và hình ảnh, không được tải lên riêng biệt nhiều lần.

  • Tìm và sửa các tài sản trùng lặp - Tìm kiếm các phần mesh giống hệt nhau và văn bản đã được tải lên nhiều lần với các ID khác nhau.

    • Mặc dù không có API nào để tự động phát hiện sự tương đồng của các tài sản, bạn có thể thu thập tất cả các ID tài sản hình ảnh trong địa điểm của bạn (có thể là thủ công hoặc bằng một kịch bản), tải xuống và so sánh chúng bằng các công cụ so sánh bên ngoài.

    • Đối với các phần mesh, chiến lược tốt nhất là lấy các ID mesh độc nhất và tổ chức chúng theo kích thước để xác định thủ công các bản sao.

    • Thay vì sử dụng các tài liệu khác nhau cho các màu khác nhau, tải lên một tài liệu duy nhất và sử dụng thuộc tính SurfaceAppearance.Color để áp dụng nhiều màu khác nhau cho nó.

  • Nhập các tài sản trong bản đồ riêng biệt - Thay vì nhập toàn bộ bản đồ cùng một lúc, hãy nhập và dựng lại các tài sản trong bản đồ riêng biệt. Trình Nhập không thực hiện bất kỳ việc loại bỏ nhân bản nào cho các mesh, vì vậy nếu bạn nhập một bản đồ lớn với nhiều gạch nền khác nhau, mỗi gạch sẽ được nhập như một tài sản riêng biệt (ngay cả khi chúng là trùng lặp). Điều này có thể dẫn đến các vấn đề về hiệu suất và bộ nhớ trong tương lai, vì mỗi mesh được coi là độc nhất và chiếm bộ nhớ và các cuộc gọi vẽ.

  • Giới hạn số pixel của các hình ảnh xuống không quá mức cần thiết. Trừ khi một hình ảnh chiếm một lượng lớn không gian vật lý trên màn hình, nó thường cần tối đa là 512x512 pixel. Hầu hết các hình ảnh nhỏ hơn nên nhỏ hơn 256x256 pixel.

  • Sử dụng các tấm trim để đảm bảo việc tái sử dụng văn bản tối đa trong các bản đồ 3D. Đối với các bước và ví dụ về cách tạo các tấm trim, xem Tạo các tấm trim.

    Bạn cũng có thể xem xét sử dụng các tấm sprite để tải nhiều hình ảnh UI nhỏ hơn như một hình ảnh duy nhất. Bạn có thể sau đó sử dụng ImageLabel.ImageRectOffsetImageLabel.ImageRectSize để hiển thị các phần của tấm.

Thời gian tải

Nhiều trò chơi triển khai các màn hình tải tùy chỉnh và sử dụng phương pháp ContentProvider:PreloadAsync() để yêu cầu các tài sản nhằm đảm bảo rằng hình ảnh, âm thanh và mesh được tải xuống trong nền.

Lợi ích của cách tiếp cận này là nó cho phép bạn đảm bảo rằng các phần quan trọng trong trò chơi của bạn được tải hoàn toàn mà không có hiện tượng pop-in. Tuy nhiên, một sai lầm phổ biến là sử dụng quá nhiều phương pháp này để tải trước nhiều tài sản hơn mức cần thiết.

Một ví dụ về thực hành kém là tải toàn bộ Workspace. Mặc dù điều này có thể ngăn hiện tượng pop-in về văn bản, nhưng nó làm tăng thời gian tải xuống đáng kể.

Một phương pháp tương tự là sử dụng ContentProvider.RequestQueueSize để đảm bảo rằng tất cả các tài sản đã được yêu cầu đã hoàn tất việc tải. Tuy nhiên, điều này gây ra vấn đề tương tự về thời gian tải tăng lên đáng kể, đồng thời cũng là một phương pháp không đáng tin cậy do tính chất biến động của nó.

Thay vào đó, chỉ sử dụng ContentProvider:PreloadAsync() trong các tình huống cần thiết, bao gồm:

  • Hình ảnh trong màn hình tải.
  • Những hình ảnh quan trọng trong menu trò chơi của bạn, chẳng hạn như nền và biểu tượng nút.
  • Các tài sản quan trọng trong khu vực bắt đầu hoặc tái sinh.

Nếu bạn cần tải một lượng lớn tài sản, chúng tôi khuyến nghị bạn cung cấp một nút Bỏ qua tải.

©2026 Roblox Corporation. Roblox, logo Roblox và Powering Imagination là các nhãn hiệu đã đăng ký và chưa đăng ký của chúng tôi tại Hoa Kỳ và các quốc gia khác.