
Dies ist der fünfte Teil einer Reihe von Artikeln, die Optimierungstipps für Ihre Unity-Projekte erläutern. Verwenden Sie sie als Leitfaden, um mit weniger Ressourcen bei höheren Bildraten zu arbeiten. Nachdem Sie diese Best Practices ausprobiert haben, sollten Sie sich die anderen Seiten der Reihe ansehen:
Physik kann komplexes Gameplay erzeugen, aber das hat seinen Preis in der Leistung. Sobald Sie diese Kosten kennen, können Sie die Simulation anpassen, um sie angemessen zu verwalten. Verwenden Sie diese Tipps, um innerhalb Ihrer Zielbildrate zu bleiben und eine flüssige Wiedergabe mit Unitys integrierter Physik (NVIDIA PhysX) zu erstellen.
Sehen Sie sich unsere neuesten Optimierungsleitfäden für Unity 6-Entwickler und -Künstler an:
Meshes, die in der Physik verwendet werden, durchlaufen einen Prozess namens Kochen. Dies bereitet das Mesh vor, damit es mit physikalischen Abfragen wie Raycasts, Kontakten usw. arbeiten kann.
Ein MeshCollider hat mehrere KochenOptionen, um Ihnen zu helfen, das Mesh für die Physik zu validieren. Wenn Sie sicher sind, dass Ihr Mesh diese Überprüfungen nicht benötigt, können Sie sie deaktivieren, um Ihre Kochzeit zu verkürzen.
In den KochenOptionen für jeden MeshCollider deaktivieren Sie einfach EnableMeshCleaning, WeldColocatedVertices und CookForFasterSimulation. Diese Optionen sind wertvoll für prozedural generierte Meshes zur Laufzeit, können jedoch deaktiviert werden, wenn Ihre Meshes bereits die richtigen Dreiecke haben.
Wenn Sie auch PC anvisieren, stellen Sie sicher, dass Sie Use Fast Midphase aktiviert lassen. Dies wechselt zu einem schnelleren Algorithmus von PhysX 4.1 während der Mittelphase der Simulation (was hilft, eine kleine Menge potenziell sich schneidender Dreiecke für physikalische Abfragen einzugrenzen).
Erfahren Sie mehr in der KochenOptionen-Dokumentation.

Wenn Sie Meshes prozedural während des Spiels generieren, können Sie zur Laufzeit einen Mesh Collider erstellen. Das Hinzufügen einer MeshCollider-Komponente direkt zum Mesh kocht/bäckt jedoch die Physik im Haupt-Thread. Dies kann erhebliche CPU-Zeit verbrauchen.
Verwenden Sie Physics.BakeMesh, um ein Mesh für die Verwendung mit einem MeshCollider vorzubereiten und die gebackenen Daten mit dem Mesh selbst zu speichern. Ein neuer MeshCollider, der auf dieses Mesh verweist, verwendet diese vorgebackenen Daten erneut (anstatt das Mesh erneut zu backen). Dies kann helfen, die Ladezeit der Szene oder die Instanziierungszeit später zu reduzieren.
Um die Leistung zu optimieren, können Sie das Mesh-Cooking mit dem C#-Job-System auf einen anderen Thread auslagern.
Siehe dieses Beispiel für Details, wie man Meshes über mehrere Threads backt.

Überprüfen Sie in den Player Einstellungen, ob Prebake Collision Meshes wann immer möglich aktiviert ist. Wir empfehlen auch, die Einrichtung der Kollisionsmatrix zu überprüfen, um sicherzustellen, dass die Spieler- und Spielmechanikobjekte in den richtigen Ebenen sind.
Das Entfernen von Rückrufen von Triggern für unnötige Ebenen kann ein großer Gewinn sein, also versuchen Sie, Ihre Ebenen-Kollisionsmatrix zu vereinfachen. Sie können Ihre Physik-Einstellungen über Projekt-Einstellungen > Physik bearbeiten.
Erfahren Sie mehr in der Kollisionsmatrix-Dokumentation.

