Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

buggypixels

Treue Seele

Beiträge: 125

Wohnort: Meerbusch

Beruf: Programmierer

  • Private Nachricht senden

31

12.04.2011, 13:05

Aha. Wenn Du das so siehst, dann bitte schön.
Wenn Du dir das mal etwas näher anschauen würdest, dann siehst Du einen erheblichen Unterschied in der API.
Hinterher eine solche Umstellung zu machen, wäre äußerst schmerzhaft.
Außerdem ist die Aussage, mit Dark Voodoo und "von 51 auf 52 Prozent" fragwürdig.
Ich selber habe letztens erst in meiner Engine an einer Stelle genau solch eine Umstellung gemacht. Hier ging es bei mir um Sprites.
Da hatte ich auch eine Sprite Klasse mit allem drum und dran und dann eine SpriteBatchNode, die eine Liste eben solcher Sprites
verwaltete. Die Umstellung, die ich hier beschrieben habe, brachte eine Steigerung von 200% ca.
Darum habe ich gedacht, ich gebe ihm direkt mal einen solchen Denkansatz mit.
Wie Du siehst, kommst das hier nicht aus dem hohlen Bauch, sondern aus einer konkreten Umsetzung.
Wenn es nicht Deinem persönlichen Geschmack trifft, oder Du lieber anders arbeitest, kein Problem.
Ich wollte ihm hier einen Vorschlag unterbreiten.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

32

12.04.2011, 13:14

Es geht mir nicht um Deinen Design-Vorschlag, sondern um das hier:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Unit {
  void setPosition(const Vec3& pos);
  void setState(const bool& active);
private:
  Vec3 pos;
  bool active;
...

class UnitController {
  void setPosition(const UnitHandle& handle,const Vec3& pos);
  void setState(const UnitHandle& handle,const bool& state);
private:
  bool* m_Active;
  Vec3* m_Positions;
}

void update() {
  bool* active = m_Active;
  Vec3* pos = m_Positions;
  for ( int i = 0; i < m_Counter; ++i ) {
    if ( *active ) {
       *pos += m_Velcoity;
    }
  }
  ++pos;
  ++active;
}

Schon allein Deine Annahme darüber, wie die Attribute der Klassen "Unit" und "UnitController" im Speicher abgelegt werden, ist mehr als fragwürdig, genau wie überhaupt die Verwendung eines Pointers statt eines Vectors.

Bei Performance geht es nie darum, ob ein einzelner Teil doppelt oder dreifach so schnell ist, sondern nur darum, wie sich die Gesamtperformance verhält. Wenn also SOWAS Dein gesamtes Programm um 200% beschleunigt hat, dann kann es ja nicht viel mehr als das gewesen sein und Du hattest vorher ohnehin vermutlich eine schlechte Wahl bezüglich der verwendeten Container getroffen, denn die aktuelle ist ja auch nicht gerade elegant oder sinnvoll.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »BlueCobold« (12.04.2011, 13:20)


buggypixels

Treue Seele

Beiträge: 125

Wohnort: Meerbusch

Beruf: Programmierer

  • Private Nachricht senden

33

12.04.2011, 13:33

Warum diskutierst Du immer an vorderster Front, selbst wenn Du Sachen nicht verstehst?
Schau Dir doch bei Gelegenheit mal http://research.scee.net/files/presentat…ing_GCAP_09.pdf an.
Hier wird das sehr anschaulich dargestellt.
Der Performance Gewinn bezog sich übrigens nur auf diese eine besagte Klasse. Da ich meinen Code ausführlichst per Profiling überwache, kann ich halt
auch leicht erkennen, wenn ich in einem Teilbereich (sprich einer Klasse) deutlich die Performance steigern kann.

Das mit den Zeigern etc. ist auch nicht so schwer zu verstehen. Wo ist denn da das Problem?

C-/C++-Quelltext

1
2
3
4
5
6
7
8
class UnitController {
private:
  Vec3* pos;
}

UnitController::UnitController() {
  pos = new Vec3[4096];
}

Verstehe nicht, wie man etwas doch recht triviales in C/C++ nicht verstehen kann. Das findet man sehr häufig.
Aber wieder Mal gebe ich mich geschlagen.

Bin mal gespannt, ob Du uns denn auch mal einen etwas konkreteren Vorschlag unterbreitest.

Sylence

Community-Fossil

Beiträge: 1 663

Beruf: Softwareentwickler

  • Private Nachricht senden

34

12.04.2011, 13:59

Können wir dafür nicht mal bitte einen seperaten Thread machen.... nervt langsam bei jedem thema in dem buggy schreibt immer bei der diskusion design vs. premature optimization zu enden...

buggypixels

Treue Seele

Beiträge: 125

Wohnort: Meerbusch

Beruf: Programmierer

  • Private Nachricht senden

35

12.04.2011, 14:26

Alles klar.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

36

12.04.2011, 15:31

buggypixels, es geht nicht um technisches Verständnis von Pointer, sondern um die Sinnlosigkeit mit der Du sie da einsetzt.
Aber Sylence hat schon Recht, die Diskussion führt nirgendwohin außer in den Mülleimer, schon weil er vermutlich das Prinzip von Optimierung im Gegensatz zu premature optimization nicht versteht.

Konkrete Vorschläge (und die sogar zur eigentlichen Frage!) habe ich übrigens schon gemacht.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

37

12.04.2011, 22:59

Zitat

Alternativ könntest du z.B. auch einfach mit Unit* bzw Unit& arbeiten und den Typ Unit nach außen hin inkomplett lassen, d.h. auf der anderen Seite deiner Schnittstelle gibts nur das:

wie geht denn das? oder meintest du UnitHandle* UnitHandle&, wie beim ansatz von buggypixels?

Zitat

Warum brauch ich den ganzen Kram, was hab ich davon und warum kann ich nicht einfach new Thingie() machen und Glücklich sein?

ich finde halt, dass bei spielobjekte mit langlebiger lebensdauer schon irgendwo eine klasse hergehort, die das ganze irgendwie verwaltet und steuert, sonst endet das imo nur im chaos, wenn ich überall im code alles machen kann ohne jegliche einschränkungen.
habe es da lieber, wenn ich z.b. weiß, dass die kernklassen auf "nichts" zugreifen und nur simpel sind, dann ne darüberliegende schicht für die logik des spiels und dann noch ne dritte schicht für die anzeige (mvc pattern z.b.).



zu buggypixels vorschlag:
1) warum machst du immer arrays der größe 4096? einfach so? oder hat das irgendeinen besonderen sinn?
2) wozu bräuchte man bei deinem optimierten ansatz überhauüt noch unit und unithandle? alle attribute von unit scheinen ja in den unitcontroller zu kommen und somit kann man eh nur mehr über den controller etwas mit den einheiten anstellen? die unit klasse selbst wird dadurch doch dann gar nicht mehr benötigt?
3) was mir an dem ansatz gefällt ist, dass dies dann vmtl recht einfach für scripting (z.b. lua) dann zu übernehmen wäre? registrieren der einfachen unithandle klasse und registrieren der unitcontroller methoden und schon könnte man alles in scripten benutzen (kenne mich da noch nicht gut aus, ist also nur ne annahme)
4) wird dein ansatz in "besseren" spieleprojekten so verwendet? nur aus interesse.

