Leistung verbessern

*Dieser Inhalt wurde mit KI (Beta) übersetzt und kann Fehler enthalten. Um diese Seite auf Englisch zu sehen, klicke hier.

Diese Seite beschreibt häufige Leistungsprobleme und bewährte Praktiken zu deren Minderung.

Skriptberechnung

Teure Operationen in Luau-Code benötigen länger zur Verarbeitung und können so die Bildrate beeinträchtigen. Sofern sie nicht parallel ausgeführt werden, wird Luau-Code synchron ausgeführt und blockiert den Haupt-Thread, bis er auf eine Funktion trifft, die den Thread yieldet.

Häufige Probleme

  • Intensive Operationen an Tabellenstrukturen - Komplexe Operationen wie Serialisierung, Deserialisierung und tiefes Klonen verursachen hohe Leistungskosten, insbesondere bei großen Tabellenstrukturen. Dies gilt insbesondere, wenn diese Operationen rekursiv sind oder beim Durchlaufen sehr großer Datenstrukturen.

  • Hochfrequente Ereignisse - Teure Operationen mit bildbasierten Ereignissen in RunService ohne Frequenzbegrenzung zu verknüpfen, bedeutet, dass diese Operationen in jedem Frame wiederholt werden, was oft zu einer unnötigen Erhöhung der Rechenzeit führt. Diese Ereignisse umfassen:

Minderung

  • Rufen Sie Code bei RunService-Ereignissen sparsam auf und beschränken Sie die Verwendung auf Fälle, in denen eine hochfrequente Aufrufhäufigkeit entscheidend ist (zum Beispiel, um die Kamera zu aktualisieren). Den meisten anderen Code können Sie in anderen Ereignissen oder weniger häufig in einer Schleife ausführen.
  • Zerlegen Sie große oder teure Aufgaben, indem Sie task.wait() verwenden, um die Arbeit über mehrere Frames zu verteilen.
  • Identifizieren und optimieren Sie unnötig teure Operationen und verwenden Sie Multithreading für rechenintensive Aufgaben, die nicht auf das Datenmodell zugreifen müssen.
  • Bestimmte serverseitige Skripte können von nativem Code-Generierung profitieren, einer einfachen Flagge, die ein Skript in Maschinencode anstatt in Bytecode kompiliert.

MicroProfiler-Bereiche

BereichAssoziierte Berechnung
RunService.PreRenderCode, der beim PreRender-Ereignis ausgeführt wird
RunService.PreSimulationCode, der beim Stepped-Ereignis ausgeführt wird
RunService.PostSimulationCode, der beim Heartbeat-Ereignis ausgeführt wird
RunService.HeartbeatCode, der beim Heartbeat-Ereignis ausgeführt wird

Für weitere Informationen zur Debugging von Skripten mit dem MicroProfiler siehe die debug-Bibliothek, die Funktionen zum Taggen spezifischer Codes und zur weiteren Erhöhung der Spezifität enthält, wie debug.profilebegin und debug.profileend. Viele von Skripten aufgerufene Roblox-API-Methoden haben ebenfalls ihre eigenen zugeordneten MicroProfiler-Tags, die nützliche Signale liefern können.

Speicherverbrauch von Skripten

Speicherlecks können auftreten, wenn Sie Skripte schreiben, die Speicher verbrauchen, den der Garbage Collector nicht ordnungsgemäß freigeben kann, wenn er nicht mehr verwendet wird. Lecks sind insbesondere auf dem Server verbreitet, da diese häufig über viele Tage hinweg online sein können, während eine Client-Sitzung viel kürzer ist.

Die folgenden Speicherwerte in der Entwicklerkonsole können auf ein Problem hinweisen, das weitere Untersuchungen erfordert:

  • LuaHeap - Hoher oder wachsender Verbrauch deutet auf ein Speicherleck hin.
  • InstanceCount - Ständig wachsende Anzahl von Instanzen legt nahe, dass Referenzen zu einigen Instanzen in Ihrem Code nicht vom Garbage Collector gesammelt werden.
  • PlaceScriptMemory - Bietet eine Skript-für-Skript-Aufschlüsselung der Speichernutzung.

