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 phép toán tốn kém trong mã Luau mất nhiều thời gian xử lý hơn và do đó có thể ảnh hưởng đến tỷ lệ khung hình. Trừ khi nó được thực hiện song song, mã Luau chạy đồng bộ và chặn luồng chính cho đến khi nó gặp một hàm trả luồng.

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

  • Các phép toán nặng trên cấu trúc bảng - Các phép toán phức tạp như chuyển đổi định dạng, hủy chuyển đổi định dạng và sao chép sâu đều tốn kém về hiệu suất, đặ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 những phép toán 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 tần suất cao - Kết nối các phép toán tốn kém với các sự kiện dựa trên khung hình của RunService mà không giới hạn tần suất có nghĩa là các phép toán này sẽ được lặp lại mỗi khung hình, điều này thường dẫn đến việc tăng thời gian tính toán không cần thiết. Các sự kiện này bao gồm:

Giảm thiểu

  • Gọi mã trong 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 cho những 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 tiền sử dụng task.wait() để phân chia công việc qua nhiều khung hình.
  • Xác định và tối ưu hóa các phép toán 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 trên máy chủ có thể hưởng lợi từ tạo mã gốc, một cờ đơn giản biên dịch kịch bản 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 bằng cách sử dụng MicroProfiler, hãy xem thư viện debug, bao gồm các chức năng để đánh dấu mã cụ thể và tăng cường độ chính xác, chẳng hạn như debug.profilebegindebug.profileend. Nhiều phương thức API Roblox được gọi bởi kịch bản cũng có các thẻ MicroProfiler liên quan của riêng chúng 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 tốn 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ỉ bộ nhớ đặc biệt phổ biến trên máy chủ, vì chúng có thể liên tục hoạt động trong nhiều ngày, trong khi phiên người dùng thường ngắn hơn.

Các giá trị bộ nhớ sau trong Developer Console có thể cho biết một vấn đề cần điều tra thêm:

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

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

  • Để kết nối vẫn kết nối - Động cơ không bao giờ thu gom rác các sự kiện kết nối với một instance 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 instances đã kết nối, các hàm đã kết nối, và các giá trị tham chiếu, nằm ngoài phạm vi của bộ thu gom rác bộ nhớ, ngay cả sau khi các sự kiện đã được kích hoạt.

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

  • Các bảng - Chèn các đối tượng vào các bảng nhưng không gỡ bỏ chúng khi không còn cần thiết gây ra tiêu thụ bộ nhớ không cần thiết, đặc biệt là 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 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ớ hơn khi ngày càng nhiều người tham gia phiên. Bất kỳ mã nào lặp qua bảng này cũng trở nên tốn kém tính toán hơn khi bảng tăng kích thước.

Giảm thiểu

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

  • Ngắt kết nối tất cả các kết nối - Đi qua mã 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 các cách sau:

    • Ngắt kết nối thủ công bằng cách sử dụng hàm Disconnect().
    • Phá hủy instance mà sự kiện thuộc về bằng hàm Destroy().
    • Phá hủy đối tượng kịch bản mà kết nối quay ngược về.
  • Gỡ bỏ đối tượng người chơi và nhân vật sau khi rời - Kích hoạt Workspace.PlayerCharacterDestroyBehavior để tự động phá hủy đố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 muốn, bạn có thể thay vào đó dọn dẹp chúng 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ý

Sự mô phỏng vật lý quá mức có thể là nguyên nhân chính dẫn đến tăng thời gian tính toán cho mỗi khung hình trên cả máy chủ và khách hàng.

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

  • Tần suất bước thời gian vật lý quá mức - Mặc định, hành vi bước là ở 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ải thiện cho vật lý cũng có sẵn, điều này buộc tất cả các lắp ráp vật lý bước ở 240 Hz (bốn lần mỗi khung hình). Điều này dẫn đến việc tính toán nhiều hơn đáng kể mỗi khung hình.

  • Số lượng phức tạp của các đối tượng mô phỏng - Càng có nhiều lắp ráp 3D được mô phỏng, thì thời gian tính toán vật lý sẽ kéo dài hơn 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 hoặc sẽ có các cơ chế có nhiều ràng buộc và khớp nối hơn mức cần thiết.

  • Phát hiện va chạm quá chính xác - Các phần mesh có thuộc tính CollisionFidelity để phát hiện va chạm, cung cấp nhiều chế độ 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 cao nhất và mất nhiều thời gian hơn để tính toán.

