Tanky projíždějící zdmi nejsou to pravé pro opravdovou hru. Dnes tedy přidáme detekci kolizí a rovněž trochu zábavy v podobě střel a explozí.
Obsah dílu:
1. základy detekce kolizí
2. kolize ve hře
3. střílení
4. exploze
Nejčastější úlohou, pro kterou detekci kolizí používáme, je zajistit, aby tělesa ve virtuální scéně skrze sebe volně neprocházela. V každém případě mají algoritmy detekce kolizí tendenci být výkonově velmi náročně a téměř nikdy se neobejdeme bez optimalizací.
Nejzákladnější optimalizací pro kolizní algoritmy je použití modelů s velmi redukovaným počtem trojúhelníků. Modely, které použijeme, jsou zobrazemy na následujících obrázcích:
Proč je počet trojúhelníků tak kritický? Protože při hledání kolize se hledají průniky každého trojúhelníku s každým trojúhelníkem druhého tělesa. Zredukujeme-li počet trojúhelníků desetkrát pro kolizní tělesa, získáme stokrát nižší časovou náročnost.
V praxi existují i určité optimalizace. Například Inventor obaluje všechny tělesa "bounding boxem" (čti baunding box), česky: ohraničující kvádr, či obalové těleso. Inventor nejprve testuje tato obalová tělesa a teprve, když zjistí jejich průnik, porovnává tělesa trojúhelník po trojúhelníku.
Použití uvedených dvou optimalizací, tedy obalových těles a kolizních těles s redukovaným počtem trojúhelníků, redukovalo časovou náročnost kolizních algoritmů do té míry, že další optimalizace už nebyly nutné.
Byl však objeven jeden chyták: Při testování jedné aplikace nám detekce kolizí neustále hlásila, že ke kolizi došlo, přestože na obrazovce se vše zdálo v pořádku a všechna tělesa byla od sebe dostatečně daleko, aby nebylo nejmenších pochyb, že bylo něco přehlédnuto. Po chvilce debugování bylo zjištěno, že všechny kolidující dvojce trojúhelníků nepatří dvěma různým tělesům, jak by se očekávalo, ale byly to trojúhelníky téhož tělesa. Po chvilce zmatení se objevilo vysvětlení: těleso bylo složeno z více So(Indexed)TriangleStripSetu uspořádaných tak, že mezi některými trojúhelníky docházelo ke kolizi. Přesněji řečeno: trojúhelníky patřící do jednoho So(Indexed)TriangleStripSetu kolizi nezpůsobí, pouze trojúhelníky patřící různým So(Indexed)TriangleStripSetům, které se protínají. Samozřejmě se daná vlastnost netýká pouze So(Indexed)TriangleStripSet, ale všech tříd odvozených od SoShape.
Výše řečený chyták se objevil i u modelu bludiště. Zde je problém ošetřen "filtrovací funkcí", kterou si ukážeme později a která zabrání detekovat kolize mezi So(Indexed)TriangleStripSety patřící jednomu tělesu. Alternativní řešení by bylo překonvertovat celou geometrii tělesa do jediného So(Indexed)TriangleStripSetu.
Pro detekci klizí slouží třída SoIntersectionDetectionAction, která je odvozena od SoAction. Základní metodou pro její použití je, podobně jako u všech akcí, metoda apply:
void SoIntersectionDetectionAction::apply(SoNode *root);
Tato metoda projde celý graf scény, jehož kořen je dán parametrem root. Přitom to nutně nemusí být graf totožný s rendrovacím grafem, ale může to být graf speciálně zoptimalizovaný pro učely kolizních algoritmů.
Metoda apply hledá v grafu všechny trojúhelníky a testuje jejich průnik. V Inventoru byla zavedena konvence, že pouze třídy odvozené od SoShape mohou obsahovat geometrii těles. Každá takováto třída přitom umí překonvertovat svůj obsah na trojúhelníkovou podobu a to i třídy, které normálně trojúhelníkovou reprezentaci neuchovávají (NURBS plochy a podobně). Získané trojúhelníky jsou pak použity pro detekci kolizí. A jak již bylo naznačeno dříve, trojúhelníky jednoho SoShape objektu nejsou testovány na kolize, pouze trojúhelníky různých SoShape objektů.
Je-li kolize detekována, je zavolán callback. V něm může uživatel získat informaci o kolidujících trojúhelnících, nebo například nastavit boolean indikující existenci kolize ve scéně.
V Tancích kvůli kolizím používáme dva grafy scény:
SoSeparator *rootkolize; SoSeparator *bludisteKolize;
Graf scény pak konstruujeme dvakrát - jednou pro renrování a jednou pro kolize. Často se liší pouze v názvu souboru, ze kterého byla načtena geometrie tělesa:
this->model->name.setValue("models/tank.wrl"); this->modelKolize->name.setValue("models/tankkolize.wrl");
Některé nody jsou mezi grafy sdíleny, jako například translace tanku:
// posunuti tanku this->trans = new SoTranslation; this->root->addChild(this->trans); this->rootKolize->addChild(this->trans);
Další detaily již najdeme ve zdrojácích.
Pro kolize používáme tři různé akce:
SoIntersectionDetectionAction *ida; //testovani kolizi tanku s bludistem SoIntersectionDetectionAction *ida2; //testovani kolizi strely s bludistem a tanky SoIntersectionDetectionAction *ida3; //testovani kolizi mezi tanky
Teoreticky by stačila pouze jedna třída, ale celá věc byla implementována jinak. Detaily můžeme najít ve funkci nazvané prepocitejScenu. Ta pracuje v těchto krocích:
Je-li stisknuta klávesa pro střílení, je při aktualizaci scény vytvořen nový objekt střely. Inicializace střely je provedena v metodě Strela::start() a její pseudo-kód je následující:
modelStrely->setPosition(tankPosition); modelStrely->setDirection(tankRotation, hlavenSmer); korenSceny->addChild(modelStrely);
Dále už je pozice střely pouze aktualizována podle rovnice balistické střely v metodě Strela::refresh().
Naše exploze bude vytvořena billboardem, na který bude nanesena animovaná textura. Ve skutečnosti se jedná o jedinou texturu obsahující 16 obrázků animované exploze. Tuto texturu si můžete sami vytvořit na stránkách: http://www.geocities.com/starlinesinc/index.html
Pro efekt animované exploze potřebujeme texturu korektně namapovat na náš billboard. Celé střídání jednotlivých obrázků je realizováno změnou texturovacích souřadnic. Textury měníme v metodě Vybuch::refresh(). Nastavují-li se korektně, textury se postupně střídají a vytvářejí efekt exploze.
Zájemci o další věci jako zvuk, síťová hra, umělá inteligence, bump-mapping, ovládání myší a další věci, jejichž předzvěst ukazuje následující screenshot:
se mohou podívat na oficiální stránky projektu. K tomu je přidána i kopa dalších užitečných linků:
Tímto tento tutoriál končí a bude následovat tutoriál o OSG nebo-li OpenSceneGrafu, což je jiná knihovna pro 3D grafiku.
zdrojáky: 5-2-Tanky-2.zip
tutoriál: tutorial13.zip