Autor Wątek: komponenty  (Przeczytany 7491 razy)

Offline Xender

  • Użytkownik

# Czerwiec 03, 2015, 20:28:45
No to teraz mamy "wzorzec projektowy" "Wiele PImpl w jednej klasie". o_O
// No dobra, nie do końca nawet to.

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline ArekBal

  • Użytkownik

# Czerwiec 03, 2015, 20:45:34
Xender, Xirdus

O czym wy gadacie?
Znowu honor warsztatu się odzywa?

Dobrze chłop kombinuje. Rezygnuje z dziedziczenia więc nie OOP, ale są obiekty więc da się tym jako tako dysponować. Będzie z tym trochę kłopotu, ale nic czego makrami i "template"ami w tym smutnym języku nie udało by się załatać(btw. nie znam "prawie" żadnego języka który implementuje SOA jako "feature" :/).

To zawsze będzie jakiś kompromis. I w jego wypadku wygoda-, szybkość+ i pamięć+

Ja swego czasu kombinowałem coś podobnego, tylko że planowałem mieć offsety i długości na wektorach dla obsługi różnych typów.
coś jakby
struct InternalTypesSOA
{
  types;
  positions;
  velocities;
  aabbs;
  weights;
  whatevereas;
 
  bulletsOffset;
  bulletsLength;
  lightsOffset;
  lightsLength;

  //..etc.
}
Celem jest coś takiego(cyferki oznaczają różne typy, 0 oznacza offset):

11111111111111111111222222222233333334444444445555 <= positions
11111111111111111111222222222233333334444444445555 <= velocities
1111111111111111111122222222223333333 <= aabbs
111111111111111111112222222222 <= weights
0000000000000000000000000000000000000444444444 <= whatevereas

Mamy hierarchię... pewnych rodzajów relacji tutaj się nie wyrazi ale jest pewien wachlarz możliwości, a 'stosunkowo pełne' DOD.

W samym kodzie wygląda to jak spory hack ale idąc tą drogą(że to hacki i w ogóle) to można się zapytać jak dostępnymi w c++ abstrakcjami wyrazić Sparse Distributed Memory Model(wiem że trochę od bani pytanie... ;)).
« Ostatnia zmiana: Czerwiec 03, 2015, 21:10:52 wysłana przez ArekBal »

Offline Xender

  • Użytkownik

# Czerwiec 03, 2015, 23:16:50
@up - Ta, tylko teraz każdą kombinację komponentów musi wyrazić jako osobny struct.

Co jest mocną regresją w stosunku do ECS przedstawianego w artykułach.

A przykład, który podałeś, nie "trochę", lecz nawet zupełnie do bani.
Idąc tą drogą, można by zapytać, jak dostępnymi w C++ abstrakcjami wyrazić sens życia, wszechświata i wszystkiego.


Może po prostu czas porozglądać się po necie w poszukiwaniu tego, problem odpowiedniej struktury danych do ECS rozwiązuje się w dużych produkcjach/silnikach?

Offline ArekBal

  • Użytkownik

# Czerwiec 04, 2015, 01:09:15
A może facepalm po raz kolejny... mnie już starczy...

Offline Astisus

  • Użytkownik
    • Portfolio

  • +8
# Czerwiec 04, 2015, 11:17:17
Idąc tą drogą, można by zapytać, jak dostępnymi w C++ abstrakcjami wyrazić sens życia, wszechświata i wszystkiego.

To chyba nie jest zbyt trudne ;)
int answer = 42;

Offline Xirdus

  • Redaktor

  • +2
# Czerwiec 04, 2015, 13:33:03
Xirdus

O czym wy gadacie?
O tym, że jeśli OP nie zweryfikuje swojego podejścia to zachlasta się na śmierć i nigdy nie skończy żadnej większej gry.

Rezygnuje z dziedziczenia więc nie OOP
OOP to nie tylko dziedziczenie. Ale to tak na marginesie.

To zawsze będzie jakiś kompromis. I w jego wypadku wygoda-, szybkość+ i pamięć+
Względem normalnego ECS to rzeczywiście pamięć na plus, ale szybkość jednak trochę na minus - niejednolite struktury danych dają ten minimalny dodatkowy narzut. A wygoda to z powodów które wcześniej podałem, leci tak mocno w dół że dla mnie byłoby nieużywalne. A wygoda to często najważniejszy parametr z tych trzech.

Offline kapustman

  • Użytkownik

# Czerwiec 05, 2015, 00:23:59
Ta, tylko teraz każdą kombinację komponentów musi wyrazić jako osobny struct.

Co jest mocną regresją w stosunku do ECS przedstawianego w artykułach.

Wszystko ma swoje wady i zalety. Jak wybiorę ECS, to są duże problemy z fragmentacją pamięci. Jak wybiorę tą hybrydę,  to muszę zakodować struktury wszystkich interesujących mnie obiektów, i nie można dynamicznie tworzyć nowych typów.