was ich persönlich halt etwas dumm bei dem ansatz finde ist, dass man halt irgendwie keine klasse unit mehr hat, die eine einheit repräsentiert, sondern nur mehr diesen "unitcontainer", der alle einheiten mitverwaltet.



@bluecobold:
das mit dem observer wird später noch kommen, für das eventsystem, aber wäre an sich auch sicherlich kein schlechter ansatz. was ich mir dazu dachte (wie du es eh auch schon bischen angedeutat hast):
- in jeder methode von unit (außer getdingen), wird der controller notified
- dem unitkonstruktor wird der parameter der id weggenommen, dafür wird vom controller eine "register()" methdoe zur verfügung gestellt, die dann verwendet wird um jede einheit, die nicht über den controller geadded wird, zum controller hinzuzufügen. das würde schonmal das "problem" von externen uniterstellungen beheben. dito mit dem destruktor.

das meiner meinung nach dumme ist dann, dass man immer diese zusätzliche überprüfungen benötigt, ob etwas direkt von der unitinstanz aufgerufen wird, oder ob es über den controller erfolgte. da die unit ja immer notified, hat man im controller ja iwie sowas:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void onNotifiy( Unit& u, ... )
{
  if( *_currentUnit != u )
  {
    // ein direkter aufruf über u erfolgte - iwie darauf reagieren
  } 
}

void update( Unit& u, ... )
{
  // currentunit setzen, damit onNotifiy "ignoriert" wird
  _currentUnit = &u;

  u.update( ... );
}


und das fand ich dann auch nicht mehr so schön. um das dann wieder auszumärzen bin ich dann selbst fast auf eine ähnlich lösung wie buggypixels gekommen( die vmtl schlechter ist als seine, aber egal:P).





wie auch immer, danke für die vielen infos und ratschläge, werde dann mal bei zeiten buggypixels vorschlag so umsetzen, wie ich ihn mir vorstelle. würde mich aber noch auf die beantwortung der obigen 4 fragen freuen :)

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

38

