Lekce 6 - 3D bludiště v XNA - Podlahy podruhé a kolize
Vítejte po šestnácté. V minulé lekci, 3D bludiště v XNA - Dokončení editoru map, jsme dokončili náš editor map.
V tomto díle si vytvoříme cílovou a startovní podlahu, které budou jinak barevné než zbylé podlahy. Vytvoření oněch podlah není tak triviální jako u podlahy normální, ale to se hnedle ukáže. Dále se podíváme na možnosti kolizí a celý systém promyslíme. Na závěr si napíšeme pomocné třídy pro vykreslení krabice a koule.
Startovní a cílová podlaha
Vytvoříme si stejně jako posledně soubor ve složce na komponenty.
Třídu opět nazvěte tak jak je vám libo, já jsem zvolil
StartovniPodlaha
. Konstruktor zůstane stejný jako minule:
public StartovniPodlaha(int x, int z): base(new Vector3(x*20+10,0,z*20+10),Matrix.Identity,new Vector3(1.34f),"podlaha") { }
Zatím není žádná podivnost na obzoru. Nyní má ale podlaha stejný vzhled jako podlahy ostatní. Ale my chceme dlaždici zvýraznit jinou barvou. Máme v zásadě dvě možnosti. Buď si v modelovacím programu dlaždici nabarvíme a uděláme si tak nový model a máme po problémech a nebo si barvu při vykreslení upravíme. První možnost je pro sraby a tak si barvu jednoduše změníme při vykreslení.
Přepíšeme si metodu Draw
s našimi parametry:
public override void Draw(Matrix View, Matrix Projection, Vector3 CameraPosition)
A nakopírujeme vlastně celý obsah původní metody, takže pro přehled ji zde uvádím:
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 půl práce je hned hotovo. Ještě nezapomenout nastavit poli s
transformacemi modifikátor na protected
, stejně jako jsem udělal
já:
protected Matrix[] transformace;
Barvu vykreslované plochy změníme velmi snadno. BasicEffect
na to má přímo proměnnou DiffuseColor
. Ale ta není kupodivu
typu Color
jak by se čekalo, ale Vector3
. Grafická
karta totiž nepracuje s barvami ve formátu 0-255
ale
0-1
a na jejich uložení se hodí právě Vector3
.
Vector4
se pak šikne pro barvy s alfa kanálem, ale tím se zatím
nebudeme zatěžovat. Třída vektoru tak dostává už třetí význam.
Připomeňme, že první bylo určení pozice a druhý byl vektor třeba pro
pohyb. Jak je navzájem převést nemusíme řešit. Struktura
Color
na to má metodu ToVector3
, kterou použijeme.
Vector3
ani Color
už ale zpětnou metodu nemá. Do
efektu tedy přiřadíme třeba světlemodrou barvu:
efekt.DiffuseColor = Color.Aqua.ToVector3();
Najdeme si třídu s mapou a do switch
e si přidáme další
větev s novou podlahou:
case 99:{ c = new StartovniPodlaha(i, j); break; }
Zkusíme si výsledek spustit abychom viděli novou tyrkysovou pohromu, která je rozlezlá po všech podlahách.
Důvod je jasný. XNA
se snaží šetřit a tak pokaždé, když
se pokusíme o nahrání modelu nebo čehokoliv, tak se podívá, zda-li jsme
tak již neučinili a v případě že ano nám vrátí uloženou instanci. To
se nám moc nehodí, celou věc to mírně komplikuje, ale není to nic
nepřekonatelného. Úplně bude stačit, když při vykreslení navrátíme
původní barvu. Takže hned za vykreslení dané meshe modelu přidáme další
foreach
cyklus, kde barvu navrátíme:
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še. Pokud nyní hru spustíme, tyrkysové zůstalo jen jedno pole a to je to, co chceme. Úplně stejně budeme postupovat i v případě cílové podlahy, pouze zvolíme jinou výraznou barvu (já jsem dal červenou), jiné číslo pole, v tomto případě 100, a jiný název souboru a třídy.
Kolize
Vůbec největší oříšek, kterému budeme čelit, jsou kolize. Pokud se nad tím zamyslíte, tak je lze vyřešit i zcela intuitivně. Máme k dispozici pole s průchozími a neprůchozími políčky. Lze tak pohyb hráče vymezit jen a pouze skrze souřadnice. Je to funkční, je to snadné. Ovšem při tvorbě enginu, o který se tak trochu stále více skrytě pokouším, to není moc taktický krok. V jaké jiné hře toto použijete? Obávám se, že asi už v žádné jiné. Má proto asi větší cenu pokusit se o pokročilejší systém, který na tomto snadném případu můžeme vyzkoušet, vytvořit a pak jej jen na složitější věci aplikovat a případně jej jen kapku rozšířit.
Základem jsou kolizní objekty, které jakoby obalují naše modely a kolize zjednodušují a dělají je matematicky uskutečnitelnými v reálném čase. Zatím jsou naše modely velmi snadné, jak do počtu hran a vrcholů, tak pro kolize, ale ne vždy to tak s modely je. Právě proto se obalují tvarově a výpočetně snazšími objekty. Trpíme tím sice na přesnosti kolize, ale za to dostáváme kratší výpočetní čas. A to je povětšinou to hlavní, o co nám jde, aby hra běžela co nejsvižněji. Používají se dva zásadní tvary: koule a krychle nebo chcete-li kvádr. Pro výpočty je nejrychlejší kolize koule s koulí. Jen se spočítá vzdálenost jejich středů. Kvádry, kterým budu pro jistotu říkat krabice, již mají výpočet složitější, ale je zde zavedeno několik zjednodušujících pravidel.
Krabice používané v XNA
jsou osově orientované. Anglicky
lze hledat návody a algoritmy pod názvem
axis aligned bounding box
nebo jen se zkratkou AABB
.
Co to ale znamená osově orientované? Česky lze říct že s nimi nejde
rotovat. Jejich hrany stále zůstávají rovnoběžné s osami herního světa.
Jak to vypadá když se objekt otáčí můžete vidět na tomto mém
vídeu:
Krabice se nám zvětšuje a opět zmenšuje. Není to moc dobré, ale co
naděláme. Máme tu ještě kouli, která se pro rotující objekty hodí
více, při rotaci je totiž stále stejná ale ne zas na všechny druhy
objektů se hodí. Naše zdi by nebyly příliš dobře obalitelné koulí.
Naopak pro hráče se koule hodí myslím poměrně dobře. XNA
obsahuje také paprsek Ray
, ten se hodí pro střílení a
klikání myší na objekty za použití takzvaného ray castingu
.
Máme také také plochu Plane
. Plocha není ničím omezena je
tedy nekonečně velká. Ale i tak ji lze použít třeba k ukončení
světa.
Hráče si tedy obalíme koulí, zdi zas krabicemi. Stále je ale počet
výpočtů, které musíme provést při každém volání metody
Update
u herního okna (zde totiž budeme kolize počítat), velmi
velký. Vezměte si, že máme bludiště 10x10 políček. To máme celkem v
nejhorším případě 100 kusů zdí. Hráč může kolidovat se 100 objekty,
krabice kolem zdi s dalšími 100 a tak dále. To je nepředstavitelně velký
počet výpočtů. Proto označíme krabice pro zdi za statické a tím také
ušetříme spoustu výpočetního času. Počítat se bude tedy pouze 100
kolizí, ale i to je poměrně dost. Existují metody, které nám to mohou
razantně zmenšit, ale ty prozatím ponechme stranou.
Rozvahu jak to to půjdeme máme tedy hotovu. Dost mi chybí že v návodech na internetu se obvykle jen dočtete jak to řešit, ale proč takto a ne jinak se už nedozvíte. Prostě proto. Snažím se být v tomto směru jiný a své myšlenkové pochody (často realizované v posteli před spaním) v tomto textu prezentovat. Mnohokráte jsem se svými řešeními narazil na nepochopení, naposled výrazněji na sočce, ale tím že sem byl ve státním kole se zde nebudu vytahovat. Pokud vás spíš zajímá, jak si okopírovat bezmyšlenkovitě těch pár řádek kódu, tak to si budete muset počkat na jindy. Nemám zde stále ještě moc jasno jak přesně to uděláme, ale už se obloha protrhává.
Co vím jistě je, že bude potřeba je krabice a koule, na ty se podíváme příště, 3D bludiště v XNA - Krabice a koule.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 174x (1.75 MB)
Aplikace je včetně zdrojových kódů v jazyce C# XNA