Może po prostu czas porozglądać się po necie w poszukiwaniu tego, problem odpowiedniej struktury danych do ECS rozwiązuje się w dużych produkcjach/silnikach?


Mapowanie przy użyciu tablic/list/hash map(pamięć jest tylko trochę mniej posiekana). Hybrydy. Stosowanie DOD tylko w krytycznych fragmentach kodu.

http://t-machine.org/index.php/2014/03/08/data-structures-for-entity-systems-contiguous-memory/
http://bitsquid.blogspot.com/2014/09/building-data-oriented-entity-system.html
https://molecularmusings.wordpress.com/2013/07/24/adventures-in-data-oriented-design-part-3c-external-references/


Musisz teraz mieć osobny kod przemieszczania kul, osobny kod przemieszczania gracza, osobny przeciwników, osobny obiektów otoczenia itd. I tak z każdą jedną pierdołą. Nie mówiąc już jak się namachasz z kolizjami... Bardzo złe rozwiązanie.

A w OOP tak nie jest? Interface,dziedziczenie i funkcje wirtualne? Dla większości obiektów muszę napisać oddzielną funkcję Update(), itp.
Kolizje? To samo.I tak się namacham,lub trzymanie wszystkiego w tablicy wskaźników/liście + dynamic_cast.

void add(float* a,const float* b,unsigned count)
{
      for(unsigned i = 0; i < count;++i)
           a[i] += b[i];
}

//wersja ECS + DOD (wersja najprostsza,z "dziurami")
add(pos,vel,active);
add(vel,acc,active); // <- jaki branching?
update_AI(ai,...,active);
update_Input(input,active);
//...

//hybryda
//kule
add(bullets.pos,bullets.vel,bullets.active);

//rakieta
add(rocket.pos,rocket.vel,rocket.active);
add(rocket.vel,rocket.acc,rocekt.active);
//...
« Ostatnia zmiana: Czerwiec 05, 2015, 00:33:15 wysłana przez kapustman »

Offline Xirdus

  • Redaktor

# Czerwiec 05, 2015, 01:04:39
A w OOP tak nie jest? Interface,dziedziczenie i funkcje wirtualne? Dla większości obiektów muszę napisać oddzielną funkcję Update(), itp.
Sensownie zrobiony OOP (tak że nie ma potrzeby robić downcastów) minimalizuje duplikację kodu - nie masz osobnej pętli dla każdej pary typów, tylko naraz wszystko opitalasz (mając heterogeniczny kontener), a dodatkowy kod masz tylko kiedy naprawdę ma być inny kod. Podobnie z ECS, z tym że nie masz żadnych heterogenicznych kontenerów tylko wszystko jest jednolite - i jak iterujesz po wszystkich elementach jednego typu (bardzo częsta operacja) to nie musisz się nawet bawić w żadne ID obiektu itp.

Swoją drogą, nie jestem zwolennikiem OOPu w Javowym wydaniu.

Offline Kos

  • Użytkownik
    • kos.gd

# Czerwiec 05, 2015, 12:48:40
Jak wybiorę tą hybrydę,  to muszę zakodować struktury wszystkich interesujących mnie obiektów, i nie można dynamicznie tworzyć nowych typów.

No i tu bym polemizował. Zależy trochę gry, ale generalnie powinieneś móc zrobić 2-3 generyczne 'kategorie' obiektów, które rzeczywiście skorzystają z innej struktury ("prawdziwe" game objecty z fizyką and whatnot, małe obiekty tymczasowe jak pociski czy eksplozje, sceneria, itemy które się przechowuje...) i wtedy w ramach jednej kategorii masz bardzo dużo swobody. Taki Quake miał bodaj dwie ketegorie: geometrię mapy i wszystko inne.

Offline Xirdus

  • Redaktor

# Czerwiec 05, 2015, 13:10:56
Taki Quake miał bodaj dwie ketegorie: geometrię mapy i wszystko inne.
Właśnie się trochę dziwiłem że jeszcze Krzysiek K. nie wyjechał ze swoim sztandarowym tekstem że w Quake'u wszystkie obiekty były jednego typu i zawierały wszystkie możliwe parametry nawet jak trzy czwarte nie było potrzebne, i sprawowało się to bardzo dobrze :)

Offline Kos

  • Użytkownik
    • kos.gd

# Czerwiec 05, 2015, 13:32:09
Krzysiek zawsze mówił że był jeden typ, a to nieprawda, bo obiektem nie była mapa. I to jest bardzo ważna obserwacja: nie musi być jedna generyczna kategoria, może być N, każda na obiekty "fundamentalnie różne", czyli potrzebujące zupełnie innych komponentów. Gdyby Quake miał system przedmiotów jak w Diablo, to pewnie dostałby jeszcze trzecią kategorię na przedmioty które można nosić.