Häufige Probleme

  • Verbindung von Verbindungen lassen - Die Engine sammelt niemals Ereignisse, die mit einer Instanz verbunden sind, und alle innerhalb des verbundenen Rückrufs referenzierten Werte. Daher sind aktive Verbindungen zu Ereignissen und Code innerhalb der verbundenen Instanzen, verbundene Funktionen und referenzierte Werte außerhalb des Scopes für den Speicher-Garbage-Collector, selbst nachdem die Ereignisse ausgelöst wurden.

    Obwohl Ereignisse getrennt werden, wenn die Instanz, zu der sie gehören, zerstört wird, ist ein häufiger Fehler anzunehmen, dass dies auf Player-Objekte zutrifft. Nachdem ein Benutzer ein Spiel verlassen hat, zerstört die Engine deren repräsentatives Player-Objekt und Charaktermodell nicht automatisch, sodass Verbindungen zu dem Player-Objekt und Instanzen unter dem Charaktermodell, wie CharacterAdded, weiterhin Speicher verbrauchen, wenn Sie diese in Ihren Skripten nicht trennen. Dies kann im Laufe der Zeit zu sehr erheblichen Speicherlecks auf dem Server führen, wenn Hunderte von Benutzern das Spiel betreten und verlassen.

  • Tabellen - Das Einfügen von Objekten in Tabellen, diese jedoch nicht zu entfernen, wenn sie nicht mehr benötigt werden, führt zu unnötigem Speicherverbrauch, insbesondere bei Tabellen, die Benutzerdaten beim Beitritt verfolgen. Zum Beispiel erstellt der folgende Beispielcode eine Tabelle, die jedes Mal Benutzerinformationen hinzufügt, wenn ein Benutzer beitritt:

    Beispiel
    local playerInfo = {}
    Players.PlayerAdded:Connect(function(player)
    playerInfo[player] = {} -- einige Informationen
    end)

    Wenn Sie diese Einträge nicht entfernen, wenn sie nicht mehr benötigt werden, wächst die Tabelle weiter in der Größe und verbraucht mehr Speicher, während mehr Benutzer der Sitzung beitreten. Jeder Code, der über diese Tabelle iteriert, wird ebenfalls rechenintensiver, je größer die Tabelle wird.

Minderung

Um alle verwendeten Werte zur Verhinderung von Speicherlecks zu bereinigen:

  • Trennen Sie alle Verbindungen - Gehen Sie durch Ihren Code und stellen Sie sicher, dass jede Verbindung über einen der folgenden Pfade bereinigt wird:

    • Manuelles Trennen mithilfe der Funktion Disconnect().
    • Zerstören der Instanz, zu der das Ereignis gehört, mit der Funktion Destroy().
    • Zerstören des Skriptobjekts, auf das die Verbindung zurückführt.
  • Entfernen Sie Spielerobjekte und Charaktere nach dem Verlassen - Aktivieren Sie Workspace.PlayerCharacterDestroyBehavior, um Spielerobjekte und Charaktermodelle nach dem Verlassen eines Benutzers automatisch zu zerstören. Alternativ können Sie diese manuell bereinigen:

    Beispiel: Spieler- und Charakterbereinigung
    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)

Physikberechnung

Übermäßige Physiksimulation kann eine zentrale Ursache für verlängerte Rechenzeiten pro Frame sowohl auf dem Server als auch auf dem Client sein.

Häufige Probleme

  • Übermäßige Physik-Zeitstufefrequenz - Standardmäßig erfolgt das Steppenverhalten im adaptiven Modus, bei dem Physik mit 60 Hz, 120 Hz oder 240 Hz, je nach Komplexität des physikalischen Mechanismus, steppt.

    Ein fester Modus mit verbesserter Genauigkeit der Physik ist ebenfalls verfügbar, der alle physikalischen Baugruppen mit 240 Hz (viermal pro Frame) steppt. Dies führt zu erheblich mehr Berechnungen pro Frame.

  • Übermäßige Anzahl von komplexen simulierten Objekten - Je mehr 3D-Baugruppen simuliert werden, desto länger dauert die Physikberechnung pro Frame. Oft haben Spiele Objekte, die simuliert werden, die es nicht benötigen oder Mechanismen, die mehr Einschränkungen und Gelenke aufweisen, als sie benötigen.

  • Übermäßig präzise Kollisionserkennung - Mesh-Teile haben eine CollisionFidelity-Eigenschaft zur Erkennung von Kollisionen, die verschiedene Modi mit unterschiedlichen Leistungsanforderungen bietet. Der präzise Kollisionserkennungsmodus für Mesh-Teile hat die teuersten Leistungskosten und benötigt länger, um von der Engine berechnet zu werden.

Minderung

  • Verankern Sie Teile, die keine Simulation erfordern - Verankern Sie alle Teile, die nicht von Physik angetrieben werden müssen, wie statische NPCs.

  • Verwenden Sie adaptive Physik-Steppung - Adaptive Steppung passt die Rate der physikalischen Berechnungen dynamisch an, sodass Physikupdates in einigen Fällen seltener durchgeführt werden können.

  • Reduzieren Sie die Komplexität des Mechanismus

    • Minimieren Sie nach Möglichkeit die Anzahl der physikalischen Einschränkungen oder Gelenke in einer Baugruppe.
    • Reduzieren Sie die Selbstkollision innerhalb eines Mechanismus, indem Sie Einschränkungen oder keine Kollisionen auf Ragdoll-Gliedmaßen anwenden, um zu verhindern, dass sie miteinander kollidieren.
  • Reduzieren Sie die Verwendung von präziser Kollisionserkennung für Meshes

    • Verwenden Sie für kleine oder nicht interaktive Objekte, bei denen Benutzer den Unterschied selten bemerken würden, Box-Fidelity.

    • Verwenden Sie für kleine bis mittelgroße Objekte je nach Form Box- oder Hülleneinstellungen.

    • Erstellen Sie für große und sehr komplexe Objekte, wann immer möglich, benutzerdefinierte Kollisionen mit unsichtbaren Teilen.

    • Für Objekte, die keine Kollisionen erfordern, deaktivieren Sie Kollisionen und verwenden Sie eine Box- oder Hülleneinstellung, da die Kollisionsgeometrie weiterhin im Speicher gespeichert wird.

    • Sie können die Kollision Geometrie zu Debugging-Zwecken im Studio anzeigen, indem Sie Kollisionsgenauigkeit aus dem Visualisierungsoptionen-Widget in der oberen rechten Ecke des 3D-Viewport aktivieren.

      Alternativ können Sie den CollisionFidelity=PreciseConvexDecomposition-Filter auf den Explorer anwenden, der eine Zählung aller Mesh-Teile mit der präzisen Genauigkeit anzeigt und es Ihnen ermöglicht, diese einfach auszuwählen.

    • Für eine eingehende Anleitung zum Auswählen einer Kollisionseinstellungsoption, die Ihre Genauigkeits- und Leistungsanforderungen ausbalanciert, siehe Physik- und Rendering-Parameter einstellen.