Physik-Engines arbeiten, indem sie auf einem festen Zeitintervall laufen. Um die feste Rate zu sehen, mit der Ihr Projekt läuft, gehen Sie zu Bearbeiten > Projekteinstellungen > Zeit.
Das Feld Fester Zeitintervall definiert den Zeitdelta, der von jedem Physikschritt verwendet wird. Zum Beispiel entspricht der Standardwert von 0,02 Sekunden (20 ms) 50 fps oder 50 Hz.
Da jeder Frame in Unity eine variable Zeit benötigt, ist er nicht perfekt mit der Physiksimulation synchronisiert. Die Engine zählt bis zum nächsten physikalischen Zeitintervall. Wenn ein Frame etwas langsamer oder schneller läuft, verwendet Unity die verstrichene Zeit, um zu wissen, wann die Physiksimulation im richtigen Zeitintervall ausgeführt werden soll.
Falls ein Frame lange braucht, um sich vorzubereiten, kann dies zu Leistungsproblemen führen. Wenn Ihr Spiel beispielsweise einen Anstieg erlebt (z. B. das Instanziieren vieler GameObjects oder das Laden einer Datei von der Festplatte), könnte der Frame 40 ms oder mehr benötigen, um zu laufen. Mit dem Standardwert von 20 ms für den festen Zeitintervall würde dies dazu führen, dass zwei Physiksimulationen im folgenden Frame ausgeführt werden, um mit dem variablen Zeitintervall „aufzuholen“ .
Zusätzliche Physiksimulationen fügen wiederum mehr Zeit hinzu, um den Frame zu verarbeiten. Auf Plattformen mit niedrigerer Leistung kann dies potenziell zu einem Abwärtstrend der Leistung führen.
Ein nachfolgendes Frame, das länger zum Vorbereiten benötigt, verlängert den Rückstand der Physiksimulationen. Dies führt zu noch langsameren Frames und noch mehr Simulationen, die pro Frame ausgeführt werden müssen. Das Ergebnis ist eine immer schlechtere Leistung.
Schließlich könnte die Zeit zwischen den Physik-Updates die maximal erlaubte Timestep überschreiten. Nach diesem Cutoff beginnt Unity, Physik-Updates zu verwerfen, und das Spiel ruckelt.
Um Leistungsprobleme mit der Physik zu vermeiden:
Simulieren Sie den Physikschritt manuell, wenn nötig, indem Sie den SimulationMode während der Update-Phase des Frames auswählen. Dies ermöglicht es Ihnen, die Kontrolle darüber zu übernehmen, wann der Physikschritt ausgeführt wird. Übergeben Sie Time.deltaTime an Physics.Simulate, um die Physik mit der Simulationszeit synchron zu halten. Dieser Ansatz kann Instabilitäten in der Physiksimulation in Szenen mit komplexer Physik oder stark variablen Frame-Zeiten verursachen, verwenden Sie ihn daher mit Vorsicht.
Erfahren Sie mehr in der Physics.Simulate-Dokumentation.

Die Unity-Physik-Engine läuft in zwei Schritten:
Die Standard-Einstellung der breiten Phase für Sweep and Prune BroadPhase (Edit > Projekteinstellungen > Physik > Breite Phasentyp) kann falsche Positivmeldungen für Welten erzeugen, die im Allgemeinen flach sind und viele Collider haben. Wenn Ihre Szene groß und größtenteils flach ist, vermeiden Sie dieses Problem und wechseln Sie zu Automatisches Box-Pruning oder Multibox-Pruning-Breitphase. Diese Optionen teilen die Welt in ein Raster, wobei jede Rasterzelle Sweep-and-Prune durchführt.
Multibox-Pruning-Breitphase ermöglicht es Ihnen, die Weltgrenzen und die Anzahl der Rasterzellen manuell festzulegen, während das automatische Box-Pruning dies für Sie berechnet.
Siehe die vollständige Liste der Physikeigenschaften hier.

Wenn Sie einen bestimmten physikalischen Körper genauer simulieren möchten, erhöhen Sie seine Rigidbody.solverIterations.
Dies überschreibt die Physics.defaultSolverIterations, die auch in Edit > Projekteinstellungen > Physik > Standard-Lösungsiterationen gefunden werden kann.
Um Ihre physikalischen Simulationen zu optimieren, setzen Sie einen relativ niedrigen Wert in den defaultSolveIterations des Projekts. Wenden Sie dann höhere benutzerdefinierte Werte für Rigidbody.solverIterations auf die einzelnen Instanzen an, die mehr Details benötigen.
Erhalten Sie weitere Informationen zu Rigidbody.solverIterations.

