Rozdział 1. Wstęp - PolishDocs/Box2D-PL GitHub Wiki

Spis treści:

1.1 O Box2D

Box2D jest biblioteką umożliwiającą dwuwymiarową symulację ciał sztywnych w grach. Programiści mogą z niej skorzystać by nadać obiektom realistyczny ruch i sprawić by świat gry był bardziej interaktywny. Z punktu widzenia silnika gry, silnik fizyczny to tylko system do proceduralnej animacji.

Box2D zostało napisane w przenośnym kodzie C++. Większość typów zdefiniowanych w silniku zaczyna się prefixem „b2”. Mam nadzieję, że wystarczy to by uniknąć konfliktów w nazewnictwie z twoim silnikiem gry.

1.2 Wymagania

W tej dokumentacji zakładam, że znasz podstawowe zagadnienia fizyczne jak masa, siła, moment obrotowy i popęd. Jeśli nie, najpierw uzupełnij wiedzę korzystając z Google i Wikipedii.

Box2D został stworzony jako część kursu fizycznego na Game Developer Conference. Możesz pobrać te kursy z sekcji download na oficjalnej stronie Box2D

Box2D jest napisany w C++, wymaga się więc od ciebie doświadczenia w programowaniu w tym języku. Box2D nie powinno być twoim pierwszym projektem w C++! Kompilacja, linkowanie i debugowanie nie powinny stanowić dla ciebie problemu.

Uwaga Przed pracą z Box2D naucz się programowania w C++.

Jest mnóstwo dobrych źródeł z których możesz się uczyć w internecie. Na przykład cpp0x.pl.

1.3 O tej dokumentacji

Ta dokumentacja pokrywa większość API Box2D. Jednak, nie każdy jego aspekt jest poruszony. Zachęcam cię do zerknięcia na środowisko testowe (testbed), dołączone do Box2D by dowiedzieć się więcej. Baza kodu Box2D posiada komentarze sformatowane pod Doxygen, więc łatwo jest stworzyć dokument opisujący API z hiperłączami.

Ta dokumentacja jest aktualizowana tylko wraz z wyjściem nowej wersji Box2D.

1.4 Wsparcie i informacje o błędach

Jeśli masz pytanie lub chciałbyś podzielić się swoją opinią czy pomysłem, zostaw komentarz na forum. Jest to też świetne miejsce do wszelkiego rodzaju dyskusji.

Problemy i błędy zgłaszaj na GitHubie.

By upewnić się, że błąd na który natrafiłeś zostanie naprawiony, szczegółowo opisz problem. Idealne byłoby podanie kroków potrzebnych do reprodukcji błędu w środowisku testowym, o którym możesz przeczytać w tej dokumentacji.

1.5 Podstawowe pojęcia

Box2D korzysta z kilku fundamentalnych pojęć. Krótko je tutaj przedstawimy, a więcej o nich, dowiesz się w dalszej części dokumentacji.

shape - kształt
Kształt to dwuwymiarowy obiekt geometryczny, taki jak koło czy wielokąt.

rigid body - ciało sztywne
Bryła materii na tyle silnie związana, że odległości między poszczególnymi kawałkami tej materii w bryle są stałe. Jest twarda jak diament. W dalszej częsci dokumentacji używamy terminu ciało wymiennie z terminem ciało sztywne.

fixture - fikstura
Fikstura wiąże kształt z ciałem i nadaje mu materiałowe właściwości takie jak gęstość, tarcie i "odbijalność" ( ang. restitution). Fikstura umieszcza kształt w systemie kolizji (broad-phase), żeby mógł kolidować z innymi kształtami.

constraint - wiązanie
Wiązanie to fizyczne ograniczenie które blokuje płaszczyzny swobody ruchu ciał. Dwuwymiarowe ciało ma 3 płaszczyzny swobody ruchu (dwie współrzędne przesunięcia i jedna współrzędna rotacji). Jeśli przypniemy ciało do ściany za pomocą szpilki (jak wahadło) to stworzyliścmy więzanie ograniczające ruch ciała względem ściany. W takiej sytuacji ciało może tylko obracać się dookoła szpilki, więc wiązanie ogranicza swobodę ruchu ciała na dwóch płaszczyznach.

contact constraint - wiązanie styczności
Wyjątkowy rodzaj wiązania, stworzony by zapobiec penetracji ciał sztywnych i by symulować tarcie i "odbijalnosć". Nie możesz stworzyć wiązania styczności, jest one tworzone automatycznie przez Box2D.

joint - połączenie
Połączenie to wiązanie używane do trzymania dwóch lub więcej ciał razem. Box2D obsługuje kilka typów połączeń: revolute - obrotowe, prismatic - pryzmatyczne, distance - odległości i inne. Niektóre połaczenia mogą mieć granice i motory.

joint limit - granica połączenia
Granica połączenia reguluje zasięg ruchu połączenia. Na przykład, ludzki łokieć umożliwia pewien ograniczony zakres ruchu.

joint motor - motor połączenia
Motor połączenia powoduje ruch połączonych ciał, zgodnie z płaszczyznami swobody ruchu. Na przykład, motor powoduje rotacje łokcia.

world - świat
Fizyczny świat jest zbiorem ciał, fikstur i wiązań które oddziałowują ze sobą. Box2D umożliwia tworzenie wielu światów, jednak nie jest to zazwyczaj potrzebne czy pożądane.