MicroProfiler-Bereiche

BereichAssoziierte Berechnung
physicsSteppedGesamte Physikberechnung
worldStepDiskrete Physikschritte, die in jedem Frame durchgeführt werden

Physikspeicherverbrauch

Die Bewegung und Kollisionserkennung der Physik verbrauchen Speicher. Mesh-Teile haben eine CollisionFidelity-Eigenschaft, die den Ansatz bestimmt, der zur Bewertung der Kollisionsgrenzen des Meshs verwendet wird.

Häufiges Problem

Die Standard- und präzisen Kollisionserkennungsmodi verbrauchen erheblich mehr Speicher als die beiden anderen Modi mit niedrigerer Fidelity der Kollisionformen.

Wenn Sie hohe Speicherverbrauchswerte unter PhysicsParts sehen, müssen Sie möglicherweise die Kollisionsgenauigkeit von Objekten in Ihrem Spiel reduzieren.

Wie man mildert

Um den Speicherverbrauch für Kollisionen zu reduzieren:

  • Für Teile, die keine Kollisionen erfordern, deaktivieren Sie deren Kollisionen, indem Sie BasePart.CanCollide, BasePart.CanTouch und BasePart.CanQuery auf false setzen.
  • Reduzieren Sie die Genauigkeit von Kollisionen mithilfe der CollisionFidelity-Einstellung. Box hat die niedrigsten Speicherüberhead, und Default und Precise sind normalerweise teurer.
    • Es ist im Allgemeinen sicher, die Kollisionseinstellung von kleinen verankerten Teilen auf Box zu setzen.
    • Für sehr komplexe große Meshes sollten Sie möglicherweise Ihr eigenes Kollisionsmesh aus kleineren Objekten mit Box-Kollisionsgenauigkeit erstellen.

Humanoiden

Humanoid ist eine Klasse, die ein breites Spektrum an Funktionen für Spieler- und Nicht-Spieler-Charaktere (NPCs) bietet. Obwohl sie mächtig ist, bringt ein Humanoid erhebliche Berechnungskosten mit sich.

Häufige Probleme

  • Alle HumanoidStateTypes bei NPCs aktiv lassen - Es gibt Kosten in der Leistung, wenn bestimmte HumanoidStateTypes aktiviert bleiben. Deaktivieren Sie alle, die für Ihre NPCs nicht notwendig sind. Zum Beispiel ist es sicher, den Zustand Climbing zu deaktivieren, es sei denn, Ihr NPC wird Leitern erklimmen.
  • Instanziieren, Modifizieren und Respawnen von Modellen mit Humanoids oder skinn-MeshParts häufig
    • Dies kann intensiv für die Engine sein, insbesondere wenn diese Modelle geschichtete Kleidung verwenden. Dies kann auch besonders problematisch in Spielen sein, in denen Avatare häufig respawnen.
    • Im MicroProfiler sind lange updateInvalidatedFastClusters-Tags (über 4 ms) oft ein Signal dafür, dass die Instanziierung/Änderung des Avatars übermäßige Invalidierungen auslöst.
  • Humanoiden in Fällen verwenden, in denen sie nicht erforderlich sind - Statische NPCs, die sich nicht bewegen, benötigen in der Regel keine Humanoid-Klasse.
  • Animationen für eine große Anzahl von NPCs vom Server aus abspielen - NPC-Animationen, die auf dem Server ausgeführt werden, müssen auf dem Server simuliert und an den Client repliziert werden. Dies kann unnötige Overhead verursachen.
  • Unnötige Größen- und Maßänderungen durchführen - Größen-/Maßänderungen erfordern einen Neuaufbau von FastCluster. Versuchen Sie, dies während des Spielens zu verringern, wenn Sie Leistungsprobleme im Zusammenhang mit FastCluster beobachten. Ähnliche Änderungen an anderen Eigenschaften können auch einen Neuaufbau von FastCluster erfordern. Reduzieren Sie diese Änderungen im Allgemeinen so weit wie möglich.