Giảm thiểu

  • Ghim các phần không cần mô phỏng - Ghim 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 các 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ần suất 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ý í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ế

    • Ở nơi có thể, tối thiểu số lượng ràng buộc hoặc khớp nối vật lý trong một lắp ráp.
    • Giảm số lượng va chạm tự nhau trong một cơ chế, chẳng hạn bằng cách áp dụng giới hạn hoặc không va chạm cho các chi nhánh 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 thể tương tác mà người dùng hiếm khi nhận thấy sự khác biệt, sử dụng độ chính xác hộp.

    • Đối với các đối tượng có kích thước nhỏ đến trung bình, sử dụng độ chính xác hộp hoặc thân, 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, 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 yêu cầu va chạm, vô hiệu hóa va chạm và sử dụng độ chính xác hộp hoặc thân, 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 để gỡ lỗi 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ổ xem 3D.

      Ngoài ra, bạn có thể áp dụng bộ lọc CollisionFidelity=PreciseConvexDecomposition cho Explorer để hiển thị số lượng 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 tỷ lệ va chạm cân bằng giữa yêu cầu độ chính xác và hiệu suất của bạn, hãy xem Cài đặt tham số vật lý và hiển thị.

Phạm vi MicroProfiler

Phạm viTính toán liên quan
physicsSteppedTính toán vật lý tổng thể
worldStepCác bước vật lý rời rạ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 tốn 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á các ranh giới va chạm của mesh.

Vấn đề phổ biến

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

Nếu bạn thấy mức tiêu thụ bộ nhớ cao trong PhysicsParts, bạn có thể cần xem xét 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ớ được 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, vô hiệu hóa va chạm của chúng bằng cách thiết lập BasePart.CanCollide, BasePart.CanTouchBasePart.CanQuery thành false.
  • Giảm độ chính xác của va chạm bằng cách sử dụng thiết lập CollisionFidelity. Box có mức tiêu thụ bộ nhớ thấp nhất, trong khi DefaultPrecise thường đắt 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 rất phức tạp, bạn có thể muốn xây dựng mesh va chạm của riêng mình từ các đối tượng nhỏ hơn có độ chính xác va chạm hộp.

Nhân bản

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

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

  • Để tất cả HumanoidStateTypes được kích hoạt trên NPC - Có một chi phí hiệu suất để để lại một số HumanoidStateTypes được kích hoạt. Vô hiệu hóa bất kỳ cái nào không cần thiết cho NPC của bạn. Ví dụ, trừ khi NPC của bạn sẽ leo thang, bạn có thể vô hiệu hóa trạng thái Climbing.
  • Tạo, sửa đổi và hồi sinh các mô hình có Humanoids hoặc MeshParts thường xuyên
    • Điều này có thể gây khó khăn cho động cơ để xử lý, đặc biệt là nếu các mô hình này sử dụng quần áo đa lớp. Điều này cũng có thể đặc biệt vấn đề trong các trò chơi nơi các avatar hồi sinh thường xuyên.
    • Trong MicroProfiler, nhiều thẻ updateInvalidatedFastClusters dài (trên 4 ms) thường là dấu hiệu cho thấy việc tạo/sửa đổi avatar kích hoạt các rò rỉ không cần thiết.
  • 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 thiết phải có lớp Humanoid.
  • Chạy các hoạt ảnh trên một số lượng lớn NPC từ máy chủ - Các hoạt ảnh của NPC chạy trên máy chủ cần được mô phỏng trên máy chủ và được sao chép đến khách hàng. Điều này có thể là gánh nặng không cần thiết.
  • Thực hiện các thay đổi kích thước và tỷ lệ không cần thiết - Thay đổi kích thước/tỷ lệ gây ra việc sửa đổi FastCluster. Hãy cố gắng giảm điều này trong thời gian chơi nếu bạn thấy các vấn đề hiệu suất liên quan đến FastCluster. Tương tự, những thay đổi thuộc tính khác cũng có thể dẫn đến việc FastCluster bị hồi phục, vì vậy nói chung giảm bớt những thay đổi này càng nhiều càng tốt.

