In meiner Game Engine verwende ich Box2D für die Physik. Die Benennungskonventionen von Box2D und die schlechte Kommentierung ruinieren den konsistenten und gut dokumentierten Rest meiner Engine, der ein wenig frustrierend ist und schlecht präsentiert, wenn Sie ihn verwenden.
Ich habe darüber nachgedacht, Wrapper-Klassen für Box2D zu erstellen. Das heißt, Klassen, die jedes der üblichen Box2D-Objekte erweitern und deren Funktionen neu geschrieben werden, um den Namenskonventionen des Rests meiner Engine zu folgen und sie deutlicher und konsistent zu kommentieren. Ich habe sogar darüber nachgedacht, einige der Klassen zu erstellen und einige kleine Teile hinzuzufügen (wie Getter für pixelbasierte Messungen in der Klasse b2Vec2
).
Das ist in Ordnung, aber ich bin mir nicht 100% sicher, welche negativen Auswirkungen das haben würde und in welchem Ausmaß sich diese auf meine Anwendungen und Spiele auswirken würden. Ich bin mir nicht sicher, ob der Compiler einige meiner Bedenken in gewissem Maße lindert oder ob ich beim Hinzufügen etwas unnötiger Klassen aus Gründen der Lesbarkeit und Konsistenz rücksichtsvoll sein muss.
Ich habe einige Vermutungen:
Ich frage speziell nach Laufzeitauswirkungen.
Dies ist ein ziemlich häufiges Problem, wenn es darum geht, Bibliotheken von Drittanbietern zu integrieren, insbesondere Bibliotheken, die Ports sind (wie Box2DAS3), wobei sie die Kodierungs- und Benennungskonventionen der übergeordneten Sprache beibehalten und nicht vollständig in die Zielsprache integrieren ( Fall in Punkt: Box2DAS3 mit getFoo()
und setFoo()
anstelle von .foo
Getter / Setter).
Um Ihre Frage schnell zu beantworten, nein, es wird keine nennenswerten Auswirkungen auf die Leistung geben, wenn Wrapper-Klassen erstellt werden. nicht mehr, als Sie in der Klassenhierarchie in Ihrem eigenen Projekt sehen. Sicher, wenn Sie eine Schleife von 5 Millionen Iterationen Zeit, Sie sehen möglicherweise eine Millisekunde oder zwei der Unterschied, aber bei normaler Verwendung, werden Sie es nicht bemerken.
"Mehr Speicherverbrauch, um der zusätzlichen Klassenstruktur Rechnung zu tragen." Wie bei jeder anderen Sprache, die eine Klassenvererbung hat, wird im Hintergrund eine Vtable verwendet, so dass Sie eine kleine Steigerung des Arbeitsspeichers / Perf haben, aber das ist vernachlässigbar.
"Leistungseinbußen beim Erstellen neuer Objekte aufgrund der Initialisierung einer zusätzlichen Mitgliederebene?" Nicht mehr als eine normale Instanziierung, also sollten Sie sich keine Sorgen machen, es sei denn, Sie erstellen eine große Menge an Objekten.
Im Hinblick auf die Leistung sollten Sie generell kein Problem haben (bevorzugen Sie Lesbarkeit und Benutzerfreundlichkeit gegenüber der Leistung, es sei denn, Sie haben tatsächlich ein Problem damit), aber ich würde es eher als ein architektonisches Problem betrachten und in diesem Sinne was würde eine negative Auswirkung der Erweiterung / Änderung von Klassen einer externen Bibliothek im Allgemeinen in drei Bereiche fallen, je nachdem, was Sie tun möchten:
Ändern Sie die Bibliothek
Da Box2DAS3 Open Source ist, gibt es nichts, was Sie davon abhält, alle Klassen- und Funktionsnamen nach Herzenslust zu springen und zu refactorisieren. Ich habe ernsthaft darüber nachgedacht, das manchmal zu tun.
Vorteile:
Nachteile:
Erweitern Sie die Klassen
Hier erstellen Sie einfach Ihre eigenen Wrapper-Klassen, die die Basis-Box2D-Klassen erweitern. Sie können Eigenschaften und Funktionen hinzufügen, wie Sie möchten, einschließlich der Implementierung eines eigenen Namensschemas, das in die Basisklasse übersetzt (z. B. MyBox2DClass.foo()
könnte einfach ein Wrapper für Box2DClass.bar()
sein)
Vorteile:
MyBox2DClass
-Objekt an eine interne Methode übergeben, die ein Box2DClass
übernimmt und Sie wissen, dass es funktioniert Nachteile:
setPos()
oder SetPosition()
verwenden?). Auch wenn Sie alleine arbeiten, wenn Sie kommen zurück zu deiner Klasse in 6 Monaten, wirst du setPos()
), bei anderen dagegen Box2D ( SetPosition()
)) Komposition mit eigenen Klassen
Sie erstellen eigene Klassen, die intern eine Box2D-Eigenschaft enthalten (z. B. MyPhysicalClass
hat eine Eigenschaft b2Body
). Sie können Ihre eigene Schnittstelle nach Belieben implementieren und nur das, was notwendig ist.
Vorteile:
b2Body
-Eigenschaft Nachteile:
Von den dreien bevorzuge ich die Komposition, da sie die größte Flexibilität bietet und die Modulnatur Ihrer Engine intakt hält, dh Sie haben Ihre Kern-Engine-Klassen und Sie erweitern -Funktionalität mit externen Bibliotheken. Die Tatsache, dass Sie Bibliotheken mit minimalem Aufwand wechseln können, ist ebenfalls ein großes Plus. Dies ist die Technik, die ich in meiner eigenen Engine verwendet habe, und ich habe sie auch auf andere Arten von Bibliotheken ausgedehnt - z. Ads - Ich habe meine Engine-Ad-Klasse, die mit Mochi, Kongregate, etc. nach Bedarf integriert werden kann - der Rest meines Spiels ist mir egal, was ich benutze, wodurch ich meinen Coding-Stil und Konsistenz während der gesamten Engine beibehalten kann immer noch flexibel und modular.
----- Update 20/9/2013 -----
Große Aktualisierungszeit! Also ging ich zurück, um etwas über Größe und Geschwindigkeit zu testen. Die Klasse, die ich verwendet habe, ist zu groß, um sie hier einzufügen. Sie können sie also unter Ссылка
herunterladenDarin teste ich eine Anzahl von Klassen:
Empty
Instanz; Eine Klasse, die nur Object
erweitert und eine leere getPostion()
-Funktion implementiert. Dies wird unser Maßstab sein b2Body
Instanz Box2DExtends
Instanz; Eine Klasse, die b2Body
erweitert und eine Funktion getPosition()
implementiert, die nur GetPosition()
(die b2Body
-Funktion) Box2DExtendsOverrides
Instanz; Eine Klasse, die b2Body
erweitert und die Funktion GetPosition()
überschreibt (sie gibt einfach super.GetPosition()
zurück) Box2DComposition
Instanz; Eine Klasse mit einer b2Body
-Eigenschaft und einer getPosition()
-Funktion, die die b2Body's
GetPosition()
zurückgibt.
Box2DExtendsProperty
Instanz; Eine Klasse, die b2Body
erweitert und eine neue Eigenschaft Point
Box2DCompositionProperty
Instanz; Eine Klasse, die sowohl eine b2Body
-Eigenschaft als auch eine Point
-Eigenschaft Alle Tests wurden im Standalone-Player, FP v11.7.700.224, Windows 7, auf einem nicht sehr guten Laptop durchgeführt.
Test1: Größe
AS3 ist ein bisschen ärgerlich, wenn Sie getSize()
aufrufen, wird Ihnen die Größe des Objekts selbst angezeigt, aber alle internen Eigenschaften, die auch Objects
sind, ergeben nur einen 4 byte
Zuwachs Zählen nur den Zeiger. Ich kann sehen, warum sie das machen, es macht es nur ein bisschen peinlich, die richtige Größe zu bekommen.
Also wandte ich mich an das flash.sampler
-Paket. Wenn wir die Erstellung unserer Objekte testen und alle Größen in den NewObjectSample
-Objekten addieren, erhalten wir die volle Größe unseres Objekts (HINWEIS: Wenn Sie sehen möchten, was erstellt wurde und die Größe, kommentieren Sie in log
ruft die Testdatei auf).
Diese Größen sind alle in Bytes. Einige bemerkenswerte Punkte:
Object
size ist 40
bytes, also nur die Klasse und nichts anderes ist 16
bytes. 20
bytes für Box2DComposition
stammen von 16
für die Klasse und 4
für den Zeiger auf die Eigenschaft b2Body
Box2DExtendsProperty
etc haben Sie 16
für die Klasse Point
selbst, 4
für den Zeiger auf die Eigenschaft Point
und 8
für jede x
und y
Eigenschaft Numbers
= 36
bytes Unterschied zwischen dieser und Box2DExtends
Der Unterschied in der Größe hängt also offensichtlich von den Eigenschaften ab, die Sie hinzufügen, aber alles in allem ziemlich vernachlässigbar.
Test 2: Erstellungsgeschwindigkeit
Dafür habe ich einfach getTimer()
, mit einer Schleife von 10000
, selbst looped 10
(also 100k) verwendet, um den Durchschnitt zu erhalten. System.gc()
wurde zwischen den einzelnen Gruppen aufgerufen, um den Zeitaufwand für die Garbage Collection zu minimieren.
Hier gibt es keinen ganzen Haufen. Die Erweiterungs- / Kompositionsklassen brauchen etwas länger, aber es ist wie 0.000007ms
(dies ist die Erstellungszeit für 100.000 Objekte), also ist es nicht wirklich eine Überlegung wert.
Test 3: Anrufgeschwindigkeit
Dafür habe ich getTimer()
erneut verwendet, mit einer Schleife von 1000000
, selbst gelooped 10
(also 10m) mal, um den Durchschnitt zu erhalten. System.gc()
wurde zwischen den einzelnen Gruppen aufgerufen, um den Zeitaufwand für die Garbage Collection zu minimieren. Für alle Objekte wurden ihre getPosition()/GetPosition()
-Funktionen aufgerufen, um den Unterschied zwischen Überschreiben und Umleiten zu sehen.
Dieser hat mich etwas überrascht, mit dem Unterschied zwischen den Zeiten ~ 2x (obwohl das immer 0.000007ms
pro Anruf ist). Die Verzögerung scheint vollständig auf die Klassenvererbung zurückzuführen zu sein - z. Box2DExtendsOverrides
ruft einfach super.GetPosition()
auf, ist aber doppelt so langsam wie Box2DExtendsProperty
, das GetPosition()
von seiner Basisklasse erbt.
Ich denke, es hat etwas mit dem Overhead von Funktions-Lookup und Calling zu tun, obwohl ich mir den generierten Bytecode mit swfdump
im FlexSDK angeschaut habe, und sie sind identisch, also liegt es entweder an mir (oder auch nicht Wenn die Schritte gleich sein sollten, ist die Zeit zwischen ihnen wahrscheinlich nicht gleich (z. B. im Speicher, springt sie zu Ihrer Klassen-V-Tabelle und springt dann zur Basisklassen-V-Tabelle) usw.)
Der Bytecode für var v:b2Vec2 = b2Body.GetPosition()
ist einfach:
während var v:b2Vec2 = Box2DExtends.getPosition()
( getPosition()
gibt GetPosition()
zurück) ist:
Im zweiten Beispiel wird der Aufruf von GetPosition()
nicht angezeigt. Daher bin ich mir nicht sicher, wie sie das beheben. Die Testdatei steht zum Download bereit, wenn jemand bei der Erklärung einen Fehler machen möchte.
Einige Punkte, die Sie beachten sollten:
GetPosition()
macht wirklich nichts; Es ist im Wesentlichen ein Getter, der als Funktion getarnt ist, was ein Grund dafür ist, dass die "Extra Class Step Penalty" so groß erscheint
Alles in allem würde ich die gleichen Ergebnisse erwarten, wenn ich einen meiner eigenen Kurse erweitern würde, also würde ich mir darüber keine Sorgen machen. Implementieren Sie die Architektur, die für Ihre Lösung am besten geeignet ist.
Ich weiß, dass diese Antwort nicht für das Kopfgeld geeignet ist, da ich viel zu faul bin, Benchmarks zu schreiben. Aber nachdem ich an der Flash-Codebasis gearbeitet habe, kann ich vielleicht ein paar Hinweise geben:
Das avm2 ist eine dynamische Sprache, daher wird der Compiler in diesem Fall nichts optimieren. Das Abwickeln eines Anrufs als Unterklassenanruf verursacht Kosten. Jedoch werden diese Kosten konstant zeit und klein sein.
Die Kosten der Objekterstellung werden höchstens von einer konstanten Menge an Zeit und Speicher beeinflusst. Auch die Zeit und der Betrag werden wahrscheinlich unbedeutend im Vergleich zu den Grundkosten sein.
Aber wie bei vielen Dingen steckt der Teufel im Detail. Ich habe box2d nie benutzt, aber wenn es irgendeine Art von Objekt-Pooling gibt, könnte es nicht mehr funktionieren. Im Allgemeinen sollten Spiele versuchen, ohne Objektzuweisungen zur Spielzeit zu laufen. Seien Sie also sehr vorsichtig, wenn Sie keine Funktionen hinzufügen, die Objekte zuweisen, um schöner zu sein.
%Vor%Kann hässlich sein, ist aber viel schneller als
%Vor%(Ich hoffe, ich habe meine AS3-Syntax richtig ...). Noch nützlicher und hässlicher könnte sein
%Vor%Also meine Antwort ist, wenn Sie nur für Lesbarkeit wickeln, gehen Sie dafür. Es ist ein kleiner, aber konstanter Preis. Aber sei sehr, sehr vorsichtig, um zu ändern, wie Funktionen funktionieren.
Ich weiß nicht, ob die Instanziierungszeit einen großen Einfluss hat, aber ich werde Ihre Frage anders beantworten: Was sind Ihre anderen Möglichkeiten? Scheinen sie, sie werden es besser machen?
Es gibt eine schöne Benchmark von Jackson Dunstan über die Funktionsleistung: Ссылка
Um es zusammenzufassen:
Wenn Sie also keine Vererbung verwenden möchten, müssen Sie sie möglicherweise durch statische Aufrufe ersetzen, was die Leistung beeinträchtigt. Persönlich werde ich diese Klassen erweitern und eine eifrige Instanziierung aller Objekte hinzufügen, die ich zur Laufzeit benötige: Wenn es groß ist, mache einen schönen Ladebildschirm ...
Sehen Sie sich auch Post-Bytecode-Optimierungen an, z. B. apparat: Ссылка
Ich glaube nicht, dass eine Verlängerung die Leistung stark beeinflussen wird. Ja, es gibt einige Kosten, aber es ist nicht so hoch, solange Sie keine Komposition verwenden. I.e. Anstatt Box2d-Klassen direkt zu erweitern, erstellen Sie eine Instanz dieser Klassen und arbeiten damit innerhalb Ihrer Klasse. Zum Beispiel das
%Vor%statt dessen
%Vor%Ich denke, Sie wissen, dass je weniger Objekte Sie erstellen, desto besser. Solange Sie die Anzahl der erstellten Instanzen beibehalten, haben Sie dieselbe Leistung.
Aus einem anderen Blickwinkel: a) das Hinzufügen einer weiteren Schicht von Abstraktionen kann die Box2d sehr verändern. Wenn Sie in einem Team arbeiten, kann das ein Problem sein, da die anderen Entwickler Ihre Benennung lernen sollten b) seien Sie vorsichtig mit Middle Man Code-Geruch. Wenn Sie mit dem Umschließen bereits vorhandener Funktionen beginnen, werden normalerweise Klassen zurückgegeben, die nur Delegatoren sind.
Einige gute Antworten hier, aber ich werde meine zwei Cent hineinwerfen.
Es gibt zwei verschiedene Konzepte, die Sie erkennen müssen: Wenn Sie eine Klasse erweitern und implementieren eine Klasse.
Hier ist ein Beispiel für die Erweiterung von MovieClip
Hier ist ein Beispiel für die Implementierung von MovieClip
%Vor%Ich denke, Sie möchten diese box2D-Klassen wahrscheinlich nicht erweitern, sondern implementieren. Hier ist ein grober Überblick:
%Vor%Viel Glück.
Tags und Links memory performance actionscript-3 avm2