solver - system liczący
Świat fizyczny ma system liczący, który jest używany do postępu czasu i obsługiwania wiązań styczności i połączeń. System liczący w Box2D jest wysoce wydajnym, iteracyjnym systemem o złożoności czasowej O(n), gdzie n jest liczbą wiązań.

continues collision - kolizja ciągła
Postęp czasu w systemie liczącym odbywa się przy użyciu dyskretnych kroków. Bez interwencji może to prowdzadzić do zjawiska zwanego tunnelingiem.

efekt tunnelingu
Box2D posiada specjalne algorytmy by móc radzić sobie z tunnelingiem. Po pierwsze, algorytmy kolizyjne mogą posłużyć się interpolacją ruchu dwóch ciał by wyznaczyć czas kolizji (ang. time of impact - TOI). Po drugie, istnieje system który przesuwa ciała na pozycje ich pierwszego kontaktu i dopiero wtedy obsługuje kolizje.

1.6 Moduły

Box2D składa się z trzech modułów: Common, Collision i Dynamics. Moduł Common zawiera kod do alokacji, obliczeń matematycznych i ustawień. Moduł Collision zawiera definicje kształtów, i funkcji odpowiedzialnych za kolizje. A moduł Dynamics odpowiedzialny jest za symulacje świata, ciał, fikstur i połączeń.

Dynamics <- Common -> Collision -> Dynamics

1.7 Jednostki

Box2D operuje na liczbach zmiennoprzecinkowych. Aby Box2D było w stanie dobrze spełniać swoje zadanie musiał zostać wprowadzony pewien zakres tolerancji dla wielkości obiektów. Ten zakres tolerancji został dostosowany do pracy z jednostkami metr-kilogram-sekunda (MKS). Konkretnie, Box2D został dostosowany do pracy z kształtami o wielkości między 0.1 a 10 metrów. Oznacza to, że obiekty o wielkości nie mniejszej niż puszka zupy i nie większej niż autobus, będą dobrze współpracowały z silnikiem. Obiekty statyczne (nie poruszające się), mogą mieć długość nawet do 50 metrów.

Biorąc pod uwagę fakt, że Box2D operuje w dwuwymiarowym świecie, intuicyjne wydaje się korzystanie z pikseli jako jednostki. Niestety, prowadzi to do obniżenia jakości symulacji i możlwości wystąpienia dziwnych zachowań. Obiekt o długości 200 pikseli zostałby zinterpretowany przez Box2D jako 45 piętrowy budynek.

Uwaga Box2D jest przystosowany do układu jednostek MKS. Utrzymuj rozmiar poruszających się obiektów mniej więcej w granicach 0.1 - 10 metrów. Będziesz potrzebować jakiegoś systemu skalowania do renderowania tych obiektów. NIE UŻYWAJ PIKSELI.

O ciałach w Box2D najlepiej jest myśleć jako poruszających się bilbordach, na których możesz umieścić swoje grafiki. Bilbord porusza się w systemie metrycznym jednak możesz skonwertować położenie w metrach na współrzędne w pikselach, korzystając z współczynnika skali. Mając dostęp do współrzędnych w pikselach możesz odpowiednio rozmieścić swoje sprite'y itp.

Box2D korzysta z radianów do wyrażania kątów. Rotacja ciała przechowywana jest w radianach i może rosnąć w nieskończonść. Rozważ normalizację kątów rotacji swoich ciał jeśli kąt staje się zbyt duży (użyj b2Body::SetAngle).

Uwaga Box2D wyraża kąty w radianach, nie stopniach.

1.8 Fabryki i definicje

Szybkie zarządzanie pamięcią odgrywa główną rolę w projekcie API Box2D. Jeśli tworzysz b2Body lub b2Joint musisz wywołać funkcję tworzącą obiekt na rzecz b2World. Nie powinieneś próbować alokacji tych typów w żaden inny sposób.

Oto funkcje tworzące obiekt:

b2Body* b2World::CreateBody(const b2BodyDef* def); 
b2Joint* b2World::CreateJoint(const b2JointDef* def);

A to odpowiadające nim funkcje usuwające obiekt:

void b2World::DestroyBody(b2Body* body);
void b2World::DestroyJoint(b2Joint* joint);

Gdy tworzysz ciało lub połączenie musisz je najpierw zdefiniować w kodzie. Te definicje zawierają wszelkie dane potrzebne do stworzenia ciała lub połączenia. To podejście zapobiega błędom przy tworzeniu obiektów, utrzymuje małą liczbę parametrów funkcji, zapewnia sensowne wartości domyślne i redukuje liczbę akcesorów (getterów).

Fikstury(kształty) muszą być przypisane do ciała, więc są tworzone i usuwane za pomocą funkcji wywoływanych na rzecz b2Body:

b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def);
void b2Body::DestroyFixture(b2Fixture* fixture);  

A to skrócony sposób stworzenia fikstury bezpośrednio z kształtu i gęstości:

b2Fixture* b2Body::CreateFixture(const b2Shape* shape, float32 density);  

Fabryki nie przechowują referencji do definicji. Możesz więc definiować obiekty na stosie i trzymać je w pamięci.

⚠️ **GitHub.com Fallback** ⚠️