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

DeKugelschieber

Community-Fossil

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

11

19.01.2015, 10:17

Mein System ist eigentlich nicht monolithisch. Ich finde es unbehaglich Komponenten global zu verwalten und dann in Managern zu suchen. Das scheint mir das ganze nur zu verkomplizieren.

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
class EineKomponente{
  // Daten
}

class EinEntity{
  EineKomponente* bla;

  EinEntity(){
    bla = nullptr;
  }
}

EinSystem::update(const float deltaTime){
  EinEntity* entity;

  for(auto e : entities){
    entity = static_cast<EinEntity*>(e);

    if(entity && entity->bla){
      // mach was mit der Komponente
    }
  }
}

buggypixels

Treue Seele

Beiträge: 125

Wohnort: Meerbusch

Beruf: Programmierer

  • Private Nachricht senden

12

19.01.2015, 12:05

Beim Ansatz von DeKugelschieber geht leider genau das "Data oriented" verloren. Es ist zwar ein Komponentenbasierter Ansatz, aber eventuell nicht das, was du willst.
Ein Ansatz (den auch der Kollege von t-machine.org vorschlägt) ist es ein "Fat Array" zu verwenden. Das hängt aber von dem Spiel ab. Also wenn deine Objekte sich nicht
wirklich groß unterscheiden in den Attributen, dann fasse alles in einen Struct zusammen:

C-/C++-Quelltext

1
2
3
4
5
6
struct ComponentData {
  Vector2f* positions;
  Vector2f* velocities;
  Texture* textures;
  int num;
}

Wichtig ist, dass Du "SoA" verwendest, damit es "data oriented" ist. Dann kann ein Movesystem so aussehen:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
class MoveSystem {

 void update(ComponentData& data,float dt) {
    Vector2f* position = data.positions;
   Vector2f* velocity = data.velocities;
  for ( int i = 0; i < data.num; ++i ) {
    *position += *velocity * dt;
    ++position;
    ++velocity;
  }
 }
}

Wenn jetzt aber nicht wirklich jedes bewegt werden soll, dann kannst Du noch ein "Mask" oder Bitfeld oder was auch immer definieren, damit die ausgeschlossen werden

C-/C++-Quelltext

1
2
3
4
5
6
7
struct ComponentData {
  Vector2f* positions;
  Vector2f* velocities;
  Texture* textures;
  int num;
  int* componentMask; // bit 0 = move bit 1 = .... bit 2 = ....
}

und dann in einem System checken, ob die passende Bitmask gesetzt ist.
Der Ansatz passt aber nur dann richtig gut, wenn wie gesagt alle Objekte in deinem Spiel auch mehr oder weniger gleich sind.

13

19.01.2015, 16:14

Wichtig ist, dass Du "SoA" verwendest, damit es "data oriented" ist. Dann kann ein Movesystem so aussehen:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
class MoveSystem {

 void update(ComponentData& data,float dt) {
    Vector2f* position = data.positions;
   Vector2f* velocity = data.velocities;
  for ( int i = 0; i < data.num; ++i ) {
    *position += *velocity * dt;
    ++position;
    ++velocity;
  }
 }
}

Von der Idee her schonmal das was ich mir vorstelle :) Nur das FatArray stört mich bisschen :P

Was mir lustigerweise gerade klar wird: Ich habe heute die Aufteilung der Subsysteme etwas geändert und de facto einen Zwischenschritt zwischen strikter Komponententrennung von FatArray gemacht xD Beispielsweise habe ich das Objekt-Behavior der Physik zugeordnet, d.h. Physik macht nun Bewegung, Kollision und die Verwaltung der Verhalten-Flags (Idle, Move, Attack etc.). Das Rendering- und Animationssystem habe ich zum Graphics-System zusammengelegt, d.h. Animieren und Zeichnen in einem System. Dadurch muss die Physik nicht mehr das aktuelle Bewegungsflag erfragen (um festzustellen, ob eine Bewegung ausgeführt werden muss). Und das Animations- und Rendersystem arbeiten quasi verzahnt. Trotzdem muss das neue Grafik-System noch Position und Blickrichtung erfragen (in dem es sich quasi PhysicsData const & pro Objekt holt. Das Input- und das KI-System arbeiten beide ohne weitere Daten (lediglich das Inputsystem braucht weitergeleitete Eingabeevents). Beide propagieren an das Physik-System die beabsichtigten Bewegungen bzw. an das Avatar-System die beabsichtigten Aktionen (Angreifern, Zaubern etc.), so dass die Zielsysteme dann für sich entscheiden können, ob die Bewegung/Aktion im Moment erlaubt ist. Alternativ könnte man auch die Bewegungen zum AvatarSys propagieren, damit das z.B. Stun berücksichtigen kann - und dann schließlich zur Physik weiterleiten.

Mit dem anderen Auge überlege ich gerade wie ich die Daten innerhalb der Systeme organiseren... manche iterieren nur über die Objekte (Input, KI, Avatar), andere iterieren (Bewegung @ Physik, Animation @ Graphics) über die Objekte und wollen einzelne Objekte über ihre Position (Kollision @ Physik, Rendering @ Graphics) erfragen. Für das reine iterieren habe ich im Moment den "contigeous array of data"-Ansatz im Auge, für die Physik eine Mischung mit Quadtree sowie für die Grafik ein diskretes Grid (da 2D Spiel) und eine Lookup-Tabel (um von der ObjektID auf die Position im Grid und dadurch an die Komponente zu kommen - bisschen umständlich aber es sind ja noch nicht alle Messen gelesen ^^).

LG

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Glocke« (19.01.2015, 16:20)


Werbeanzeige