Minderung

  • NPC-Animationen auf dem Client abspielen - In Spielen mit einer großen Anzahl von NPCs sollten Sie in Erwägung ziehen, den Animator auf dem Client zu erstellen und die Animationen lokal auszuführen. Dies verringert die Belastung des Servers und die Notwendigkeit einer unnötigen Replikation. Darüber hinaus macht es zusätzliche Optimierungen möglich (wie z.B. Animationen nur für NPCs abzuspielen, die sich in der Nähe des Charakters befinden).
  • Leistungsfreundliche Alternativen zu Humanoiden verwenden - NPC-Modelle müssen nicht unbedingt ein Humanoid-Objekt enthalten.
    • Verwenden Sie für statische NPCs einen einfachen AnimationController, da sie sich nicht bewegen müssen, sondern nur Animationen abspielen müssen.
    • Für sich bewegende NPCs sollten Sie in Erwägung ziehen, Ihren eigenen Bewegungskontroller zu implementieren und einen AnimationController für Animationen zu verwenden, abhängig von der Komplexität Ihrer NPCs.
  • Deaktivieren Sie nicht verwendete Humanoidzustände - Verwenden Sie Humanoid:SetStateEnabled(), um nur notwendige Zustände für jeden Humanoid zu aktivieren.
  • Pooling von NPC-Modellen mit häufigem Respawn - Anstatt einen NPC vollständig zu zerstören, senden Sie den NPC zu einem Pool inaktiver NPCs. Auf diese Weise können Sie, wenn ein neuer NPC für das Respawn benötigt wird, einfach einen der NPCs aus dem Pool reaktivieren. Dieser Prozess wird als Pooling bezeichnet, was die Anzahl der Instanziierungen der Charaktere minimiert.
  • Spawn von NPCs nur, wenn Benutzer in der Nähe sind - Spawnen Sie keine NPCs, wenn Benutzer nicht im Bereich sind, und kürzen Sie diese, wenn Benutzer ihren Bereich verlassen.
  • Vermeiden Sie Änderungen an der Avatar-Hierarchie nach der Instanziierung - Bestimmte Modifikationen an einer Avatar-Hierarchie haben erhebliche Auswirkungen auf die Leistung. Einige Optimierungen sind verfügbar:
    • Für benutzerdefinierte prozedurale Animationen, aktualisieren Sie nicht die JointInstance.C0- und JointInstance.C1-Eigenschaften. Aktualisieren Sie stattdessen die Motor6D.Transform- Eigenschaft.
    • Wenn Sie irgendwelche BasePart-Objekte am Avatar befestigen müssen, tun Sie dies außerhalb der Hierarchie des Avatar Model.

MicroProfiler-Bereiche

BereichAssoziierte Berechnung
stepHumanoidHumanoidsteuerung und Physik
stepAnimationHumanoid- und Animatoranimation
updateInvalidatedFastClustersAssoziiert mit der Instanziierung oder Modifizierung eines Avatars

Rendering

Ein erheblicher Teil der Zeit, die der Client in jedem Frame verbringt, entfällt auf das Rendering der Szene im aktuellen Frame. Der Server führt kein Rendering durch, daher ist dieser Abschnitt exklusiv für den Client.

Draw-Calls

Ein Draw-Call ist eine Gruppe von Anweisungen von der Engine an die GPU, um etwas zu rendern. Draw-Calls haben erhebliche Overhead-Kosten. Im Allgemeinen gilt: Je weniger Draw-Calls pro Frame, desto weniger Rechenzeit wird für das Rendering eines Frames aufgewendet.

Sie können sehen, wie viele Draw-Calls derzeit ausgeführt werden, mit dem Menüpunkt RenderstatsTiming in Studio. Sie können Renderstats im Client anzeigen, indem Sie ShiftF2 drücken.

Je mehr Objekte in Ihrer Szene in einem bestimmten Frame gezeichnet werden müssen, desto mehr Draw-Calls werden an die GPU ausgegeben. Die Roblox-Engine nutzt jedoch einen Prozess namens Instanziierung, um identische Meshes mit den gleichen Texturmerkmalen in einen einzelnen Draw-Call zusammenzufassen. Insbesondere werden mehrere Meshes mit dem gleichen MeshContent in einem einzigen Draw-Call behandelt, wenn:

Weitere häufige Probleme

  • Übermäßige Objektdichte - Wenn eine große Anzahl von Objekten mit hoher Dichte konzentriert ist, erfordert das Rendern dieses Bereichs der Szene mehr Draw-Calls. Wenn Sie feststellen, dass Ihre Bildrate sinkt, wenn Sie auf einen bestimmten Teil der Karte blicken, kann dies ein gutes Signal dafür sein, dass die Objektdichte in diesem Bereich zu hoch ist.

    Objekte wie Decals, Texturen und Partikel lassen sich nicht gut bündeln und führen zu zusätzlichen Draw-Calls. Achten Sie besonders auf diese Objekttypen in einer Szene. Insbesondere können Änderungen an den Eigenschaften von ParticleEmitters erhebliche Auswirkungen auf die Leistung haben.

  • Verpasste Instanziierungsmöglichkeiten - Oft enthält eine Szene dasselbe Mesh, das mehrere Male dupliziert wurde, aber jede Kopie des Mesh hat unterschiedliche Mesh- oder Textur-Asset-IDs. Dies verhindert die Instanziierung und kann zu unnötigen Draw-Calls führen.

    Ein häufiger Grund für dieses Problem ist, wenn eine gesamte Szene auf einmal importiert wird, anstatt einzelne Assets in Roblox zu importieren und sie nach dem Import zu duplizieren, um die Szene zusammenzustellen.

    Selbst ein einfaches Skript wie dieses kann Ihnen helfen, Mesh-Teile mit demselben Namen zu identifizieren, die unterschiedliche Mesh-IDs verwenden:

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

    Die Ausgabe (mit Stacklinien aktiviert) könnte etwa so aussehen. Wiederholte Zeilen deuten darauf hin, dass das gleiche Mesh wiederverwendet wird, was gut ist. Einzigartige Zeilen sind nicht unbedingt schlecht, könnten aber je nach Ihrem Namensschema auf duplizierte Meshes in Ihrem Spiel hinweisen:

    LargeRock, rbxassetid://106420009602747 (x144) -- gut
    LargeRock, rbxassetid://120109824668127
    LargeRock, rbxassetid://134460273008628
    LargeRock, rbxassetid://139288987285823
    LargeRock, rbxassetid://71302144984955
    LargeRock, rbxassetid://90621205713698
    LargeRock, rbxassetid://113160939160788
    LargeRock, rbxassetid://135944592365226 -- alle möglichen Duplikate
  • Übermäßige Objektkomplexität - Obwohl nicht so wichtig wie die Anzahl der Draw-Calls, beeinflusst die Anzahl der Dreiecke in einer Szene, wie lange ein Frame zum Rendern benötigt. Szenen mit einer sehr hohen Anzahl sehr komplexer Meshes sind ein häufiges Problem, ebenso wie Szenen mit der MeshPart.RenderFidelity-Eigenschaft, die auf Precise für zu viele Meshes gesetzt ist.

  • Übermäßiges Schattenwerfen - Die Handhabung von Schatten ist ein kostenintensiver Prozess, und Karten, die eine hohe Anzahl und Dichte von Lichtobjekten, die Schatten werfen (oder eine hohe Anzahl und Dichte von kleinen Teilen, die von Schatten beeinflusst werden), enthalten, können Leistungsprobleme aufweisen.

  • Hohe Transparenzüberzeichnung - Das Platzieren von Objekten mit partieller Transparenz nahe beieinander zwingt die Engine, die überlappenden Pixel mehrfach zu rendern, was die Leistung beeinträchtigen kann. Für weitere Informationen zur Identifizierung und Behebung dieses Problems siehe Löschung gestapelter Transparenzen.

  • Unnötige Bewegung von skinned MeshPart - Skinned MeshParts, die Teil eines Modells ohne Humanoid sind, werden in räumlich organisierten FastClusters gruppiert. Wenn sich diese MeshParts bewegen, müssen sie kontinuierlich in und aus diesen räumlichen Clustern hinzugefügt und entfernt werden, was einen Neuaufbau der Cluster erfordert und die Leistung beeinträchtigt.

    • Eine äußerst effektive Lösung ist es, einen Humanoid innerhalb des Modells einzubetten. Das Vorhandensein eines Humanoiden überschreibt das Standardverhalten der räumlichen Clustering, wodurch die Verwendung eines einzelnen, einheitlichen FastClusters für das gesamte Modell erforderlich ist. Daher sind Positionsaktualisierungen nicht mehr auf Neuaufbauten von Clustern angewiesen, was das Leistungsengpass mildert. Diese Technik sollte ausschließlich für MeshParts mit erwarteter Bewegung reserviert werden, da sie den Speicheraufwand erhöhen und die Vorteile der räumlichen Optimierung negieren kann. Wir empfehlen dringend, Ihr Spiel nach Änderungen dieser Art zu profilieren. Weitere Informationen finden Sie in Humanoiden Leistungstipps.
  • Zu viele Teile in einem Model - Zu viele Teile in einem Modell könnten häufige Neuaufbauten verursachen, da die Wahrscheinlichkeit besteht, dass sich die Eigenschaften eines Teils ändern, was zu einem vollständigen Neuaufbau führen muss. Finden Sie das richtige Gleichgewicht von Teilen in einem Modell, wenn es FastCluster verwendet.