Giảm thiểu

  • Chơi hoạt ảnh NPC trên khách - Trong các trò chơi có số lượng lớn NPC, hãy xem xét việc tạo Animator trên máy khách và chạy các hoạt ảnh tại chỗ. Điều này giảm tải cho máy chủ và cần thiết phải sao chép không cần thiết. Nó cũng tạo điều kiện cho các tối ưu hóa bổ sung (như chỉ phát hoạt ảnh cho các NPC gần nhân vật).
  • Sử dụng các thay thế thân thiện với hiệu suất cho Humanoids - Các mô hình NPC không nhất thiết cần 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 di chuyển xung quanh mà 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.
  • 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.
  • Pool các mô hình NPC với tần suất hồi sinh - Thay vì phá hủy hoàn toàn một NPC, hãy gửi NPC đến một pool các NPC không hoạt động. Bằng cách này, khi một NPC mới cần hồi sinh, bạn có thể đơn giản kích hoạt lại một trong các NPC từ pool. Quá trình này được gọi là pooling, giúp giảm thiểu số lần các nhân vật cần được tạo.
  • Chỉ sinh ra NPC khi người dùng ở gần - Không sinh ra NPC khi người dùng không ở trong tầm nhìn, và cắt giảm chúng khi người dùng rời khỏi tầm nhìn của họ.
  • Tránh thay đổi cấu trúc avatar sau khi nó được tạo - Một số sửa đổi cho cấu trúc avatar có tác động lớn đế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 đó, hãy 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 avatar, hãy làm điều này bên ngoài cấu trúc của Model avatar.

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
updateInvalidatedFastClustersCó liên quan đến việc tạo ra hoặc sửa đổi một avatar

Hiển thị

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

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ừ động cơ đến GPU để hiển thị một cái gì đó. Các cuộc gọi vẽ có nhiều chi phí overhead. Nói chung, càng ít cuộc gọi vẽ mỗi khung hình, thời gian tính toán dành cho việc hiển thị một khung hình càng ít.

Bạn có thể xem số lượng cuộc gọi vẽ đang xảy ra với mục Render StatsTiming trong Studio. Bạn có thể xem Render Stats trong khách bằng cách nhấn ShiftF2.

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

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

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

    Các đối tượng như decal, kết cấu và hạt không gộp tốt và giới thiệu các cuộc gọi vẽ bổ sung. Đặc biệt chú ý đến các loại đối tượng này trong một cảnh. Cụ thể, các thay đổi thuộc tính đối với ParticleEmitters có thể tác động lớn đến hiệu suất.

  • Bỏ lỡ cơ hội instancing - Thường thì, một cảnh sẽ bao gồm cùng một mesh được nhân đôi một số lần, nhưng mỗi bản sao của mesh có các ID tài sản mesh hoặc kết cấu khác nhau. Điều này ngăn chặn việc instancing và có thể dẫn đến các cuộc gọi vẽ không cần thiế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ì các tài sản riêng lẻ được nhập vào Roblox và sau đó 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ó thể giúp bạn xác định các phần mesh có cùng tên sử dụng các ID mesh 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ư sau. Các dòng lặp lại cho thấy việc sử dụng lại cùng một mesh, điều này là tốt. Các dòng duy 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 biết 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ả là có thể là bản sao
  • Độ 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à một khung hình cần để hiển thị. Các cảnh với số lượng rất lớn các mesh rất phức tạp là một vấn đề phổ biến, như là các cảnh có thuộc tính MeshPart.RenderFidelity được đặt thành Precise trên quá nhiều mesh.

  • Gây bóng quá nhiều - Xử lý bóng là một quá trình tốn kém, và các bản đồ chứa nhiều đối tượng ánh sáng với một số và độ dày cao gây bóng (hoặc một số và độ dày cao của các phần nhỏ bị ảnh hưởng bởi bóng) có thể có các vấn đề về hiệu suất.

  • Overdraw độ trong suốt cao không cần thiết - Đặt các đối tượng với độ trong suốt một phần gần nhau buộc động cơ phải hiển thị 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à sửa vấn đề này, hãy xem Xóa các độ trong suốt gộp.

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

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

