Wenn ich in-Motor bin Codierung, bin ich oft nur mit einem festen besorgt n
: Ich habe bereits eine räumliche Teilung die Anzahl der Objekte zu begrenzen empfängt update()
, physics()
und render()
auf etwa diejenigen auf dem Bildschirm und die umliegenden Gebiete. Die maximale Stapelgröße ist normalerweise pro Spiel ziemlich genau definiert, obwohl sie immer etwas größer ist, als Sie es geplant haben.
In diesem Fall beschäftige ich mich weniger mit Big-O als mit dem konstanten Faktor-Multiplikator und Termen niedrigerer Ordnung. Für eine Funktion mit Laufzeit wie a*n^2 + b*n + c
(was ist O(n^2)
), bin ich oft viel mehr mit dem Reduzieren a
und möglicherweise Eliminieren beschäftigt c
. Einrichtungs- oder Abbaukosten c
können proportional groß zu einem kleinen werden n
.
Dies bedeutet jedoch nicht, dass Big-O (oder insbesondere Big-Theta ) ein guter Code-Geruchsindikator ist. Sehen Sie sich O(n^4)
irgendwo oder noch schlimmer eine O(k^n)
geometrische Zeit an und stellen Sie sicher, dass Sie andere Optionen in Betracht ziehen.
Ich mache mir im Allgemeinen viel mehr Sorgen um die Big-O-Optimalität und springe durch die Rahmen, um Algorithmen mit niedrigerem Big-O zu finden, wenn ich mit Datenerstellungswerkzeugen arbeite. Während die Anzahl der Objekte in einem bestimmten Level / Streaming-Bereich im Allgemeinen genau definiert ist, kann es sein, dass die Gesamtanzahl der Objekte / Kunstobjekte / Konfigurationsdateien / usw. in einem gesamten Spiel nicht genau definiert ist. Es ist auch eine viel größere Zahl. Selbst wenn wir ein paralleles Daten-Make ausführen, warten wir immer noch in der Größenordnung einer Minute (ich weiß, Winseln - Daten-Make für Konsolen kann Stunden dauern - wir sind meist kleine Handheld-Spiele), um einen jam data-clean && jam data
Zyklus zu durchlaufen .
Um ein konkretes Beispiel zu nennen: Ein Streaming-Algorithmus für Kacheln im Hintergrund, der 8x8 Kacheln mit 256 Farben streamt, ist völlig außer Kontrolle geraten. Es ist nützlich, Streaming-Puffer zwischen Hintergrund- "Ebenen" zu teilen, und wir können bis zu 6 von ihnen in einer bestimmten Ebene haben, die denselben Puffer teilen. Das Problem ist, dass die Schätzung der Größe des benötigten Puffers auf den möglichen Positionen aller 6 Ebenen basiert - und wenn es sich um eine Breite / Höhe / Bildlaufrate von Primzahlen handelt, beginnen Sie schnell mit einer umfassenden Suche - welche beginnt sich zu nähernO(6^numTiles)
- die in vielen Fällen in der Kategorie "länger als das Universum sein wird" ist. Glücklicherweise sind die meisten Fälle nur 2-3 Schichten, aber selbst dann haben wir eine Laufzeit von über einer halben Stunde. Momentan untersuchen wir eine sehr kleine Teilmenge dieser Möglichkeiten und erhöhen die Granularität, bis eine festgelegte Zeitspanne verstrichen ist (oder wir haben die Aufgabe abgeschlossen, die für kleine Doppelschichtkonfigurationen auftreten kann). Wir erhöhen diese Schätzung ein wenig, basierend auf früheren Statistiken darüber, wie oft wir uns als falsch erwiesen haben, und fügen dann ein wenig zusätzliche Polsterung hinzu, um eine gute Maßnahme zu treffen.
Ein weiteres lustiges Beispiel: Vor einiger Zeit experimentierte der leitende Ingenieur bei einem PC-Spiel eine Weile mit Sprunglisten . Der Speicheraufwand führt letztendlich zu mehr Cache-Effekten, wodurch die gesamte Angelegenheit um einen nicht konstanten Multiplikator erweitert wird. Für kleine Unternehmen sind sie also keine gute Wahl n
. Für größere sortierte Listen, in denen häufig gesucht wird, bieten sie jedoch Vorteile.
(Ich stelle oft fest, dass der naive Algorithmus einen höheren Big-O-Wert aufweist, bei kleineren Datenmengen schneller und einfacher zu verstehen ist. Die interessanteren / komplexeren Algorithmen (z. B. Patricia Trie) sind für die Benutzer schwieriger zu verstehen und zu verwalten, bei größeren jedoch eine höhere Leistung Datensätze.)