Standardmäßig synchronisiert Unity Änderungen an Transforms nicht automatisch mit der Physik-Engine. Stattdessen wartet es bis zum nächsten Physik-Update oder bis Sie manuell Physics.SyncTransforms aufrufen. Wenn dies aktiviert ist, synchronisieren sich alle Rigidbody oder Collider auf diesem Transform oder dessen Kindern automatisch mit der Physik-Engine.
Wann manuell synchronisieren
Wenn autoSyncTransforms deaktiviert ist, synchronisiert Unity nur Transformationen vor dem physikalischen Simulationsschritt in FixedUpdate oder wenn dies ausdrücklich über Physics.Simulate angefordert wird. Sie müssen möglicherweise zusätzliche Synchronisierungen durchführen, wenn Sie APIs verwenden, die direkt von der Physik-Engine zwischen Transformänderungen und dem Physik-Update lesen. Beispiele sind der Zugriff auf Rigidbody.position oder das Durchführen von Physics.Raycast.
Leistungsbest Practices
Obwohl autoSyncTransforms sicherstellt, dass physikalische Abfragen aktuell sind, verursacht es Kosten in der Leistung. Jeder physikbezogene API-Aufruf zwingt zu einer Synchronisation, was die Leistung beeinträchtigen kann, insbesondere bei mehreren aufeinanderfolgenden Abfragen. Befolgen Sie diese Best Practices:
Erfahren Sie mehr über Physics.SyncTransforms.

Kontaktarrays sind im Allgemeinen deutlich schneller, daher ist die allgemeine Empfehlung, diese zu verwenden, anstatt Kollision-Callbacks wiederzuverwenden. Berücksichtigen Sie jedoch Folgendes, wenn Sie einen spezifischen Anwendungsfall dafür haben.
Die Callbacks MonoBehaviour.OnCollisionEnter, MonoBehaviour.OnCollisionStay und MonoBehaviour.OnCollisionExit nehmen alle eine Kollision-Instanz als Parameter. Diese Kollision-Instanz wird im verwalteten Heap zugewiesen und muss vom Garbage Collector gesammelt werden.
Um die Menge an erzeugtem Garbage zu reduzieren, aktivieren Sie Physics.reuseCollisionCallbacks (auch zu finden in Projekteinstellungen > Physik > Kollision-Callbacks wiederverwenden). Mit dieser Aktivierung weist Unity jeder Callback nur ein einzelnes Kollision-Paar-Instanz zu. Dies reduziert den Abfall für den Garbage Collector und verbessert die Leistung.
Die allgemeine Empfehlung ist, die Wiederverwendung von Kollision-Callbacks immer zu aktivieren, um Leistungsgewinne zu erzielen. Sie sollten diese Funktion nur für Legacy-Projekte deaktivieren, bei denen der Code auf einzelne Instanzen der Collision-Klasse angewiesen ist, was es unpraktisch macht, einzelne Felder zu speichern.
Erfahren Sie mehr über Physics.reuseCollisionCallbacks.