Giảm thiểu

  • Gộp các mesh giống hệt nhau và giảm số lượng mesh duy nhất - Nếu bạn đảm bảo tất cả các mesh giống hệt nhau có cùng ID tài sản cơ bản, động cơ có thể nhận diện và hiển thị chúng trong một cuộc gọi vẽ duy nhất. Đảm bảo chỉ cần tải mỗi mesh trong một bản đồ một lần và sau đó nhân đôi chúng trong Studio để tái sử dụng thay vì nhập toàn bộ bản đồ, điều này có thể khiến các mesh giống nhau có các ID nội dung khác nhau và được động cơ nhận diện như các tài sản độc nhất. Gói 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 tham gia vào khung hình đã hiển thị cuối cùng. Theo mặc định, động cơ bỏ qua các cuộc gọi vẽ cho các đối tượng bên ngoài tầm nhìn máy ảnh (frustum culling) và các phần, mesh, và địa hình bị khuất tầm nhìn bởi các đối tượng khác (occlusion culling). Trong một số tình huống, chẳng hạn như môi trường trong nhà, bạn có thể có khả năng 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 bớt cuộc gọi vẽ hay tải tính toán tổng thể hơn nữa.

  • Giảm mức độ chi tiết cho các mô hình - Kích hoạt streaming instance và thiết lập thuộc tính LevelOfDetail của các mô hình thế giới của bạn thành SLIM để hiển thị mesh SLIM nhẹ tối ưu hóa cho mô hình khi khoảng cách từ máy ảnh tăng lên.

  • Giảm mức độ chi tiết cho các avatar - Kích hoạt streaming instance và thiết lập Workspace.EnableSLIMAvatars để hiển thị các avatar nền tảng như các biểu diễn lightweight SLIM tối ưu hóa với đầy đủ hỗ trợ hoạt ảnh khi khoảng cách từ máy ảnh tăng lên.

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

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

    • Sử dụng thuộc tính BasePart.CastShadow để vô hiệu hóa ánh sáng trên các phần nhỏ nơi bóng không có khả năng hiển thị. 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.

    • Vô hiệu hóa bóng trên các đối tượng di chuyển khi có thể.

    • Vô hiệu hóa Light.Shadows trên các instances ánh sáng nơi mà đối tượng không cần phải gây bóng.

    • Giới hạn phạm vi và góc của các instances ánh sáng.

    • Sử dụng ít instances ánh sáng hơn.

    • Cân nhắc vô hiệu hóa ánh sáng ngoài một phạm vi cụ thể hoặc trên cơ sở 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 PerformHiển thị tổng thể
Perform/Scene/computeLightingPerformCập nhật ánh sáng lưới 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 hiển thị và cập nhật hạt
Perform/Scene/RenderViewHiển thị và xử lý hậu kỳ

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 khách hàng kết nối. Thông tin được gửi giữa khách và máy chủ mỗi khung hình, nhưng một lượng lớn thông tin yêu cầu nhiều thời gian tính toán hơn.

Các 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 dành cho việc xử lý các gói vào 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 đầu vào của người dùng mà không có bất kỳ cơ chế nào để kiểm soát.
    • Phát thông tin nhiều hơn mức cần thiết. Ví dụ, gửi toàn bộ kho đồ của người chơi khi họ mua một mục thay vì chỉ thông tin về mục đã mua.
  • Tạo hoặc loại bỏ các cây instance phức tạp - Khi có sự thay đổi trong mô hình dữ liệu trên máy chủ, nó sẽ được sao chép đến các khách hàng đã kết nối. Điều này có nghĩa là việc tạo và hủy các hệ thống cây instance lớn như bản đồ tại thời gian chạy có thể rất nặng nề cho 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 bản rig. Nếu những thứ này không bị xóa trước khi trò chơi được phát hành và mô hình hoạt hình được nhân đôi thường xuyên, một lượng lớn dữ liệu sẽ được 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 tweened được sao chép đến mỗi khách hàng mỗi khung hình. Điều này không chỉ khiến việc tween bị nhấp nháy khi độ trễ của khách hàng dao động, mà còn gây ra một lượng lớn lưu lượng mạng không cần thiết.

Giảm thiểu

Bạn có thể áp 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 qua các sự kiện từ xa. Thay vào đó, chỉ gửi 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 nó thay đổi thay vì mỗi khung hình.
  • Chia nhỏ các cây instance phức tạp như các bản đồ và tải chúng từng phần để phân phối 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 việc sao chép instance không cần thiết, đặc biệt trong các trường hợp mà máy chủ không cần biết về các instances đang được tạo. Điều này bao gồm:
    • Các hiệu ứng hình ảnh như một vụ nổ hoặc một phép thuật ma thuật. Máy chủ chỉ cần biết vị trí để xác định kết quả, trong khi các khách hàng có thể tạo hình ảnh cục bộ.
    • Các mô hình xem đầu đồ vật đầu tiên.
    • Tween các đối tượng trên máy khách 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 vào, chẳng hạn như gọi sự kiện và thay đổi thuộc tính
Allocate Bandwidth and Run SendersCác sự kiện ra liên quan trên các máy chủ

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

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

Streaming instance

Streaming instance tải ra một cách chọn lọc 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 đáng kể giảm và tăng khả năng của khách để ngăn ngừa các sự cố khi gặp phải áp lực bộ nhớ.

