6. diel - 3D bludisko v XNA - Podlahy druhýkrát a kolízie
Vitajte po šestnástej. V tomto diele si vytvoríme cieľovú a štartové podlahu, ktoré budú inak farebné než zvyšné podlahy. Vytvorenie oných podláh nie je tak triviálne ako u podlahy normálne, ale to sa hnedle ukáže. Ďalej sa pozrieme na možnosti kolízií a celý systém premyslíme. Na záver si napíšeme pomocné triedy pre vykreslenie krabice a gule.
Štartovej a cieľová podlaha
Vytvoríme si rovnako ako posledne súbor v priečinku na komponenty. Triedu
opäť nazvite tak ako je vám libo, ja som zvolil
StartovniPodlaha
. Konštruktor zostane rovnaký ako minule:
public StartovniPodlaha(int x, int z): base(new Vector3(x*20+10,0,z*20+10),Matrix.Identity,new Vector3(1.34f),"podlaha") { }
Zatiaľ nie je žiadna podivnosť na obzore. Teraz má ale podlaha rovnaký vzhľad ako podlahy ostatní. Ale my chceme dlaždicu zvýrazniť inou farbou. Máme v zásade dve možnosti. Buď si v modelovacím programu dlaždicu nafarbíme a urobíme si tak nový model a máme po problémoch a alebo si farbu pri vykreslenie upravíme. Prvá možnosť je pre srab a tak si farbu jednoducho zmeníme pri vykreslenie.
Prepíšeme si metódu Draw
s našimi parametrami:
public override void Draw(Matrix View, Matrix Projection, Vector3 CameraPosition)
A nakopírujeme vlastne celý obsah pôvodnej metódy, takže pre prehľad ju tu uvádzam:
Matrix world = Utility.CreateWorld(Pozice, Rotace, Meritko); foreach (ModelMesh mesh in Model.Meshes){ foreach (ModelMeshPart part in mesh.MeshParts){ if (part.Effect is BasicEffect){ BasicEffect efekt = part.Effect as BasicEffect; efekt.View = View; efekt.Projection = Projection; efekt.World = transformace[mesh.ParentBone.Index] * world; efekt.EnableDefaultLighting(); } } mesh.Draw(); }
A pol práca je hneď hotovo. Ešte nezabudnúť nastaviť poli s
transformáciami modifikátor na protected
, rovnako ako som urobil
ja:
protected Matrix[] transformace;
Farbu vykresľovanie plochy zmeníme veľmi ľahko. BasicEffect
na to má priamo premennú DiffuseColor
. Ale tá nie je napodiv
typu Color
ako by sa čakalo, ale Vector3
. Grafická
karta totiž nepracuje s farbami vo formáte 0-255
ale
0-1
a na ich uloženie sa hodí práve Vector3
.
Vector4
sa potom hodia pre farby s alfa kanálom, ale tým sa
zatiaľ nebudeme zaťažovať. Trieda vektora tak dostáva už tretí význam.
Pripomeňme, že prvé bolo určenie pozície a druhý bol vektor potrebné pre
pohyb. Ako ich navzájom previesť nemusíme riešiť. Štruktúra
Color
na to má metódu ToVector3
, ktorú použijeme.
Vector3
ani Color
už ale spätnú metódu nemá. Do
efektu teda priradíme treba svetlomodrou farbu:
efekt.DiffuseColor = Color.Aqua.ToVector3();
Nájdeme si triedu s mapou a do switch
e si pridáme ďalšiu
vetvu s novou podlahou:
case 99:{ c = new StartovniPodlaha(i, j); break; }
Skúsime si výsledok spustiť aby sme videli novú tyrkysovú pohromu, ktorá je rozlezlá po všetkých podlahách.
Dôvod je jasný. XNA
sa snaží šetriť a tak zakaždým, keď
sa pokúsime o nahranie modelu alebo čohokoľvek, tak sa pozrie, či ak sme tak
už neurobili a v prípade že áno nám vráti uloženú inštanciu. To sa nám
veľmi nehodí, celú vec to mierne komplikuje, ale nie je to nič
neprekonateľného. Úplne bude stačiť, keď pri vykreslenie vrátime
pôvodnú farbu. Takže hneď za vykreslenie danej meshe modelu pridáme
ďalšie foreach
cyklus, kde farbu navrátime:
foreach (ModelMeshPart part in mesh.MeshParts){ if (part.Effect is BasicEffect){ BasicEffect efekt = part.Effect as BasicEffect; efekt.DiffuseColor = Color.Blue.ToVector3(); } }
To je všetko. Ak teraz hru spustíme, tyrkysové zostalo len jedno pole a to je to, čo chceme. Úplne rovnako budeme postupovať aj v prípade cieľovej podlahy, iba zvolíme inú výraznú farbu (ja som dal červenú), iné číslo poľa, v tomto prípade 100, a iný názov súboru a triedy.
Kolízie
Vôbec najväčší oriešok, ktorému budeme čeliť, sú kolízie. Ak sa nad tým zamyslíte, tak je možné vyriešiť aj celkom intuitívne. Máme k dispozícii polia s priechodnými a neprůchozími políčkami. Možno tak pohyb hráča vymedziť len a len skrze súradnice. Je to funkčný, je to ľahké. Avšak pri tvorbe enginu, o ktorý sa tak trochu stále viac skryto pokúšam, to nie je moc taktický krok. V akej inej hre toto použijete? Obávam sa, že asi už v žiadnej inej. Má preto asi väčšiu cenu pokúsiť sa o pokročilejšie systém, ktorý na tomto jednoduchom prípadu môžeme vyskúšať, vytvoriť a potom ho len na zložitejšie veci aplikovať a prípadne ho len kvapku rozšíriť.
Základom sú kolízne objekty, ktoré akoby obaľujú naše modely a kolízie zjednodušujú a robia je matematicky uskutočniteľnými v reálnom čase. Zatiaľ sú naše modely veľmi jednoduché, ako do počtu hrán a vrcholov, tak pre kolízie, ale nie vždy to tak s modelmi je. Práve preto sa obaľujú tvarovo a výpočtovo jednoduchšími objekty. Trpíme tým síce na presnosti kolízie, ale za to dostávame kratší výpočtový čas. A to je poväčšinou to hlavné, o čo nám ide, aby hra bežala čo najsvižnejšie. Používajú sa dva zásadné tvary: gule a kocky alebo ak chcete kváder. Pre výpočty je najrýchlejší kolízie gule s guľou. Len sa spočíta vzdialenosť ich stredov. Kvádre, ktorým budem pre istotu hovoriť krabice, už majú výpočet zložitejšie, ale je tu zavedených niekoľko zjednodušujúcich pravidiel.
Krabica používané v XNA
sú osovo orientované. Anglicky
možno hľadať návody a algoritmy pod názvom
axis aligned bounding box
alebo len so skratkou AABB
.
Čo to ale znamená osovo orientované? Slovensky možno povedať že s nimi
nejde rotovať. Ich hrany stále zostávajú rovnobežné s osami herného
sveta. Ako to vyzerá keď sa objekt otáča môžete vidieť na tomto mojom
videu:
Krabice sa nám zväčšuje a opäť
zmenšuje. Nie je to moc dobré, ale čo narobíme. Máme tu ešte guľu, ktorá
sa pre rotujúce objekty hodí viac, pri rotácii je totiž stále rovnaká ale nie zas na všetky druhy
objektov sa hodí. Naše múru by neboli príliš dobre obalitelné gulí.
Naopak pre hráčov sa guľa hodí myslím pomerne dobre. XNA
obsahuje tiež lúč Ray
, ten sa hodí pre strieľanie a klikanie
myšou na objekty za použitia takzvaného ray castingu
. Máme
tiež tiež plochu Plane
. Plocha nie je ničím obmedzená je teda
nekonečne veľká. Ale aj tak ju možno použiť napríklad k ukončeniu
sveta.
Hráča si teda obalíme gulí, múry zas krabicami. Stále je ale počet
výpočtov, ktoré musíme vykonať pri každom volanie metódy
Update
u hracieho okna (tu totiž budeme kolízie počítať),
veľmi veľký. Vezmite si, že máme bludisko 10x10 políčok. To máme celkom
v najhoršom prípade 100 kusov múrov. Hráč môže kolidovať so 100
objektmi, krabice okolo múru s ďalšími 100 a tak ďalej. To je
nepredstaviteľne veľký počet výpočtov. Preto označíme krabica pre múry
za statické a tým tiež ušetríme veľa výpočtového času. Počítať sa
bude teda iba 100 kolízií, ale aj to je pomerne dosť. Existujú metódy,
ktoré nám to môžu razantne zmenšiť, ale tie zatiaľ ponechajme
stranou.
Súvahu ako to to pôjdeme máme teda hotovú. Dosť mi chýba že v návodoch na internete sa zvyčajne len dočítate ako to riešiť, ale prečo takto a nie inak sa už nedozviete. Jednoducho preto. Snažím sa byť v tomto smere iný a svoje myšlienkové pochody (často realizované v posteli pred spaním) v tomto texte prezentovať. Mnohokrát som so svojimi riešeniami narazil na nepochopenie, naposledy výraznejšie na Socci, ale tým že sem bol v štátnom kole sa tu nebudem vyťahovať. Ak vás skôr zaujíma, ako si okopírovať bezmyšlienkovite tých pár riadkov kódu, tak to si budete musieť počkať na inokedy. Nemám tu ešte stále moc jasno ako presne to urobíme, ale už sa obloha protrhávat. Čo viem iste je že bude potreba je krabica a gule, na tie sa pozrieme nabudúce.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 174x (1.75 MB)
Aplikácia je vrátane zdrojových kódov v jazyku C#