Minderung

  • Instanziieren identischer Meshes und Reduzierung der Anzahl einzigartiger Meshes - Wenn Sie sicherstellen, dass alle identischen Meshes die gleichen zugrunde liegenden Asset-IDs haben, kann die Engine sie erkennen und in einem einzigen Draw-Call rendern. Stellen Sie sicher, dass Sie jedes Mesh in einer Karte nur einmal hochladen und dann in Studio duplizieren, um sie wiederzuverwenden, anstatt große Karten als Ganzes zu importieren, was dazu führen kann, dass identische Meshes separate Inhalts-IDs haben und von der Engine als einzigartige Assets erkannt werden. Pakete sind ein hilfreiches Mittel zur Wiederverwendung von Objekten.

  • Culling - Culling beschreibt den Prozess der Eliminierung von Draw-Calls für Objekte, die nicht in das endgültig gerenderte Frame einfließen. Standardmäßig überspringt die Engine Draw-Calls für Objekte außerhalb des Sichtfelds der Kamera (Frustum-Culling) und Teile, Meshes und Gelände, die vom Blickfeld anderer Objekte verdeckt werden (Occlusion-Culling). In bestimmten Szenarien, wie z.B. in Innenräumen, können Sie möglicherweise ein Raum- oder Portal-System implementieren und Objekte manuell kürzen, um Draw-Calls oder die gesamte Rechenlast weiter zu reduzieren.

  • Reduzieren des Detailgrads für Modelle - Aktivieren Sie Instanz-Streaming und setzen Sie die LevelOfDetail-Eigenschaft Ihrer Weltmodelle auf SLIM, um optimierte schlanke SLIM-Meshes zu rendern, je größer der Abstand zur Kamera wird.

  • Reduzieren des Detailgrads für Avatare - Aktivieren Sie das Instanz-Streaming und setzen Sie Workspace.EnableSLIMAvatars, um Plattformavatare als optimierte leichte SLIM-Darstellungen mit vollständiger Animationsunterstützung zu rendern, je größer der Abstand zur Kamera wird.

  • Reduzieren der Rendering-Fidelity - Setzen Sie MeshPart.RenderFidelity auf Automatic oder Performance. Dies ermöglicht es Meshes, auf weniger komplexe Alternativen zurückzugreifen, wodurch die Anzahl der Polygone reduziert werden kann, die gezeichnet werden müssen.

  • Deaktivieren Sie das Werfen von Schatten auf geeigneten Teilen und Lichtobjekten - Die Roblox-Engine verringert automatisch die Schattenqualität, wenn das Grafikqualitätsniveau des Clients abnimmt, und deaktiviert schließlich die Schatten komplett bei Qualitätsstufen unter 4. Sie können jedoch selektiv die Schattenwerfereigenschaften auf Lichtobjekten und Teilen deaktivieren, um die Leistung zu verbessern, während Schatten aktiviert sind, und die Wahrscheinlichkeit zu erhöhen, dass Schatten aktiviert bleiben. Einige Beispiele für Optimierungen, die Sie entweder zur Bearbeitungszeit oder dynamisch zur Laufzeit vornehmen können:

    • Verwenden Sie die BasePart.CastShadow-Eigenschaft, um das Werfen von Schatten auf kleinen Teilen zu deaktivieren, bei denen Schatten wahrscheinlich nicht sichtbar sind. Diese Strategie ist besonders effektiv, wenn sie auf Teile angewendet wird, die weit von der Kamera des Benutzers entfernt sind.

    • Deaktivieren Sie Schatten auf bewegenden Objekten, wenn möglich.

    • Deaktivieren Sie Light.Shadows bei Lichtinstanzen, bei denen das Objekt keine Schatten werfen muss.

    • Begrenzen Sie den Bereich und den Winkel von Lichtinstanzen.

    • Verwenden Sie weniger Lichtinstanzen.

    • Ziehen Sie in Betracht, Lichter, die außerhalb eines bestimmten Bereichs liegen oder in Innenräumen, Zimmer für Raum zu deaktivieren.

MicroProfiler-Bereiche

BereichAssoziierte Berechnung
Prepare and PerformGesamtes Rendering
Perform/Scene/computeLightingPerformLichtgitter- und Schattenaktualisierungen
LightGridCPUVoxellichtgitteraktualisierungen
ShadowMapSystemSchattierungskartierung
Perform/Scene/UpdateViewVorbereitung für Rendering und Partikelaktualisierungen
Perform/Scene/RenderViewRendering und Nachbearbeitung

Netzwerk und Replikation

Netzwerk und Replikation beschreiben den Prozess, durch den Daten zwischen dem Server und verbundenen Clients gesendet werden. Informationen werden in jedem Frame zwischen dem Client und dem Server gesendet, aber größere Datenmengen benötigen mehr Rechenzeit.

Häufige Probleme

  • Übermäßiger Verkehr über Remote - Das Senden großer Datenmengen durch RemoteEvent- oder RemoteFunction-Objekte oder deren sehr häufigen Aufruf kann zu hohen Mengen an CPU-Zeit führen, die für die Verarbeitung eingehender Pakete in jedem Frame aufgewendet wird. Häufige Fehler sind:

    • Daten in jedem Frame zu replizieren, die nicht repliziert werden müssen.
    • Daten bei Benutzereingaben ohne Mechanismus zur Drosselung zu replizieren.
    • Mehr Daten zu versenden, als nötig sind. Zum Beispiel das Senden des gesamten Inventars des Spielers, wenn er einen Artikel kauft, anstatt nur Details des gekauften Artikels.
  • Erstellung oder Entfernung komplexer Instanzbäume - Wenn eine Änderung am Datenmodell auf dem Server vorgenommen wird, wird sie an verbundene Clients repliziert. Das bedeutet, dass die Erstellung und Zerstörung großer Instanzhierarchien wie Karten zur Laufzeit sehr netzwerkintensiv sein kann.

    Ein häufiger Übeltäter hier sind die komplexen Animationsdaten, die von Animation Editor Plugins in Riggs gespeichert werden. Wenn diese nicht entfernt werden, bevor das Spiel veröffentlicht wird und das animierte Modell regelmäßig geklont wird, wird eine große Menge an Daten unnötig repliziert.

  • Serverseitiges TweenService - Wenn TweenService zum Tweenen eines Objekts genutzt wird, wird die getweente Eigenschaft in jedem Frame an jeden Client repliziert. Dies führt nicht nur dazu, dass das Tween ruckelig ist, wenn sich die Latenz der Clients ändert, sondern verursacht auch viel unnötigen Netzwerkverkehr.

