IO — Ivan Labs

Ein Unity-Spiel für schwache Hardware optimieren

3 Min. Lesezeit
UnitySpieleentwicklung

Unity-Optimierung hat eine lange Liste möglicher Techniken, aber der meiste tatsächliche Performance-Gewinn kommt von einer kurzen, korrekt angewendeten Liste.

Erst profilieren — den Engpass nicht raten

Ohne vorheriges Profiling zu optimieren ist einer der häufigsten Wege, Zeit auf Änderungen zu verschwenden, die nichts bewegen. Unitys eingebauter Profiler zeigt dir genau, wohin die Frame-Zeit tatsächlich geht — CPU-Logik, Rendering, Physik, oder Garbage Collection — bevor du irgendetwas anfasst.

Die wirkungsvollsten Fixes, ungefähr in Reihenfolge

  1. Draw Calls reduzieren. Batching (statisches Batching für unbewegte Objekte, dynamisches Batching oder GPU Instancing für bewegte) und Texture Atlasing (mehrere Texturen zu einer kombinieren) reduzieren die Anzahl separater Rendering-Anweisungen, die die CPU ausgeben muss — meist der größte einzelne Gewinn für schwächere Hardware.
  2. Object Pooling für alles, was häufig erzeugt wird. Instantiate() und Destroy() sind relativ teuer; einen Pool vorher erstellter Objekte (Projektile, Partikel, Gegner) wiederzuverwenden statt sie ständig zu erstellen und zu zerstören vermeidet sowohl diese Kosten als auch den damit verbundenen Garbage-Collection-Druck.
  3. Garbage-Collection-Druck reduzieren. Häufige kleine Allokationen (besonders in Update(), das jeden Frame läuft) lösen Garbage-Collection-Pausen aus, die sich als Ruckeln zeigen. Wiederverwendbare Objekte zu cachen und Allokationen in Hot Paths zu vermeiden (wie Pro-Frame-String-Verkettung) reduziert das erheblich.
  4. Physik-Update-Frequenz dort senken, wo Präzision nicht kritisch ist. Nicht jedes Objekt braucht die Standard-Fixed-Timestep-Rate — weniger kritische Physik-Interaktionen können manchmal mit reduzierter Rate laufen, ohne einen wahrnehmbaren Unterschied.
  5. LOD (Level of Detail) und Culling. Detail bei entfernten Objekten zu reduzieren und nicht zu rendern, was außerhalb des Bildschirms ist, reduziert direkt die Rendering-Arbeit pro Frame.
// Naiv: alloziert jeden Frame
void Update() {
    string status = "HP: " + currentHp; // neue String-Allokation jeden Frame
}
 
// Besser: aktualisiert nur, wenn sich der Wert tatsächlich ändert
void OnHealthChanged(int newHp) {
    statusText.text = $"HP: {newHp}"; // nur alloziert, wenn das tatsächlich feuert
}

Was speziell auf schwacher Hardware zu prüfen ist

SymptomWahrscheinliche Ursache
Konstant niedrige FramerateZu viele Draw Calls, oder übermäßig komplexe Shader
Periodisches Ruckeln/EinfrierenGarbage-Collection-Spitzen durch häufige Allokationen
Langsame LadezeitenUnkomprimierte oder übergroße Texturen/Audio
Frame-Einbrüche während Kampf/PartikelnFehlendes Object Pooling für erzeugte Effekte

Der Trade-off, der leicht überkorrigiert wird

Nicht alles braucht die aggressivste Optimierung — unverhältnismäßigen Aufwand in die Optimierung eines selten besuchten Menübildschirms zu stecken, während die eigentliche Gameplay-Schleife unoptimiert bleibt, ist eine häufige Fehlallokation. Profilieren, herausfinden, wo die Zeit tatsächlich verbracht wird, und dort zuerst optimieren.

Das verbindet sich direkt mit breiteren Architekturentscheidungen — siehe unsere Notiz zum Pet-Project-Prototyping dafür, warum vorzeitige Optimierung während des frühen Prototypings meist der falsche Instinkt ist, im Gegensatz zur Anwendung dieser Techniken, sobald eine Mechanik als wert bestätigt wurde, weiter ausgebaut zu werden.

Häufige Fragen

Sollte ich fortlaufend optimieren, oder bis zum Ende warten?

Meist warten — vorzeitige Optimierung von Systemen, die noch gestrichen oder neu designt werden könnten, verschwendet Aufwand. Die Ausnahme sind architektonische Entscheidungen (Object Pooling, Draw-Call-Muster), die später teuer nachzurüsten sind — die lohnt es sich, früh zu entscheiden, auch wenn du sie noch nicht vollständig implementierst.

Was ist die einzelne wirkungsvollste Optimierung für die meisten Unity-Spiele?

Draw Calls reduzieren, meist durch Batching (statisch oder dynamisch) und Texture Atlasing — das adressiert den häufigsten Engpass (die CPU verbringt zu viel Zeit mit dem Ausgeben von Rendering-Anweisungen), bevor man etwas Exotischeres anfasst.

Lohnt sich Object Pooling trotz der zusätzlichen Komplexität?

Für alles, was häufig erzeugt und zerstört wird — Projektile, Partikel, Gegner — ja, fast immer. Instantiate/Destroy-Aufrufe sind relativ teuer, und häufiges Spawnen ist einer der häufigsten realen Performance-Übeltäter.

Brauchst du Hilfe dabei?

Melde dich, und ich helfe dir weiter.

Kontaktiere mich

Ähnliche Artikel

Teilen:X / TwitterLinkedIn