Diese Seite beschreibt häufige Leistungsprobleme und die besten Praktiken zur Linderung dieser Probleme.
Skriptberechnung
Kostspensive Operationen im Luau-Code dauern länger, um zu verarbeiten, und können somit die Bildrate beeinflussen.Es wird ausgeführt, es sei denn, es wird parallel ausgeführt, führt Luau-Code synchron aus und blockiert den Haupt thread, bis er eine Funktion findet, die den Thread liefert.
Gewöhnliche Probleme
Intensive Operationen an Tabellenstrukturen - Komplexe Operationen wie Serienisierung, Deserialisierung und tiefe Klonung verursachen hohe Leistungskosten, insbesondere auf großen Tabellenstrukturen.Das gilt besonders, wenn diese Operationen rekursiv sind oder sich auf die Iteration über sehr große Datenstrukturen beziehen.
Häufige Ereignisse - Das Binden teurer Operationen an Frame-basierte Ereignisse von RunService ohne die Häufigkeit zu begrenzen, bedeutet, dass diese Operationen jeden Frame wiederholt werden, was oft zu einer unnötigen Erhöhung der Berechnungszeit führt.Diese Ereignisse umfassen:
Vermeidung
- Beschwöre Code auf RunService Ereignissen sparsam, begrenze die Nutzung auf Fälle, in denen eine häufige Beschwörung unerlässlich ist (zum Beispiel, die Kamera zu aktualisieren).Du kannst den meisten anderen Code in anderen Ereignissen oder seltener in einer Schleife ausführen.
- Teile große oder teure Aufgaben mit task.wait(), um die Arbeit auf mehrere Rahmen zu verteilen.
- Identifizieren und optimieren Sie unnötig teure Operationen und verwenden Sie Multithreading für kostenintensive Aufgaben, die nicht auf das Datenmodell zugreifen müssen.
- Bestimmte serverseitige Skripte können von nativer Codegeneration profitieren, einer einfachen Flagge, die ein Skript in Maschinencode kompiliert, anstatt in Bytecode.
MicroProfiler-Umgebungen
Bereich | Verknüpfte Berechnung |
LaufenService.PreRender | Code wird auf dem PreRender-Ereignis ausgeführt |
LaufService.PreSimulation | Code wird beim Stepped-Ereignis ausgeführt |
LaufService.PostSimulation | Code wird beim Heartbeat-Ereignis ausgeführt |
RunService.Herzschlag | Code wird beim Heartbeat-Ereignis ausgeführt |
Für weitere Informationen zum Debuggen von Skripten mit dem MicroProfiler, siehe die debug Bibliothek, die Funktionen für das Markieren spezifischen Codes und die weitere Erhöhung der Spezifität enthält, wie debug.profilebegin und debug.profileend.Viele Roblox-API-Methoden, die von Skripten aufgerufen werden, haben auch eigene MicroProfiler-Tags, die nützliche Signale liefern können.
Skriptspeicherverwendung
Speicherlecks können auftreten, wenn du Skripte schreibst, die Speicher verbrauchen, den der Garbage-Collector nicht richtig freigeben kann, wenn er nicht mehr in Verwendung ist.Lecks sind speziell auf dem Server verbreitet, weil sie kontinuierlich für viele Tage online sein können, während eine Client-Sitzung viel kürzer ist.
Die folgenden Speicherwerte in der Entwickler-Konsole können ein Problem anzeigen, das weitere Untersuchungen erfordert:
- LuaHeap - Hohe oder wachsende Verbrauch zeigt auf eine Speicherleck.
- InstanceCount - Konsistent wachsende Anzahl von Instanzen deutet darauf hin, dass sich keine Referenzen auf einige Instanzen in deinem Code nicht sammeln lassen.
- PlaceScriptMemory - Stellt ein Skript durch Skript-Aufschlüsselung der Speicherverwendung bereit.
Gewöhnliche Probleme
Verbindungen offen lassen - Die Engine sammelt nie Garbage-Events, die mit einer Instanz verbunden sind, und alle Werte, die innerhalb der verbundenen Rückrufe referenziert werden.Daher sind aktive Verbindungen von Ereignissen und Code innerhalb der verbundenen Instanzen, verbundenen Funktionen und referenzierten Werten für den Speicher-Garbage-Sammler außerhalb des Bereichs, auch nachdem die Ereignisse abgefeuert wurden.
Obwohl Ereignisse getrennt sind, wenn die zugehörige Instanz zerstört wird, ist ein häufiger Fehler die Annahme, dass dies für Player Objekte gilt.Nachdem ein Benutzer ein Erlebnis verlässt, zerstört die Engine nicht automatisch sein repräsentatives Player Objekt und Charaktermodell, so dass Verbindungen zum Player Objekt und Instanzen unter dem Charaktermodell, wie Player.CharacterAdded, weiterhin Speicher verbrauchen, wenn du sie nicht in deinen Skripten trennst.Dies kann zu sehr signifikanten Speicherlecks auf dem Server im Laufe der Zeit führen, wenn sich Hunderte von Benutzern der Erfahrung anschließen und sie verlassen.
Tabellen - Das Einfügen von Objekten in Tabellen, aber sie nicht zu entfernen, wenn sie nicht mehr benötigt werden, verursacht unnötigen Speicherverbrauch, insbesondere für Tabellen, die Benutzerdaten verfolgen, wenn sie beitreten.Zum Beispiel erstellt das folgende Codebeispiel eine Tabelle, die jedes Mal, wenn ein Benutzer beitritt, Benutzerinformationen hinzufügt:
Beispiellocal playerInfo = {}Players.PlayerAdded:Connect(function(player)playerInfo[player] = {} -- etwas infoend)Wenn du diese Einträge nicht entfernst, wenn sie nicht mehr benötigt werden, wächst die Tabelle weiter und verbraucht mehr Speicher, wenn mehr Benutzer der Sitzung beitreten.Jeder Code, der über diese Tabelle iteriert, wird auch teurer, je größer die Tabelle wird.
Vermeidung
Um alle verwendeten Werte zu löschen, um Leckagen zu verhindern:
Trennen Sie alle Verbindungen - Gehen Sie durch Ihre Codebasis, um sicherzustellen, dass jede Verbindung über einen der folgenden Pfade gereinigt wird:
- Trennen manuell mit der Funktion Disconnect() .
- Zerstörung der Instanz, zu der das Ereignis gehört, mit der Destroy()-Funktion.
- Zerstörung des Skript-Objekts, auf das die Verbindung zurückverfolgt wird.
Entferne Spielerobjekte und -charaktere nach dem Verlassen - Implementiere Code, um sicherzustellen, dass keine Verbindungen nach dem Verlassen eines Benutzers bestehen bleiben, wie im folgenden Beispiel:
BeispielPlayers.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
Übertriebene Physiksimulation kann eine wichtige Ursache für die Zunahme der Berechnungszeit pro Frame auf dem Server und dem Client sein.
Gewöhnliche Probleme
Übertriebene Physik-Zeitstufenfrequenz - Standardmäßig ist das Schrittverhalten im adaptiven Modus, wo Physikschritte entweder mit 60 Hz, 120 Hz oder 240 Hz ausgeführt werden, je nach der Komplexität des physikalischen Mechanismus.
Es ist auch ein fixierter Modus mit verbesserter Genauigkeit der Physik verfügbar, der alle Physik-Assemblys zwingt, bei 240 Hz (viermal pro Frame) zu treten.Dies führt zu deutlich mehr Berechnung pro Frame.
Exzessive Anzahl der Komplexität von simulierten Objekten - Je mehr 3D-Montagen simuliert werden, desto länger dauern die physikalischen Berechnungen pro Frame.Oft werden Erlebnisse Objekte haben, die simuliert werden, die nicht sein müssen oder Mechanismen haben, die mehr Einschränkungen und Gelenke haben, als sie brauchen.
Übermäßig genaue Kollisionserkennung - Netzwerkteile haben ein CollisionFidelity Eigenschaft zum Erkennen von Kollisionen, die eine Vielzahl von Modi mit unterschiedlichen Leistungseffekten bietet.Der präzise Kollisionserkennungsmodus für Netzwerkteile hat die teuerste Leistungskosten und dauert länger, um zu berechnen.
Vermeidung
Ankerteile, die keine Simulation erfordern - Anker alle Teile, die nicht von der Physik gesteuert werden müssen, wie z. B. für statische NPCs.
Verwende adaptive Physik-Schritte - Adaptive Schritte passen die Rate der Physik-Berechnungen für physikalische Mechanismen dynamisch an, so dass Physik-Updates in einigen Fällen weniger häufig durchgeführt werden können.
Reduzieren Sie die Komplexität des Mechanismus * Wo immer möglich, minimiere die Anzahl der physikalischen Einschränkungen oder Verbindungen in einer Montagemaschine.
- Reduziere die Menge der Selbstkollision innerhalb eines Mechanismus, z. B. durch die Anwendung von Grenzen oder No-Collision-Einschränkungen auf Ragdoll-Gliedmaßen, um sie vor dem Zusammenstoßen zu schützen.
Reduzieren Sie die Verwendung genauer Kollisionsgenauigkeit für Meshes * Für kleine oder nicht interaktionsfähige Objekte, in denen Benutzer selten den Unterschied bemerken würden, verwende Box-Treue.
Für kleinere bis mittlere Objekte verwende Box- oder Hulltreue, abhängig von der Form.
Für große und sehr komplexe Objekte baue bei Bedarf benutzerdefinierte Kollisionen mit unsichtbaren Teilen aus.
Für Objekte, die keine Kollisionen erfordern, deaktiviere Kollisionen und verwende Box- oder Hulltreue, da die Kollisionsgeometrie immer noch in der Speicher verwahrt wird.
Du kannst die Kollisionsgeometrie für Fehlerbehebungszwecke in Studio rendern, indem du auf Kollisionsgenauigkeit vom Visualisierungsoptionen-Widget in der oberen rechten Ecke des 3D-Ansichtsfensters umschaltest.
Alternativ kannst du den CollisionFidelity=PreciseConvexDecomposition Filter auf den Explorer anwenden, der eine Zählung aller Meshelemente mit der genauen Genauigkeit anzeigt und es dir ermöglicht, sie leicht auszuwählen.
Für einen ausführlichen Überblick darüber, wie man eine Kollisionsgenauigkeitsoption auswählt, die die Präzisions- und Leistungsanforderungen ausgleicht, siehe Setze physikalische und Render参数.
MicroProfiler-Umgebungen
Bereich | Verknüpfte Berechnung |
physicsStepped | Gesamte Physikberechnung |
Weltschritt | Diskrete physikalische Schritte werden jeden Frame unternommen |
Physikspeicherverbrauch
Die Bewegung von Physik und Kollisionserkennung verbraucht Speicher.Mesh-Teile haben ein CollisionFidelity-Eigenschaft, die die Art und Weise bestimmt, mit der die Kollisionsgrenzen des Meshes bewertet werden.
Gewöhnliches Problem
Die Standard- und präzisen Kollisionserkennungsmodi verbrauchen deutlich mehr Speicher als die beiden anderen Modi mit niedrigerer Kollisionsgenauigkeit.
Wenn du hohe Niveaus des Speicherverbrauchs unter PhysicsParts siehst, musst du möglicherweise untersuchen, die Kollisionsgenauigkeit von Objekten in deiner Erfahrung zu reduzieren.
Wie man sich abmildert
Um die für die Kollisionssicherheit verwendete Speicher zu reduzieren:
- Für Teile, die keine Kollisionen benötigen, deaktiviere ihre Kollisionen, indem du BasePart.CanCollide, BasePart.CanTouch und BasePart.CanQuery auf false setzt.
- Reduziere die Treffergenauigkeit von Kollisionen mit der Einstellung CollisionFidelity.Box hat den niedrigsten Speicheraufwand, und Default und Precise sind im Allgemeinen teurer.
- Es ist in der Regel sicher, die Kollisionsfidelität eines kleinen angeankerten Teils auf Box zu setzen.
- Für sehr komplexe große Meshes möchten Sie vielleicht Ihr eigenes Kollisionsmesch aus kleineren Objekten mit Kistenkollisionsgenauigkeit bauen.
Menschenoiden
Humanoid ist eine Klasse, die eine Vielzahl von Funktionen für Spieler- und Nicht-Spielercharaktere (NPCs) bietet.Obwohl mächtig, kommt ein Humanoid mit einer erheblichen Berechnungskosten.
Gewöhnliche Probleme
- Alle HumanoidStateTypes auf NPCs aktiviert lassen - Es gibt eine Leistungskosten, wenn bestimmte HumanoidStateTypes aktiviert bleiben.Deaktiviere alles, was für deine NPCs nicht benötigt wird.Zum Beispiel ist es, wenn dein NPC keine Leitern klettern wird, sicher, den Zustand Climbing zu deaktivieren.
- Instanziieren, modifizieren und respawnen von Modellen mit Humanoiden häufig * Dies kann intensiv für die Verarbeitung der Engine sein, insbesondere, wenn diese Modelle mehrschichtige Kleidung verwenden.Dies kann auch in Erlebnissen problematisch sein, in denen Avatare häufig respawnen.
- Im Mikroprofilierer werden lange updateInvalidedFastClusters -Tags (über 4 ms) oft zu einem Signal, dass die Avatar-Instanzierung/Modifikation übermäßige Unzulänglichkeiten auslöst.
- Verwendung von Humanoiden in Fällen, in denen sie nicht erforderlich sind - Statische NPCs, die sich im Allgemeinen nicht bewegen, haben keine Notwendigkeit für die Humanoid -Klasse.
- Spielen von Animationen auf einer großen Anzahl von NPCs vom Server - NPC-Animationen, die auf dem Server ausgeführt werden, müssen auf dem Server simuliert und auf den Client repliziert werden.Dies kann unnötige Aufwendungen sein.
Vermeidung
- Spiele NPC-Animationen auf dem Client - In Erlebnissen mit einer großen Anzahl von NPCs, erwäge die Erstellung der Animator auf dem Client und die Ausführung der Animationen lokal.Dies reduziert die Belastung auf dem Server und die Notwendigkeit unnötiger Replikation.Es ermöglicht auch zusätzliche Optimierungen (z. B. nur Animationen für NPCs abspielen, die sich in der Nähe des Charakters befinden).
- Verwende leistungsfreundliche Alternativen zu Humanoids - NPC-Modelle müssen nicht unbedingt ein menschliches Objekt enthalten.
- Für statische NPCs verwende ein einfaches AnimationController, da sie sich nicht bewegen müssen, aber nur Animationen spielen müssen.
- Für bewegliche NPCs, erwäge die Implementierung eines eigenen Bewegungscontrollers und die Verwendung eines AnimationController für Animationen, abhängig von der Komplexität deiner NPCs.
- Deaktiviere unbenutzte menschliche Zustände - Verwende Humanoid:SetStateEnabled(), um nur notwendige Zustände für jeden Menschenoid zu aktivieren.
- Pool-NPC-Modelle mit häufigem Respawnen - Statt einen NPC vollständig zu zerstören, schicke den NPC in einen Pool inaktiver NPCs.Auf diese Weise, wenn ein neuer NPC zum Respawnen benötigt wird, kannst du einfach einen der NPCs aus dem Pool reaktivieren.Dieser Prozess heißt Pooling, was die Anzahl der Zeiten minimiert, in denen Zeichen instanziiert werden müssen.
- Spawne nur NPCs, wenn Benutzer in der Nähe sind - Spawne keine NPCs, wenn Benutzer nicht in Reichweite sind, und vernichte sie, wenn Benutzer ihre Reichweite verlassen.
- Vermeiden Sie Änderungen an der Avatar-Hierarchie, nachdem sie instanziiert wurde - Bestimmte Änderungen an einer Avatar-Hierarchie haben erhebliche Leistungseinschränkungen.Einige Optimierungen sind verfügbar:
- Für benutzerdefinierte prozedurale Animationen aktualisieren Sie nicht die Eigenschaften JointInstance.C0 und JointInstance.C1. Stattdessen aktualisieren Sie die Eigenschaft Motor6D.Transform.
- Wenn du jedes BasePart Objekt an den Avatar anfügen musst, tue dies außerhalb der Hierarchie des Avatars Model.
MicroProfiler-Umgebungen
Bereich | Verknüpfte Berechnung |
stepHumanoid | Humanoide Steuerung und Physik |
Schrittanimation | Humanoide und Animator-Animation |
aktualisierenUpdateFastClustersUnzulässig | Verknüpft mit der Instanzierung oder Änderung eines Avatars |
Renderung
Ein erheblicher Teil der Zeit, die der Client pro Frame verbringt, ist mit der Rendering der Szene im aktuellen Frame verbunden.Der Server macht keine Rendering, also ist dieser Abschnitt exklusiv für den Client.
Ziehaufrufe
Ein Draw-Call ist eine Reihe von Anweisungen von der Engine an die GPU, etwas zu rendern.Ziehaufrufe haben erhebliche Overhead.Im Allgemeinen werden je weniger Ziehaufrufe pro Frame ausgeführt, desto weniger wird zur Berechnung einer Frames Zeit aufgewendet.
Du kannst sehen, wie viele Zeichnungsanrufe derzeit mit dem Render Stats > Timing Artikel in Studio auftreten.Du kannst Render-Statistiken anzeigen im Client durch Drücken von anzeigen .
Je mehr Objekte in deiner Szene in einem bestimmten Frame gezeichnet werden müssen, desto mehr GPU-Aufrufe werden getätigt.Die Roblox-Engine nutzt jedoch einen Prozess namens Instanzierung, um identische Meshes mit den gleichen Texturmerkmalen in eine einzige Draw-Aufruf zusammenzuführen.Genau genommen werden mehrere Meshes mit derselben MeshId in einer einzigen Zeichnungsanruf behandelt, wenn:
- SurfaceAppearances sind identisch. TextureIDs sind identisch, wenn SurfaceAppearance nicht existiert.
- Materialien sind identisch, wenn sowohl SurfaceAppearance als auch MeshPart.TextureID nicht existieren.
Andere häufige Probleme
Übertriebene Objektdichte - Wenn eine große Anzahl von Objekten mit hoher Dichte konzentriert ist, erfordert die Rendering dieses Bereichs der Szene mehr Zeichnungsaufrufe.Wenn du deine Bildrate findest, wenn du auf einen bestimmten Teil der Karte schaust, kann dies ein gutes Signal sein, dass die Objektdichte in diesem Bereich zu hoch ist.
Objekte wie Bilder, Texturen und Partikel werden nicht gut gebündelt und führen zu zusätzlichen Zeichnungsaufrufen.Achten Sie besonders auf diese Objektarten in einer Szene.Insbesondere können Eigenschaftsänderungen auf ParticleEmitters einen dramatischen Einfluss auf die Leistung haben.
Versäumte Instanzierungsgelegenheiten - Oft wird eine Szene die gleiche Mesh-ID mehrmals wiederholen, aber jede Kopie des Meshs hat unterschiedliche Mesh- oder Textur-Asset-IDs.Dies verhindert Instanziierung und kann zu unnötigen Draw-Aufrufen führen.
Eine häufige Ursache für dieses Problem ist, wenn eine ganze Szene auf einmal importiert wird, anstatt einzelne Assets in Roblox importiert und dann nach dem Import dupliziert werden, um die Szene zusammenzustellen.
Sogar ein einfaches Skript wie dieses kann Ihnen helfen, Netzwerkteile mit demselben Namen zu identifizieren, die unterschiedliche Netzwerk-IDs verwenden:
local Workspace = game:GetService("Workspace")for _, descendant in Workspace:GetDescendants() doif descendant:IsA("MeshPart") thenprint(descendant.Name .. ", " .. descendant.MeshId)endendDie Ausgabe (mit Stapellinien aktiviert ) könnte so aussehen.Wiederholte Zeilen zeigen die Wiederverwendung desselben Meshes an, was gut ist.Einzigartige Zeilen sind nicht unbedingt schlecht, aber abhängig von deinem Namensschema könnten sie doppelte Meshes in deiner Erfahrung anzeigen:
LargeRock, rbxassetid://106420009602747 (x144) -- goodLargeRock, rbxassetid://120109824668127LargeRock, rbxassetid://134460273008628LargeRock, rbxassetid://139288987285823LargeRock, rbxassetid://71302144984955LargeRock, rbxassetid://90621205713698LargeRock, rbxassetid://113160939160788LargeRock, rbxassetid://135944592365226 -- all possible duplicatesÜbertriebene Objektkomplexität - Obwohl es nicht so wichtig ist wie die Anzahl der Ziehaufrufe, beeinflusst die Anzahl der Dreieck in einer Szene, wie lange ein Frame zum Rendern braucht.Szenen mit einer sehr großen Anzahl sehr komplexer Meshes sind ein häufiges Problem, ebenso wie Szenen mit der Eigenschaft MeshPart.RenderFidelity mit zu vielen Meshes auf Enum.RenderFidelity.Precise gesetzt.
Übertriebene Schattenwurf - Das Handling von Schatten ist ein teurer Prozess, und Karten, die eine hohe Anzahl und Dichte von Lichtobjekten enthalten, die Schatten werfen (oder eine hohe Anzahl und Dichte kleiner Teile, die von Schatten beeinflusst werden), sind wahrscheinlich mit Leistungsproblemen verbunden.
Hohe Transparenz überschreiben - Das Platzieren von Objekten mit partieller Transparenz in der Nähe einander zwingt die Engine, die überlappenden Pixel mehrmals zu rendern, was die Leistung schädigen kann.Für weitere Informationen zur Identifizierung und Behebung dieses Problems siehe Layer-Transparenzen löschen.
Vermeidung
- Instanzierung identischer Meshes und Reduzierung der Menge einzigartiger Meshes - Wenn Sie sicherstellen, dass alle identischen Meshes die gleichen Unternehmens-IDs haben, kann die Engine sie erkennen und in einer einzigen Draw-Anruf rendern.Stellen Sie sicher, dass Sie jedes Netz nur einmal in einer Karte hochladen und dann in Studio duplizieren, um sie wiederzuverwenden, anstatt große Karten als Ganzes zu importieren, was dazu führen kann, dass identische Netze separate Inhalts-IDs haben und vom Motor als einzigartige Assets erkannt werden.Pakete sind ein hilfreicher Mechanismus für die Wiederverwendung von Objekten.
- Auslese - Auslese beschreibt den Prozess der Eliminierung von Ziehaufrufen für Objekte, die nicht in den endgültigen gerenderten Rahmen einfließen.Standardmäßig überspringt die Engine Ziehaufrufe für Objekte außerhalb des Sichtfelds der Kamera (Frustum-Auslese), aber nicht Ziehaufrufe für Objekte, die durch andere Objekte aus der Sicht ausgeschlossen sind (Ausschluss-Auslese).Wenn deine Szene eine große Anzahl von Zeichnungsanrufen hat, erwäge, deine eigene zusätzliche Auswahl zur Laufzeit dynamisch für jeden Frame umzusetzen, z. B. die Anwendung der folgenden häufigen Strategien:
- Für Innenumgebungen implementiere ein Zimmer- oder Portal-System, das Objekte versteckt, die derzeit von keinen Benutzern beansprucht werden.
- Reduzierung der Rendertreue - Stellen Sie die Rendertreue auf Automatisch oder Leistung ein.Dies ermöglicht Meshes, zu weniger komplexen Alternativen zurückzufallen, die die Anzahl der zu zeichnenden Polygone reduzieren können.
- Deaktivierung von Schattenwurf auf geeignete Teile und Lichtobjekte - Die Komplexität der Schatten in einer Szene kann durch die selektive Deaktivierung von Schattenwurf-Eigenschaften auf Lichtobjekten und Teilen reduziert werden.Dies kann zur Bearbeitungszeit oder dynamisch zur Laufzeit erfolgen.Einige Beispiele sind:
Verwende die Eigenschaft BasePart.CastShadow, um Schattenwurf auf kleinen Teilen zu deaktivieren, auf denen es unwahrscheinlich ist, dass Schatten sichtbar sind.Dies kann besonders effektiv sein, wenn es nur auf Teile angewendet wird, die weit von der Kamera des Benutzers entfernt sind.
Deaktiviere Schatten bei bewegenden Objekten, wenn möglich.
Deaktiviere Light.Shadows auf leichten Instanzen, wo das Objekt keine Schatten werfen muss.
Begrenze die Reichweite und den Winkel der Lichtinstanzen.
Verwende weniger leichte Instanzen.
Betrachte die Deaktivierung von Lichtern, die sich außerhalb einer bestimmten Reichweite oder auf einer Raum-zu-Raum-Basis für Innenräume befinden.
MicroProfiler-Umgebungen
Bereich | Verknüpfte Berechnung |
Vorbereiten und durchführen | Gesamte Rendering |
Ausführen/Szene/ computeLightingPerform | Lichtnetz- und Schattenaktualisierungen |
Leichte Gitter-CPU | Aktualisierungen der Voxel-Lichtgitter |
Schattenkarte-System | Schattenmapping |
Ausführen/Szene/UpdateView | Vorbereitung für Rendering und Partikel-Updates |
Ausführen/Szene/Renderansicht | Renderung und Nachbearbeitung |
Netzwerk und Replikation
Netzwerk- und Replikationsbeschreibung beschreibt den Prozess, durch den Daten zwischen dem Server und den verbundenen Clients gesendet werden.Informationen werden zwischen Client und Server jedem Frame gesendet, aber größere Mengen an Informationen erfordern mehr Berechnungszeit.
Gewöhnliche Probleme
Übertriebener Fernverkehr - Das Senden einer großen Menge an Daten durch RemoteEvent oder RemoteFunction Objekte oder das häufige Aufrufen von ihnen kann dazu führen, dass eine große Menge an CPU-Zeit für die Verarbeitung einghender Pakete pro Frame ausgegeben wird.Gewöhnliche Fehler umfassen:
- Daten replizieren, jeden Frame, der nicht repliziert werden muss.
- Daten replizieren auf Benutzereingabe ohne irgendeinen Mechanismus, um sie zu beschränken.
- Versenden von mehr Daten als erforderlich.Zum Beispiel das Senden des gesamten Inventars des Spielers, wenn er ein 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 auf verbundene Clients repliziert.Das bedeutet, dass die Erstellung und Zerstörung großer Instanz-Hierarchien wie Karten zur Laufzeit sehr netzwerkintensiv sein kann.
Ein häufiger Schuldiger hier sind die komplexen Animationsdaten, die von Animations-Editor-Plugins in Rigs gespeichert werden.Wenn diese nicht vor der Veröffentlichung des Spiels entfernt werden und das animierte Modell regelmäßig geklont wird, wird eine große Menge an Daten unnötig repliziert.
Server-seitiger TweenService - Wenn TweenService verwendet wird, um einen Objektserver seitlich zu durchschalten, wird die durchgeschaltete Eigenschaft in jedem Frame an jeden Client repliziert.Dies führt nicht nur dazu, dass der Teenager nervös wird, da die Latenz der Clients schwankt, sondern verursacht auch viel unnötigen Netzwerkverkehr.
Vermeidung
Du kannst die folgenden Taktiken einsetzen, um unnötige Replikation zu reduzieren:
- Vermeiden Sie das Senden großer Mengen an Daten auf einmal durch Remote-Ereignisse .Senden Sie stattdessen nur notwendige Daten mit einer niedrigeren Frequenz.Zum Beispiel, für den Zustand eines Charakters, reproduziere ihn, wenn er sich ändert, anstatt jedes Frame.
- Füge komplexe Instanzbaumstrukturen zusammen wie Karten und lade sie in Stücke auf, um die Arbeit zu verteilen, die diese über mehrere Frames repliziert.
- Löschen von Animationsmetadaten , insbesondere der Animationsdirektory von Rigs, nach dem Importieren.
- Beschränke die unnötige Instanzreplikation , insbesondere in Fällen, in denen der Server nicht wissen muss, dass die erstellten Instanzen existieren.Dazu gehören:
- Visuelle Effekte wie eine Explosion oder eine magische Zauberexplosion.Der Server muss nur die Lokalität kennen, um das Ergebnis zu bestimmen, während die Clients visuelle Inhalte lokal erstellen können.
- First-Person-Artikelansichtsmodelle.
- Teenage-Objekte auf dem Client anstatt auf dem Server.
MicroProfiler-Umgebungen
Bereich | Verknüpfte Berechnung |
Prozesspakete | Verarbeitung von eingehenden Netzwerkpaketen, wie Ereignisaufrufen und Eigenschaftsänderungen |
Bandbreite zuweisen und Sender ausführen | Ausgangsereignisse relevant auf Servern |
Asset-Speicherverwendung
Der höchste Auswirkungsmechanismus, den Ersteller zur Verbesserung der Client-Speicherverwendung zur Verfügung haben, besteht darin, Instanzstreaming zu aktivieren.
Instanz-Streaming
Instance-Streaming lässt Teile des Datenmodells selektiv laden, die nicht benötigt werden, was zu einer deutlich reduzierten Ladezeit führt und die Fähigkeit des Clients erhöht, Kollisionen zu verhindern, wenn er unter Druck kommt.
Wenn Sie Speicherprobleme auftreten und Instanzstreaming deaktiviert ist, erwägen Sie, Ihr Erlebnis zu aktualisieren, um es zu unterstützen, insbesondere wenn Ihre 3D-Welt groß ist.Instance-Streaming basiert auf der Entfernung im 3D-Raum, sodass größere Welten natürlich davon profitieren.
Wenn Instanz Streaming aktiviert ist, kannst du die Aggressivität erhöhen. Zum Beispiel:
- Reduzierung der Verwendung der dauerhaften StreamingIntegrity .
- Reduzierung des Streamingradius .
Für weitere Informationen zu Streaming-Optionen und ihren Vorteilen siehe Streaming-Eigenschaften.
Andere häufige Probleme
- Asset-Dopplung - Ein häufiger Fehler besteht darin, dasselbe Asset mehrmals hochgeladen wird, was zu unterschiedlichen Asset-IDs führt.Dies kann dazu führen, dass derselbe Inhalt mehrmals in den Speicher geladen wird.
- Übertriebene Asset-Volumen - Selbst wenn die Assets nicht identisch sind, gibt es Fälle, in denen Gelegenheiten verpasst werden, dasselbe Asset wiederzuverwenden und Speicher zu sparen.
- Audiodateien - Audiodateien können ein überraschender Beitrag zur Speicherverwendung sein, insbesondere wenn Sie sie alle auf einmal in den Client laden, anstatt nur das zu laden, was Sie für einen Teil der Erfahrung benötigen.Für Strategien siehe Ladezeiten.
- Hochauflösende Texturen - Der Grafikspeicherverbrauch für eine Textur ist nicht mit der Größe der Textur auf der Festplatte verbunden, sondern vielmehr mit der Anzahl der Pixel in der Textur.
- Zum Beispiel verbraucht eine 1024x1024-Pixel-Texture viermal mehr Grafikspeicher als eine 512x512-Texture.
- Bilder, die auf Roblox hochgeladen werden, werden in ein festes Format transkodiert, so dass es keinen Speichervorteil gibt, Bilder in einem Farbmodell mit weniger Bytes pro Pixel hochzuladen.Ebenso kann das Komprimieren von Bildern vor dem Hochladen oder das Entfernen des Alphakanals von Bildern, die es nicht benötigen, die Bildgröße auf der Festplatte verringern, aber entweder verbessert es sich nicht oder verbessert es nur minimal den Speicherverbrauch.Obwohl die Engine die Texturauflösung auf einigen Geräten automatisch herunterskaliert, hängt das Ausmaß der Herunterskalierung von den Gerätecharakteristika ab, und eine übermäßige Texturauflösung kann immer noch Probleme verursachen.
- Du kannst die Grafikspeicherverbrauch für eine bestimmte Textur identifizieren, indem du die Grafiktextur -Kategorie in der Entwickler-Konsole erweiterst.
Vermeidung
Lade nur einmal Assets hoch - Wiederverwende die gleiche Asset-ID über Objekte und stelle sicher, dass derselbe Asset, insbesondere Meshes und Bilder, nicht mehrfach separat hochgeladen werden.
Finden und beheben von doppelten Assets - Suche nach identischen Mesh-Teilen und Texturen, die mit verschiedenen IDs mehrfach hochgeladen werden.
- Obwohl es keine API gibt, die Ähnlichkeiten von Assets automatisch erkennt, kannst du alle Bild-Asset-IDs in deinem Platz sammeln (manuell oder mit einem Skript), herunterladen und vergleichen, indem du externe Vergleichswerkzeuge verwendest.
- Für Mesh-Teile ist die beste Strategie, einzigartige Mesh-IDs zu nehmen und sie nach Größe zu organisieren, um Duplikate manuell zu identifizieren.
- Anstatt separate Texturen für verschiedene Farben zu verwenden, lade eine einzige Textur hoch und verwende die Eigenschaft SurfaceAppearance.Color, um verschiedene Tönungen darauf anzuwenden.
Importiere Ressourcen in der Karte separat - Statt eine gesamte Karte auf einmal zu importieren, importiere und konstruiere Ressourcen in der Karte einzeln und konstruiere sie neu.Der 3D-Importierer führt keine De-Duplikation von Meshes durch, also wenn du eine große Karte mit vielen separaten Bodenplatten importieren würdest, würde jede dieser Platten als separates Asset importiert werden (auch wenn sie dupliziert sind).Dies kann zu Leistungs- und Speicherproblemen auf der Linie führen, da jedes Mesh als einzeln behandelt wird und Speicher und Anrufe aufnimmt.
Beschränke die Pixel von Bildern auf nicht mehr als die notwendige Menge.Es sei denn, ein Bild nimmt einen großen Teil des physischen Raums auf dem Bildschirm ein, es benötigt in der Regel höchstens 512x512 Pixel.Die meisten kleineren Bilder sollten kleiner als 256x256 Pixel sein.
Verwende Schneideblätter , um maximale Texturwiederverwendung in 3D-Karten zu gewährleisten.Für Schritte und Beispiele, wie man Trim-Blätter erstellt, siehe Trim-Blätter erstellen.
Du kannst auch in Betracht ziehen, Sprite-Blätter zu verwenden, um viele kleinere UI-Bilder als ein einzelnes Bild zu laden.Du kannst dann ImageLabel.ImageRectOffset und ImageLabel.ImageRectSize verwenden, um Teile der Seite anzuzeigen.
Ladezeiten
Viele Erlebnisse implementieren benutzerdefinierte Ladebildschirme und verwenden die ContentProvider:PreloadAsync()-Methode, um Assets anzufordern, so dass Bilder, Sounds und Meshes im Hintergrund heruntergeladen werden.
Der Vorteil dieser Herangehensweise ist, dass Sie sicherstellen können, dass wichtige Teile Ihrer Erfahrung ohne Pop-in vollständig geladen sind.Allerdings ist ein häufiger Fehler die übermäßige Nutzung dieser Methode, um mehr Assets vorzuladen, als tatsächlich erforderlich sind.
Ein Beispiel für eine schlechte Praxis ist das Laden der gesamten Workspace. Während dies das Auftauchen von Texturen verhindern kann, erhöht es die Ladezeit erheblich.
Stattdessen verwende nur ContentProvider:PreloadAsync() in notwendigen Situationen, die umfassen:
- Bilder auf dem Ladebildschirm.
- Wichtige Bilder in deinem Erlebnismenü, wie zum Beispiel Knopf-Hintergründe und Ikonen.
- Wichtige Assets im Start- oder Spawn-Bereich.
Wenn Sie eine große Anzahl von Assets laden müssen, empfehlen wir Ihnen, eine Laden überspringen Schaltfläche bereitzustellen.