Minderung

Sie können die folgenden Taktiken verwenden, um unnötige Replikationen zu reduzieren:

  • Vermeiden Sie es, große Datenmengen gleichzeitig über Remote-Events zu senden. Senden Sie stattdessen nur notwendige Daten in niedrigerer Frequenz. Zum Beispiel replizieren Sie den Zustand eines Charakters, wenn er sich ändert, anstatt in jedem Frame.
  • Teilen Sie komplexe Instanzbäume wie Karten in Stücke auf und laden Sie diese in Teilen, um die Arbeit bei der Replikation über mehrere Frames zu verteilen.
  • Bereinigen Sie Animationsmetadaten, insbesondere das Animationsverzeichnis von Riggs nach dem Importieren.
  • Begrenzen Sie unnötige Instanzreplikation, insbesondere in Fällen, in denen der Server kein Wissen über die erstellten Instanzen benötigt. Dazu gehören:
    • Visuelle Effekte wie eine Explosion oder einen magischen Zauberblitz. Der Server muss nur die Position kennen, um das Ergebnis zu bestimmen, während die Clients die visuellen Effekte lokal erstellen können.
    • Modelle für die First-Person-Ansicht.
    • Tween-Objekte auf dem Client statt auf dem Server.

MicroProfiler-Bereiche

BereichAssoziierte Berechnung
ProcessPacketsVerarbeitung eingehender Netzwerkpakete, z.B. Ereignisaufrufe und Eigenschaftsänderungen
Allocate Bandwidth and Run SendersAusgehende Ereignisse, die auf Servern relevant sind

Asset-Speicherverbrauch

Der größte Einflussmechanismus, den Ersteller zur Verbesserung der Client-Speicherauslastung aktivieren können, ist das Aktivieren von Instanz-Streaming.

Instanz-Streaming

Instanz-Streaming lädt selektiv Teile des Datenmodells, die nicht erforderlich sind, was zu deutlich reduzierten Ladezeiten führen und die Fähigkeit des Clients erhöhen kann, K crashes zu verhindern, wenn er unterSpeicherdruck steht.

Wenn Sie auf Speicherprobleme stoßen und das Instanz-Streaming deaktiviert haben, sollten Sie in Betracht ziehen, Ihr Spiel zu aktualisieren, um es zu unterstützen, insbesondere wenn Ihre 3D-Welt groß ist. Instanz-Streaming basiert auf der Distanz im 3D-Raum, sodass größere Welten natürlich mehr Nutzen daraus ziehen.

Wenn das Instanz-Streaming aktiviert ist, können Sie die Aggressivität erhöhen. Zum Beispiel könnten Sie:

  • Die Verwendung von Enum.ModelStreamingMode.Persistent wo möglich reduzieren. Möglicherweise müssen Sie Ihre Skripte aktualisieren, wenn Sie es als Maßnahme zur Kompatibilität verwenden.
  • Den Workspace.StreamingMinRadius und den Workspace.StreamingTargetRadius reduzieren.

Für weitere Informationen zu Streaming-Optionen und deren Vorteilen siehe Streaming-Eigenschaften.

Weitere häufige Probleme

  • Asset-Duplikation - Ein häufiger Fehler besteht darin, dass dasselbe Asset mehrmals hochgeladen wird, was zu unterschiedlichen Asset-IDs führt. Dies kann dazu führen, dass dieselben Inhalte mehrmals in den Speicher geladen werden.

  • Übermäßiges Asset-Volumen - Selbst wenn Assets nicht identisch sind, gibt es Fälle, in denen Gelegenheiten zur Wiederverwendung desselben Assets und zur Einsparung von Speicher versäumt werden.

  • Audio-Dateien - Audiodateien können einen überraschenden Beitrag zum Speicherverbrauch leisten, insbesondere wenn Sie alle auf einmal in den Client laden, anstatt nur das zu laden, was Sie für einen Teil des Spiels benötigen. Für Strategien siehe Ladezeiten.

  • Hochauflösende Texturen - Der Verbrauch von Grafikspeicher für eine Textur hängt nicht von der Größe der Textur auf der Festplatte ab; die Anzahl der Pixel in der Textur bestimmt den Speicherverbrauch. Zum Beispiel benötigt eine 1024x1024-Pixel-Textur viermal so viel Grafikspeicher wie eine 512x512-Textur.

    Bilder, die auf Roblox hochgeladen werden, werden in ein fixes Format konvertiert, sodass there is no memory benefit from uploading images in a color model associated with fewer bytes per pixel. Similarly, compressing images before upload or removing the alpha channel from images that don't need it can decrease image size on disk, but doesn't improve memory usage.

    As a game loads, the engine automatically starts with lower quality textures and then ramps up quality based on available device memory, distance from the camera, amount of screen-space that the texture takes up, and other factors. Even still, strategically sizing your textures can improve memory usage in your game.