12.04.2011, 23:14

Zitat

Alternativ könntest du z.B. auch einfach mit Unit* bzw Unit& arbeiten und den Typ Unit nach außen hin inkomplett lassen, d.h. auf der anderen Seite deiner Schnittstelle gibts nur das:

wie geht denn das? oder meintest du UnitHandle* UnitHandle&, wie beim ansatz von buggypixels?

Nein, ich mein Unit* bzw. Unit&. Wenn du nicht willst dass der Benutzer deines Interface direkt mit Unit arbeitet (warum auch immer) dann gibt ihm einfach nicht die Klassendefinition davon sondern nur eine Forward-Declaration. Auf diese Weise kannst du ihm einfach einen Unit* bzw. Unit& geben der eben ein Unit identifiziert, aber den genauen Aufbau von Unit kennst du nur intern, in den Implementierungen der Methoden die damit arbeiten. Der Benutzer kann dir so zwar einen Unit* bzw. Unit& als "Handle" übergeben aber sonst nichts damit anfangen. Für dich fällt aber die ganze Sache mit Table-Lookups etc. weg da du den Pointer/die Referenz einfach direkt verwenden kannst.

Zitat

Warum brauch ich den ganzen Kram, was hab ich davon und warum kann ich nicht einfach new Thingie() machen und Glücklich sein?

ich finde halt, dass bei spielobjekte mit langlebiger lebensdauer schon irgendwo eine klasse hergehort, die das ganze irgendwie verwaltet und steuert, sonst endet das imo nur im chaos, wenn ich überall im code alles machen kann ohne jegliche einschränkungen.

Ich halte von irgendwelchen reinen Managerklassen eigentlich nicht viel. Auch wenn deine Objekte einen langlebigeren Scope haben, es gibt eben einen Scope in den sie rein logisch gehören (z.B. das Objekt welches sie erzeugt) warum brauch ich da ein anderes Objekt das sich darum kümmert, imo sorgen solche Konstrukte erst recht für Chaos.

buggypixels

Treue Seele

Beiträge: 125

Wohnort: Meerbusch

Beruf: Programmierer

  • Private Nachricht senden

39

13.04.2011, 08:19

Dann werde ich mal die 4 Fragen beantworten

Zitat


1) warum machst du immer arrays der größe 4096? einfach so? oder hat das irgendeinen besonderen sinn?
2) wozu bräuchte man bei deinem optimierten ansatz überhauüt noch unit und unithandle? alle attribute von unit scheinen ja in den unitcontroller zu kommen und somit kann man eh nur mehr über den controller etwas mit den einheiten anstellen? die unit klasse selbst wird dadurch doch dann gar nicht mehr benötigt?
3) was mir an dem ansatz gefällt ist, dass dies dann vmtl recht einfach für scripting (z.b. lua) dann zu übernehmen wäre? registrieren der einfachen unithandle klasse und registrieren der unitcontroller methoden und schon könnte man alles in scripten benutzen (kenne mich da noch nicht gut aus, ist also nur ne annahme)
4) wird dein ansatz in "besseren" spieleprojekten so verwendet? nur aus interesse.


1) 4096 ist nur eine Zahl. In dem UnitHandle hatte ich den Index mit 28 Bit definiert, dass wären also maximal 268435456. Soviel Unit Instanzen könntest Du dann maximal in das Array setzen. Aber ich dachte halt, 4096 ist ne vernünftige Obergrenze.

2) Die Unit Klasse entfällt komplett. Ich meinte ja, dass alle Methoden von der Unit Klasse in den Controller wandern.

3) Das ist korrekt

4) Ja. Ich hatte ja einen Link zu einem PDF gepostet. Dieser Ansatz findet sich in professionellen Spielen sehr häufig. Wenn Du dich intensiver mit dem Thema beschäftigst, dann wirst Du viele Powerpoint Präsentationen, PDFs und Artikel von wirklich bekannten Leuten finden.

Ich weiß halt auch, dass viele Leute am Anfang das alles sehr schräg finden. Mir ging es ja nicht anders. Aber wenn man sich mal darauf einläßt, dann fühlt es sich nach einiger Zeit nicht mehr so schräg an.

Bei Fragen kannst Du dich an direkt an mich wenden. Nicht alle Leute hier mögen das Thema und wir sollten das hier dann nicht mehr weiter ausführen.

40

13.04.2011, 08:43

Würde es nicht eigentlich den gleichen Effekt haben, wenn man, statt die einzelnen Attribute in eigene Arrays zu packen, einfach einen Object Pool baut?
http://gameprogrammingpatterns.com/object-pool.html
http://en.wikipedia.org/wiki/Object_pool_pattern

Werbeanzeige