Identyfikowanie „typów” jednostki w systemie jednostek-elementów

10

Jeśli jednostka nie ma wyraźnego „typu” (np. Odtwarzacz) i jest po prostu zbiorem komponentów, w jaki sposób mogę zidentyfikować jednostki, nad którymi moje systemy powinny i nie powinny pracować? Na przykład w grze Pong wiosło i piłka zderzają się z granicami okna. Jednak systemy obsługi kolizji dla każdego będą inne, dlatego system nie powinien obsługiwać jednostek niewłaściwego typu.

void PlayerCollisionSystem::update(std::vector<Entity *> entities) {
  typedef std::vector<Entity *>::iterator EIter;
  for (EIter i = entities.begin(); i != entities.end(); ++i) {
    Entity *player = *i; // How do I verify that the entity is a player?

    // Get relevant components.
    PositionComponent *position = player->getComponent<PositionComponent>();
    VelocityComponent *velocity = player->getComponent<VelocityComponent>();
    SpriteComponent *sprite = player->getComponent<SpriteComponent>();

    // Detect and handle player collisions using the components.
  }
}

Zarówno zawodnik, jak i piłka mają te same istotne typy elementów do obsługi kolizji, ale ich implementacje systemu będą się różnić.

Jeśli mam kontener wszystkich encji w grze, w jaki sposób mogę zidentyfikować określone typy encji bez dziedziczenia Entitylub uwzględnienia zmiennej członka, takiej jak std::string type, w którym to przypadku encja nie jest już tylko zbiorem komponentów?

Garee
źródło

Odpowiedzi:

21

Odpowiedź Nicola Bolasa jest prosta, ale odsuwając się na bok i patrząc na problem z dystansu: naprawdę nie potrzebujesz typu bytu.

Musisz tylko dbać o to, czy „obiekt ma komponent X”, czy nie, a Twoim problemem jest to, że nie zostałeś poprawnie zidentyfikowany X. Jeśli dwa obiekty zachowują się inaczej, podaj im różne komponenty lub po prostu umieść na nich flagę boolowską, aby działały inaczej dla różnych konfiguracji obiektów. Skorzystaj z systemu komponentów, aby podejmować decyzje dotyczące zachowania, a nie „typu” encji. Taki jest sens używania komponentów.

Możesz całkowicie mieć PaddlePhysicskomponent / system i oddzielny BallPhysicskomponent / system, jeśli zachowują się inaczej. Lub możesz rozbić komponenty na bardziej szczegółowe cząstki, tak że masz Bouncekomponent, który ma tylko Ball, i StopAtBoundarykomponent, który oba, Balli który Paddlema, jeśli część zachowania jest wystarczająco skomplikowana, aby uzasadnić udostępnienie kodu. Lub możesz po prostu stworzyć PongPhysicskomponent, który ma Bouncesustawioną flagę logiczną truedla Balli falsedla Paddle. Możesz nawet stworzyć WallCollisionkomponent podstawowy , a następnie uzyskać ten komponent, aby uzyskać BallWallCollisiondodatkowe zachowanie, które jest tam potrzebne.

Sean Middleditch
źródło
4
Myślę, że powinna to być zaakceptowana odpowiedź, ponieważ absolutnie nie ma żadnych ograniczeń ani problemów z ECS „waniliowym”. Znaczniki można łatwo osiągnąć, tworząc dedykowane komponenty, które służą jako znaczniki. Może to być również atrapa PlayerTypeComponent, która nie robi nic pożytecznego, a jedynie służy jako tag.
tiguchi
19

System jest użyteczny tylko wtedy, gdy jest użyteczny. Jeżeli system, w którym dany podmiot jest „po prostu zbiorem elementów” jest mniej przydatny niż system, w którym jednostka jest głównie jako „zbiór elementów”, a następnie zrobić .

Przestań próbować tworzyć „czyste” systemy i skup się na tworzeniu dobrych , które robią to, czego potrzebujesz. Używaj komponentów, dopóki nie będą już dla ciebie przydatne. Następnie użyj czegoś innego.

Już spędziłeś więcej czasu na myśleniu o tym, niż na to zasługuje.

Nicol Bolas
źródło
bardzo fajnie +1 „Spędziłeś już więcej czasu na myśleniu o tym, niż na to zasługuje”
wes
8
Nie sądzę, żeby to była odpowiedź. Temat udoskonalenia ECS zasługuje na znaczną uwagę, a Garee (kiedy opublikował to w 2013 r.) Prawdopodobnie nie spędził wystarczająco dużo czasu na myślenie o tym. Pogląd, że temat nie zasługuje na więcej czasu, sugeruje, że systemy powinny być proste lub trywialne i ogólnie nie zasługują na nasz czas. Wolałbym odpowiedź Seana Middleditcha, ponieważ faktycznie próbuje odpowiedzieć na pytanie, zamiast je odrzucić.
Gavin Williams,
Świetna odpowiedź. Czasami muszę to sobie powiedzieć. Skoncentruj się na ruchu do przodu.
Dominic Bou-Samra
5

Jeśli chcesz nadać jednostkom jawny typ, najprostszym sposobem jest zdefiniowanie zmiennej typu w klasie jednostek. Zachowaj wzór EC tylko tak długo, jak jest to użyteczne.

W przeciwnym razie typ jest sugerowany przez atrybuty komponentu. Na przykład element fizyki miałby atrybut dla urządzeń mobilnych i stacjonarnych. System wie, kiedy zderzą się dwa telefony komórkowe (piłka i wiosło). Podobnie możesz mieć atrybuty określające sposób reakcji systemu kolizji. Zatrzymać obiekt czy go odbić? Patrzenie na atrybuty powinno dać ci wyobrażenie o tym, czym jest byt, ale powinno być nieistotne. Systemy nie powinny wiedzieć, z jakim typem jednostki pracują, powinny otrzymać wystarczającą ilość informacji za pomocą dostarczonych im komponentów.

Wreszcie można dodać dodatkowy komponent, który zawiera typ, ale podobnie jak w przypadku dodawania typu do encji, skończy się pisanie dużej ilości kodu specyficznego dla typu, co pokrzyżuje cel systemu WE.

MichaelHouse
źródło
0

Jednostka to zestaw komponentów. Nie można przypisać zgrabnych etykiet do losowego zestawu. Rezygnacja z ograniczeń typu jest ceną za dużą elastyczność.

Oczywiście możesz mieć specjalne (typowane) klasy jednostek, które nakładają ograniczenia na komponenty.

Idealnie komponenty są niezależne. Rozwiązaniem problemu byłoby wywołanie obsługi kolizji w każdym podskładniku, w odpowiedniej kolejności. W rzeczywistych aplikacjach występują współzależności i problemy z porządkowaniem. W takim przypadku potrzebujesz logiki „dyspozytora” w każdej metodzie klasy Entity.

Karl
źródło