Minderung

  • Laden Sie Assets nur einmal hoch - Verwenden Sie dieselbe Asset-ID über Objekte hinweg und stellen Sie sicher, dass dieselben Assets, insbesondere Meshes und Bilder, nicht separat mehrmals hochgeladen werden.

  • Suchen und beheben Sie doppelte Assets - Suchen Sie nach identischen Mesh-Teilen und Texturen, die mehrmals mit unterschiedlichen IDs hochgeladen wurden.

    • Obwohl es keine API gibt, um Ähnlichkeiten von Assets automatisch zu erkennen, können Sie alle Bild-Asset-IDs in Ihrem Platz (entweder manuell oder mit einem Skript) sammeln, sie herunterladen und mit externen Vergleichstools vergleichen.
    • Für Meshteile ist die beste Strategie, einzigartige Mesh-IDs zu nehmen und sie nach Größe zu organisieren, um manuell Duplikate zu identifizieren.
    • Anstatt separate Texturen für unterschiedliche Farben zu verwenden, laden Sie eine einzige Textur hoch und verwenden Sie die SurfaceAppearance.Color-Eigenschaft, um verschiedene Farbtöne anzuwenden.
  • Importieren Sie Assets in der Karte separat - Anstatt eine gesamte Karte auf einmal zu importieren, importieren und rekonstruieren Sie die Assets in der Karte einzeln und rekonstruieren Sie sie. Der Importer führt keine De-Duplizierung von Meshes durch. Wenn Sie also eine große Karte mit vielen einzelnen Fliesen importieren, wird jede dieser Fliesen als separates Asset importiert (auch wenn sie Duplikate sind). Dies kann im Laufe der Zeit zu Leistungs- und Speicherproblemen führen, da jedes Mesh als individuell behandelt wird und Speicher und Draw-Calls beansprucht.

  • Begrenzen Sie die Pixel von Bildern auf nicht mehr als notwendig. Es sei denn, ein Bild nimmt einen großen physischen Raum auf dem Bildschirm ein, benötigt es normalerweise maximal 512x512 Pixel. Die meisten kleineren Bilder sollten kleiner als 256x256 Pixel sein.

  • Verwenden Sie Trim-Sheets, um eine maximale Texturwiederverwendung in 3D-Karten sicherzustellen. Für Schritte und Beispiele zur Erstellung von Trim-Sheets siehe Trim-Sheets erstellen.

    Sie sollten auch in Erwägung ziehen, Sprite-Sheets zu verwenden, um viele kleinere UI-Bilder als ein einziges Bild zu laden. Sie können dann ImageLabel.ImageRectOffset und ImageLabel.ImageRectSize verwenden, um Teile des Sheets anzuzeigen.

Ladezeiten

Viele Spiele implementieren benutzerdefinierte Ladebildschirme und verwenden die Methode ContentProvider:PreloadAsync(), um Assets anzufordern, sodass Bilder, Sounds und Meshes im Hintergrund heruntergeladen werden.

Der Vorteil dieses Ansatzes besteht darin, dass Sie sicherstellen können, dass wichtige Teile Ihres Spiels vollständig geladen sind, ohne Pop-ins. Ein häufiger Fehler ist jedoch die übermäßige Nutzung dieser Methode, um mehr Assets vorzuladen, als tatsächlich benötigt werden.

Ein Beispiel für eine schlechte Praxis ist das Laden der gesamten Workspace. Während dies Werte von Textur-Pop-ins verhindern könnte, erhöht es die Ladezeiten erheblich.

Eine ähnliche Praxis ist es, ContentProvider.RequestQueueSize zu nutzen, um sicherzustellen, dass alle angeforderten Assets das Laden abgeschlossen haben. Dies bringt jedoch dasselbe Problem mit sich, nämlich erheblich längere Ladezeiten, während es auch eine unzuverlässige Methode wegen ihrer schwankenden Natur ist.

Verwenden Sie stattdessen die Methode ContentProvider:PreloadAsync() nur in notwendigen Situationen, zu denen gehören:

  • Bilder im Ladebildschirm.
  • Wichtige Bilder in Ihrem Spielmenü, wie Schaltflächenhintergründe und -symbole.
  • Wichtige Assets im Start- oder Spawnbereich.

Wenn Sie eine große Anzahl von Assets laden müssen, empfehlen wir, dass Sie eine Laden überspringen-Schaltfläche bereitstellen.

©2026 Roblox Corporation. Roblox, das Roblox-Logo und "Powering Imagination" gehören zu unseren eingetragenen und nicht eingetragenen Markenzeichen in den USA und anderen Ländern.