Nếu bạn đang gặp phải các vấn đề về bộ nhớ và đã bật streaming instance vô hiệu, hãy xem xét việc cập nhật 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 instance dựa trên khoảng cách trong không gian 3D, vì vậy các thế giới lớn về cơ bản được hưởng lợi nhiều hơn từ nó.

Nếu streaming instance được bật, bạn có thể tăng cường độ chặt chẽ của nó. Ví dụ, hãy xem xét:

  • Giảm sử dụng Enum.ModelStreamingMode.Persistent ở mức có thể. Bạn có thể cần cập nhật mã của mình nếu bạn đang sử dụng nó như là 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, hãy xem tính chất streaming.

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

  • Sao chép 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 bị 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 - Các tệp âm thanh có thể là một yếu tố bất ngờ gây ra mức sử dụng bộ nhớ, đặc biệt nếu bạn tải tất cả chúng vào khách 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 các chiến lược, hãy xem Thời gian tải.

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

    Các hình ảnh tải lên Roblox được chuyển đổi sang một định dạng cố định, vì vậy không có lợi ích bộ nhớ nào trong việc tải lên hình ảnh trong một mô hình màu liên quan đến ít byte trên mỗi pixel hơn. Tương tự như vậy, nén hình ảnh trước khi tải lên hoặc loại bỏ kênh alpha khỏi hình ảnh không cần thiết có thể 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 được tải, động cơ sẽ tự động bắt đầu với các kết cấu chất lượng thấp hơn và sau đó tăng bậc chất lượng dựa trên bộ nhớ thiết bị có sẵn, khoảng cách từ camera, lượng không gian màn hình mà kết cấu chiếm và các yếu tố khác. Ngay cả như vậy, việc định hình kích thước của các kết cấu của bạn có thể cải thiện việ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 - Sử dụng cùng một ID tài sản giữa các đối tượng và đảm bảo các tài sản giống hệt nhau, đặc biệt là mesh và hình ảnh, không được tải lên một cách riêng biệt nhiều lần.

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

    • Mặc dù không có API tự động để phát hiện sự tương đồng giữ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 nơi của bạn (hoặc thủ công hoặc bằng một kịch bản), tải chúng 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 phần trùng lặp.
    • Thay vì sử dụng các kết cấu riêng biệt cho các màu sắc khác nhau, hãy tải lên một kết cấu duy nhất và sử dụng thuộc tính SurfaceAppearance.Color để áp dụng các sắc thái khác nhau cho nó.
  • Nhập các tài sản trong bản đồ riêng lẻ - Thay vì nhập toàn bộ bản đồ cùng một lúc, nhập và tái cấu trúc các tài sản trong bản đồ một cách riêng biệt. Trình Nhập không thực hiện bất kỳ việc loại bỏ trùng lặp 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 sàn riêng biệt, mỗi viên sàn đó sẽ được nhập như một tài sản riêng biệt (ngay cả khi chúng là các bản sao). Điều này có thể dẫn đến các vấn đề về hiệu suất và bộ nhớ sau này, vì mỗi mesh được coi là riêng biệt và chiếm bộ nhớ và cuộc gọi vẽ.

  • Giới hạn số pixel của hình ảnh xuống chỉ nhiều nhất bằng số pixel 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, thông thường nó 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ờ trim để đảm bảo tái sử dụng tối đa kết cấu trong các bản đồ 3D. Để biết các bước và ví dụ về cách tạo các tờ trim, hãy xem Tạo các tờ trim.

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

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 thức ContentProvider:PreloadAsync() để yêu cầu tài sản để các hình ảnh, âm thanh và mesh được tải xuống trong nền.

Ưu điểm của phương pháp này là nó đảm bảo các phần quan trọng của trò chơi của bạn được tải đầy đủ mà không có sự gián đoạn. 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 quá nhiều tài sản thực sự không cần thiết.

Một ví dụ về một thực hành không tốt là tải toàn bộ Workspace. Mặc dù điều này có thể ngăn ngừa việc hình ảnh xuất hiện, nhưng nó sẽ tăng thời gian tải lên đá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 đã yêu cầu đã hoàn tất tải. Tuy nhiên, điều này gây ra vấn đề tương tự là thời gian tải tăng lên đáng kể, đồng thời cũng không phải là một phương pháp đáng tin cậy do tính chất dao độ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.
  • Hình ảnh quan trọng trong menu trò chơi của bạn, chẳng hạn như hình nền nút và biểu tượng.
  • Tài sản quan trọng trong khu vực bắt đầu hoặc hồi sinh.

Nếu bạn phải tải một số lượng lớn tài sản, chúng tôi khuyên bạn nê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.