Statische Collider sind GameObjects mit einer Collider-Komponente, aber ohne Rigidbody.
Beachten Sie, dass Sie einen statischen Collider bewegen können, im Gegensatz zum Begriff „statisch“. Um dies zu tun, ändern Sie einfach die Position des Physik-Körpers. Akumulieren Sie die Positionsänderungen und synchronisieren Sie sie vor dem Physik-Update. Sie müssen keine Rigidbody-Komponente zum statischen Collider hinzufügen, nur um ihn zu bewegen.
Wenn Sie jedoch möchten, dass der statische Collider auf komplexere Weise mit anderen Physik-Körpern interagiert, geben Sie ihm ein kinematic Rigidbody. Verwenden Sie Rigidbody.position und Rigidbody.rotation, um ihn zu bewegen, anstatt auf die Transform-Komponente zuzugreifen. Dies garantiert ein vorhersehbareres Verhalten der Physik-Engine.
Hinweis: Wenn ein einzelner statischer Collider 2D zur Laufzeit bewegt oder neu konfiguriert werden muss, fügen Sie eine Rigidbody 2D-Komponente hinzu und setzen Sie sie auf den Static Körper-Typ, da es schneller ist, den Collider 2D zu simulieren, wenn er sein eigenes Rigidbody 2D hat. Wenn eine Gruppe von Collider 2Ds zur Laufzeit bewegt oder neu konfiguriert werden muss, ist es schneller, wenn sie alle Kinder des einzelnen versteckten Eltern-Rigidbody 2D sind, als jedes GameObject einzeln zu bewegen.
Erhalten Sie weitere Informationen über Rigidbodies.
Um Collider in 3D-Projekten innerhalb einer bestimmten Entfernung und in eine bestimmte Richtung zu erkennen und zu sammeln, verwenden Sie Raycasts und andere Physik-Abfragen wie BoxCast. Beachten Sie, dass
Physik-Abfragen, die mehrere Collider als Array zurückgeben, wie OverlapSphere oder OverlapBox, müssen diese Objekte im verwalteten Heap zuweisen. Das bedeutet, dass der Garbage Collector schließlich die zugewiesenen Objekte sammeln muss, was die Leistung verringern kann, wenn es zur falschen Zeit geschieht.
Um diesen Overhead zu reduzieren, verwenden Sie die NonAlloc Versionen dieser Abfragen. Wenn Sie beispielsweise OverlapSphere verwenden, um alle potenziellen Collider um einen Punkt zu sammeln, verwenden Sie stattdessen OverlapSphereNonAlloc.
Dies ermöglicht es Ihnen, ein Array von Collidern (die ErgebnisseParameter) als Puffer zu übergeben. Die NonAlloc-Methode funktioniert, ohne Müll zu erzeugen. Andernfalls funktioniert es wie die entsprechende Zuweisungsmethode.
Beachten Sie, dass Sie einen Ergebnispuffer ausreichender Größe definieren müssen, wenn Sie eine NonAlloc-Methode verwenden. Der Puffer wächst nicht, wenn der Speicherplatz ausgeht.
2D-Physik
Beachten Sie, dass der obige Rat nicht für 2D-Physikabfragen gilt, da in Unitys 2D-Physiksystem Methoden keinen "NonAlloc"-Suffix haben. Stattdessen bieten alle 2D-Physikmethoden, einschließlich derjenigen, die mehrere Ergebnisse zurückgeben, Überladungen an, die Arrays oder Listen akzeptieren. Zum Beispiel hat das 3D-Physiksystem Methoden wie RaycastNonAlloc, während das 2D-Pendant einfach eine überladene Version von Raycast verwendet, die ein Array oder List als Parameter akzeptieren kann, wie:
var results = new List();
int hitCount = Physics2D.Raycast(origin, direction, contactFilter, results);
Durch die Verwendung von Überladungen können Sie nicht zuweisende Abfragen im 2D-Physiksystem durchführen, ohne spezialisierte NonAlloc-Methoden zu benötigen.
Erfahren Sie mehr in der Dokumentation der NonAlloc-Methode.
Sie können Raycast-Abfragen mit Physics.Raycast durchführen. Wenn Sie jedoch eine große Anzahl von Raycast-Operationen haben (z. B. Berechnung der Sichtlinie für 10.000 Agenten), kann dies eine erhebliche Menge an CPU-Zeit in Anspruch nehmen.
Verwenden Sie RaycastCommand, um die Abfrage mit dem C# Job-System zu batchen. Dies entlastet die Arbeit vom Hauptthread, sodass die Raycasts asynchron und parallel erfolgen können.
Siehe ein Beispiel in der Dokumentation zu RaycastCommands.
Verwenden Sie das Physics-Debug-Fenster (Fenster > Analyse > Physics Debugger), um Probleme mit Kollisionen oder Abweichungen zu beheben. Dies zeigt einen farbcodierten Indikator der GameObjects, die miteinander kollidieren können.
Für weitere Informationen siehe Dokumentation des Physics Debuggers.


Finden Sie weitere optimale Vorgehensweisen und Tipps im Unity-Hub für optimale Vorgehensweisen. Wählen Sie aus über 30 Leitfäden, die von Branchenexperten sowie Unity-Ingenieuren und technischen Künstlern erstellt wurden und Ihnen helfen, effizient mit den Werkzeugen und Systemen von Unity zu entwickeln.