Klávesnice a myš v XNA

5. díl - Klávesnice a myš v XNA

Tomáš Herceg       30. 3. 2008       VB.NET, XNA       8323 zobrazení

Po delší odmlce přichází další díl oblíbeného seriálu o XNA frameworku a jeho používání z VB.NET. V tomto díle se naučíme zpracovávat vstup uživatele, konkrétně stisky kláves a pohyby myši. Naprogramujeme si hru, ve které se můžete projet na jednorožci po krajině.

V minulém díle jsme se naučili pracovat se světlem a s texturami, dnes se naučíme zpracovávat vstup uživatele z klávesnice nebo z myši. Naprogramujeme jednoduchou hru, ve které budeme naším známým jednorožcem z druhého dílu. Otevřete si tedy projekt z minula a než začneme, provedeme pár úprav.

Změna textury trávy

Naše tráva na terénu vypadá tak trochu uměle a není z ní zřetelně vidět tvar terénu, takže ji můžeme zkusit vyměnit za tuto texturu. Stáhněte si ji (pravým tlačítkem na ni klikněte a zvolte Uložit obrázek jako...). Teturu uložte do složky Content ve složce projektu a nahraďte jí obrázek grass.jpg.

Nová textura trávy

Úprava opakování textur

Minule jsme do kódu ve třídě Landscape napsali "natvrdo", že textura, kterou terénu přiřadíme, se má opakovat 8x na délku a 8x na šířku celého terénu. Bude lepší, když z této napevno zadané hodnoty uděláme vlastnost třídy Landscape a budeme ji moci nastavovat zvenčí. Naše třída Landscape pak bude univerzálnější. Otevřete si tedy soubor s kódem třídy Landscape a najděte proceduru PrepareVertexBuffer. Řádek začínající .TextureCoordinate opravte takto:

                     .TextureCoordinate = New Vector2(x * _textureScale / width, y * _textureScale / height)

Visual Studio vám samozřejmě nahlásí chybu, protože používáme proměnnou _textureScale, kterou nemáme nadeklarovanou. Odrolujte si tedy kód nahoru a k ostatním deklaracím uvnitř třídy (ne v proceduře!) přidejte tuto vlastnost:

     Private _textureScale As Single = 16F
Public Property TextureScale() As Single
Get
Return _textureScale
End Get
Set(ByVal value As Single)
_textureScale = value
End Set
End Property

Nastavení pozice kamery dynamicky

Také pozici kamery jsme do třídy Game napsali "natvrdo", ale nyní s ní budeme potřebovat manipulovat. Najděte tedy ve třídě Game tyto tři řádky:

     Private world As Matrix = Matrix.Identity
Private view As Matrix = Matrix.CreateLookAt(New Vector3(32, 12, 16), New Vector3(32, 8, 32), Vector3.Up)
Private proj As Matrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 4 / 3, 1, 1000)

Smažte je a místo nich vložte tyto deklarace:

     Private posX As Single = 26, posZ As Single = 18, angle As Single = 0

Private world As Matrix = Matrix.Identity
Private view As Matrix
Private proj As Matrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 4 / 3, 1, 1000)

Přidal jsem dvě proměnné posX a posZ, které reprezentují pozici jednorožce, a proměnnou angle, která drží úhel, ve kterém je jednorožec natočen, matici view podle těchto hodnot vždy spočítáme v metodě Update, ale to až později.

Přidání jednorožce

Do projektu si přidejte znovu našeho jednorožce z druhého dílu, ve třídě Game do deklarací přidejte první řádek a do metody LoadContent řádek druhý. Není na tom nic, co bychom neznali.

     Private unicorn As Model
     unicorn = Content.Load(Of Model)("Content\unicorn")

Pokud jste ze svého projektu v některém z minulých dílů neodstranili proceduru RenderModel ve třídě Game, kterou jsme napsali ve 2. dílu, odstraňte ji a nahraďte ji touto verzí, které jsem přidal možnost provádět změnu měřítka. Model jednorožce je totiž v jiném měřítku než terém, je třeba jej 3x zvětšit.

     Public Sub RenderModel(ByVal m As Model, ByVal position As Vector3, ByVal rotation As Double, ByVal scale As Single)
' Vykreslit celý model
Dim transforms(m.Bones.Count - 1) As Matrix
m.CopyAbsoluteBoneTransformsTo(transforms)

For Each mesh As ModelMesh In m.Meshes ' projít všechny části modelu

For Each eff As BasicEffect In mesh.Effects ' všem efektům nastavit pozice
' nastavit všechny 3 matice
eff.World = Matrix.CreateScale(scale) * Matrix.CreateRotationY(rotation) * transforms(mesh.ParentBone.Index) * Matrix.CreateTranslation(position)
eff.View = view
eff.Projection = proj

eff.EnableDefaultLighting()
' vypnout standardní osvětlení
Next

mesh.Draw() ' vykreslit část modelu

Next
End Sub

Zjištění výšky terénu v konkrétním bodě

Abychom mohli spolehlivě pozicovat jednorožce po terénu, určitě budeme potřebovat funkci, které předáme souřadnice X a Z nějakého místa a ona nám vrátí přesnou výšku terénu v tomto bodě. Pokud by mohly být souřadnice X i Z jen celočíselné, bylo by to poměrně triviální, ale náš jednorožec vždycky nemusí stát na místě s celočíselnými souřadnicemi, tedy tam, kde výšku známe rovnou. Potřebujeme zkrátka ze souřadnic zjistit, na kterém trojúhelníku se hledané souřadnice nacházejí, a podle vzdálenosti od vrcholů v tomto trojúhelníku dopočítáme výšku. Přesný postup doufám vysvětluje dostatečně tento obrázek:

 Výpočet výšky v bodě

Červený čtvereček určuje bod, ve kterém výšku terénu hledáme. My známe výšku pouze ve všech rozích čtverce. Jednoduchou podmínkou tedy rozhodneme, jestli je bod v pravém či levém trojúhelníku (stačí porovnat souřadnice bodu v rámci čtverce - pokud má červený bod X souřadnici větší než Z, pak je v pravém čtverci, pokud má větší Z, je ve čtverci levém; jen pro doplnění, na světle modré úhlopříčce mají body souřadnice X a Z stejné).

Jakmile tedy víme, ve kterém trojúhelníku bod je, proložíme z jednoho rohu tímto bodem přímku a v místě, kde protne nějakou stěnu čtverce, máme vyhráno. V našem případě máme vyznačenou oranžovou stranu čtverce - na ní se totiž výška mění plynule (lineárně) z jednoho rohu do druhého. Výšku v bodě, kde se protíná s proloženou čárkovanou přímkou, spočítáme pomocí vzorce:

bod.Y = roh1.Y + (roh2.Y - roh1.Y) * (bod.Z - roh1.Z)

Jak to funguje? Představte si, že už víme, kde je bod (známe jeho souřadnici Z), a máte jít z bodu roh1 do bodu roh2. Vaše nadmořská výška na začátku byla stejná, jako v bodě roh1, a jakmile dorazíte do bodu roh2, přičetl se k této výšce rozdíl výšek obou bodů (tedy roh2.Y - roh1.Y). Bod bod je někde řekněme v polovině cesty a výška roste rovnoměrně, proto v bodě bod se k vaší původní nadmořské výšce přičte jen polovina rozdílu výšek na začátku a na konci. My využijeme toho, že víme, že body jsou v naší mřížce rozmístěné ve vzdálenostech 1, takže vzdálenost bodů bod a roh1 bude odpovídat přesně části původní cesty. Když tedy chceme spočítat výšku v bodě bod, k výšce v bodě roh1 přičteme rozdíl výšek bod2.Y - bod1.Y, který vynásobíme příslušnou vzdáleností bod.Z a roh1.Z (jdeme totiž po svislé souřadnici Z), která se pohybuje od 0 do 1 podle toho, kde náš bod je.

Nyní tedy známe výšku v bodě bod. A celý postup můžeme zopakovat ještě jednou, tentokrát s čárkovanou úsečkou. Známe výšky v jejích krajních bodech, jediné, co ještě nevíme, je kde náš hledaný bod na úsečce leží (ve které části). Ale tady nám pomůže Pythagorova věta, známe délku tmavě modré horní strany (to je 1), známe vzdálenost z bodu do rohu1, takže můžeme podle známého vzorce c2 = a2 + b2 dopočítat c, což bude délka čárkované úsečky. No a z rozdílu souřadnic X a Z horního levého rohu a hledaného bodu můžeme opět spočítat vzdálenost těchto bodů (opět použití Pythagorovy věty, proložte si hledaným bodem svislou čáru a uvidíte pravoúhlý trojúhelník, kde jeho dvě kratší strany - odvěsny - mají délky přesně rozdíly souřadnic X a Z horního levého rohu a hledaného bodu).

Pokud jste se ještě neztratili, napadlo vás, že používáme bod bod, ale neznáme jeho Z souřadnici. Tu získáme úplně stejným postupem, akorát rozdíl vynásobíme číslem "o trochu vyšším než jedna". Je to jako kdybyste bod2 přešli a šli ještě dál, pořád budete stoupat a rozdíl se přičte tolikrát, kolikrát více jste urazili než jste urazit měli. A to je přesně ono.

Celému tomuto divadlu, které jsme nyní třikrát použili, se říká lineární interpolace. Zkrátka pro zjištění nějaké mezihodnoty, která plynule přechází z jednoho bodu do druhého, stačí přičíst k hodnotě v prvním bodě rozdíl krajních hodnot, který vynásobíme číslem od 0 do 1, které charakterizuje, na kterém místě v cestě hodnotu zjišťujeme. Čím je toto číslo nižší, tím blíže je u prvního bodu, čím víc se blíží jedničce, tím víc se blíží bodu druhému. Je to vlastně poměr vzdálenosti hledaného bodu a prvního bodu ku celkové délce z jednoho bodu do druhého. Protože tuto operaci budeme provádět vícekrát, vyplatí se napsat si metodu Interpolate, které předáme hodnoty v krajních bodech a koeficient (poměr vzdáleností), a ona nám již výsledek spočítá.

Nebudu to již dále popisovat, zde je kód, který souřadnice spočítá, přidejte jej do třídy Landscape.

     Private Function Interpolate(ByVal val1 As Single, ByVal val2 As Single, ByVal koef As Single) As Single
'provede lineární interpolaci a vrátí výsledek
'- val1 a val2 jsou hodnoty v krejních bodech
'- koef je číslo od 0 do 1 reprezentující vzdálenost od prvního bodu
Return val1 + (val2 - val1) * koef
End Function

Public Function GetHeight(ByVal x As Single, ByVal z As Single) As Single
'pokud jsme náhodou mimo terén, vrátit nulovou výšku
If x < 0.0F Or z < 0.0F Or x >= width - 1 Or z >= height - 1 Then Return 0.0F

'ošetřit body ve skoro celočíselných vrcholech
If Math.Abs(x - Math.Round(x)) < 0.001F And Math.Abs(z - Math.Round(z)) < 0.001F Then Return heights(Math.Round(x), Math.Round(z))

'zjistit souřadnice horního levého rohu čtverce
Dim lX As Integer = Math.Floor(x), lZ As Integer = Math.Floor(z)

'určit, ve kterém trojúhelníku jsme
Dim rX As Single = x - lX, rZ As Single = z - lZ
If rX > rZ Then 'pravý trojúhelník
Dim bodZ As Single = Interpolate(lZ, z, 1.0F / rX) 'spočítat bod.Z
Dim bodY As Single = Interpolate(heights(lX + 1, lZ), heights(lX + 1, lZ + 1), bodZ - lZ) 'spočítat bod.Y
Dim koef As Single = Math.Sqrt(rX * rX + rZ * rZ) / Math.Sqrt(1 * 1 + (bodZ - lZ) * (bodZ - lZ)) 'spočítat poměr vzdáleností
Return Interpolate(heights(lX, lZ), bodY, koef)

Else 'levý trojúhelník
Dim bodX As Single = Interpolate(lX, x, 1.0F / rZ) 'spočítat bod.Z
Dim bodY As Single = Interpolate(heights(lX, lZ + 1), heights(lX + 1, lZ + 1), bodX - lX) 'spočítat bod.Y
Dim koef As Single = Math.Sqrt(rX * rX + rZ * rZ) / Math.Sqrt((bodX - lX) * (bodX - lX) + 1 * 1) 'spočítat poměr vzdáleností
Return Interpolate(heights(lX, lZ), bodY, koef)

End If
End Function

Pro pravý trojúhelník počítáme přesně podle postupu uvedeného nahoře, nejprve zjistíme bod.Z, pak spočítáme výšku v bodě Z a nakonec z poměru vzdáleností na čárkované čáře spočítáme finální výšku hledaného bodu. Pro levé trojúhelníky je to to samé, akorát počítáme bod.X. Jinak v proměnných lX a lZ jsou souřadnice levého horního rohu vrcholu a proměnné rX a rZ udávají rozdíly souřadnic hledaného bodu a levého horního vrcholu.

Nasazení jednorožce do terénu

Jednorožce máme již načteného, takže jej můžeme vykreslit. Tento řádek přidejte za vykreslování terénu do procedury Draw uvnitř třídy Game:

 RenderModel(unicorn, New Vector3(posX, land.GetHeight(posX, posZ), posZ), angle - MathHelper.PiOver2, 3.0F)

Pozici jednorožce zjistíme z proměnných posX, posZ a jeho výšku z funkce, kterou jsme napsali před chvílí, tedy land.GetHeight(posX, posZ). Jednorožce otočíme o angle - π/2 stupňů, protože model je otočený o 90 stupňů, což je právě π/2 radiánů.

Ještě jež to bude fungovat správně, musíme nastavit kameru podle proměnných posX a posZ, jak jsem slíbil na začátku. Tento kód přidejte do procedury Update ve třídě Game:

         'kamera se bude dívat na místo, kde je jednorožec, ale na místo 3 jednotky nad zemí
Dim lookAt As Vector3 = New Vector3(posX, land.GetHeight(posX, posZ) + 2, posZ)
'spočítat pozici kamery v závislosti na natočení jednorožce
Dim camPos As Vector3 = New Vector3(1.5 * Math.Sin(angle), 0.2, -1.5 * Math.Cos(angle))
'vytvořit matici výhledu
view = Matrix.CreateLookAt(lookAt + camPos, lookAt, Vector3.Up)

Do proměné lookAt si připravíme vektor se souřadnicemi posX a posZ, tedy se souřadnicemi jednorožce. Jako souřadnici Y mu ale předáme výšku terénu v tomto bodě + 3 jednotky, abychom se nedívali jednorožci pod nohy, ale viděli mu přes hlavu, musíme prostě být kus nad zamí. Na tuto pozici bude totiž kamera mířit.

Proměnnou camPos, která udává pozici kamery vzhledem k pozici jednorožce, počítáme rotací vektoru 0, 0.2, -1.5 kolem osy Y podle aktuálního úhlu. Takže souřadnici Z tohoto vektoru násobíme hodnotou Math.Cos(angle), když je úhel 0, pak je hodnota funkce kosinus 1, takže se souřadnice Z násobí jedničkou, kdežto souřadnice X se násobí hodnotou sinus 0, což je 0. Pokud měníme proměnnou angle, budou se hodnoty plynule přelévat tak, aby se vektor otáčel správně. Z těchto dvou vektorů pak vytvoříme matici kamery.

Pohyb jednorožce

Pohyb jednorožce bude poměrně jednoduchý, ale je třeba dát si pozor na pár věcí. Navíc se naučíme, jak pracovat s klávesnicí a myší z XNA. Nemáme totiž žádné události, jako normálně, musíme si stavy zjišťovat sami. Stav klávesnice zjistíte zavoláním Keyboard.GetState(). Je dobré si v každém snímku zjistit stav jen jednou a neptat se na něj pořád. Ve VB.NET jsou na to ideální bloky With. Následující 2 bloky kódu vložte postupně do procedury Update nad vypočítávání pozice kamery.

         Dim hopping As Double = 0
'reagovat na ovládání klávesnicí
With Keyboard.GetState()
If .IsKeyDown(Input.Keys.Up) Then 'jedeme dopředu
posX += -Math.Sin(angle) * gameTime.ElapsedGameTime.Milliseconds * 0.01F 'posunout jednorožce
posZ += Math.Cos(angle) * gameTime.ElapsedGameTime.Milliseconds * 0.01F
hopping = 0.09 * Math.Sin(gameTime.TotalGameTime.TotalMilliseconds * 0.006F)
'efekt hopsání
ElseIf .IsKeyDown(Input.Keys.Down) Then 'couváme
posX -= -Math.Sin(angle) * gameTime.ElapsedGameTime.Milliseconds * 0.005F 'posunout jednorožce
posZ -= Math.Cos(angle) * gameTime.ElapsedGameTime.Milliseconds * 0.005F
End If
End With

V tomto kusu kódu ovládáme jízdu jednorožce. Bude umět jezdit dopředu a při tom bude ještě hopsat, a také bude umět couvat, ale to bude dělat pomaleji a u toho už hopsat nebude. Založíme si tedy proměnnou hopping, kde bude vzdálenost, o kterou se bude vychylovat svisle kamera, aby to dojem hopsání navodilo.

Dále si zjistíme stav klávesnice a metodou IsKeyDown se ptáme na konkrétní klávesu, jestli je stisknutá. Pokud je stisknutá klávesa nahoru, do proměnných posX přičítáme vhodný násobe funkcí Sin a Cos pro aktuální natočení jednorožce vynásobený hodnotou gameTime.ElapsedGameTime.Milliseconds, což je počet milisekund, kolik zabralo vykreslování posledního snímku. Na každém počítači totiž může být počet snímků různý a pak by také jednorožec jezdil všude různě rychle. Když rychlost posunu 0.01 vynásobíme počtem milisekund, dostaneme hodnotu, o kolik milisekund se má jednorožec posunout. Pokud se tedy stihnul za 30 milisekund 1 snímek, jednorožec se posune o 0.3, pokud se stihnuly 2 snímky, jednorožec se posune 2x, ale pokaždé o 0.15, takže ve výsledku je to stejné.

Nakonec do proměnné hopping přidáme hodnotu vynásobenou opět nějakou hodnotou Sin, kde gameTime.TotalGameTime.TotalMilliseconds je celkový počet milisekund, který uplynul od začátku hry. Jako výsledek bude hodnota proměnné hopping kolísat v sinusovém rytmu, tedy bude se plynule měnit od -0.09 do 0.09, dokud jednorožec pojede. Možná si říkáte, že dost často něco násobíme nějakou konstantou, ale sami byste na to nepřišli, že ta konstanta bude zrovna takto. Když navrhujete kód, musíte metodou pokus-omyl vymyslet, jaké ty konstanty budou, aby to hezky vypadalo.

Nyní se vrhneme na otáčení výhledu jednorožce. To nám zajistí tento kód:

         'zatáčet pomocí myši
With Mouse.GetState()
'otáčet pohled
angle += (.X - Me.Window.ClientBounds.Width / 2) * 0.006F
'vrátit myš doprostřed okna
Mouse.SetPosition(Me.Window.ClientBounds.Width / 2, Me.Window.ClientBounds.Height / 2)
End With

Z Mouse.GetState() si zjistíme stav myši a používáme vlastnosti .X a .Y se souřadnicemi myši vzhledem k levému rohu okna. Podle vzdálenosti kurzoru od prostředku okna určíme hodnotu, která se má přičíst do proměnné angle. Po odečtení nastavíme kurzor doprostřed okna, aby nám neujel na konec obrazovky, pak bychom již nemohli otáčet na obě strany.

To je skoro vše, ještě poslední věc, upravte přepočítávání pozice kamery takto, aby se bralo v úvahu hopsání jednorožce, které v předchozí verzi nebylo:

         'kamera se bude dívat na místo, kde je jednorožec, ale na místo 3 jednotky nad zemí
Dim lookAt As Vector3 = New Vector3(posX, land.GetHeight(posX, posZ) + 2, posZ)
'spočítat pozici kamery v závislosti na natočení jednorožce
Dim camPos As Vector3 = New Vector3(1.5 * Math.Sin(angle), 0.1 + hopping, -1.5 * Math.Cos(angle))
'vytvořit matici výhledu
view = Matrix.CreateLookAt(lookAt + camPos, lookAt, Vector3.Up)

A to už byla poslední úprava, nyní se s naším jednorožcem budeme moci po terénu projet. Jen podotýkám, že kurzor myši se bude pořád držet uprostřed okna, takže jej budete muset zavřít přes Alt-F4. Nebo si do procedury Update můžete přidat ukončení hry při stisku klávesy Escape, to už je na vás.

Doufám, že se příliš neztrácíte v matematice, začíná toho být moc. Příští díl asi bude obsahovat teoretickou část o goniometrických funkcích sinus a kosinus, abych měl jistotu, že všichni rozumí tomu, co děláme. Pokud máte nějaké další nápady nebo potřebujete něco lépe vysvětlit, napište do diskuse.

Pokud jste se někde ztratili nebo jste se někde přehlédli, můžete si stáhnout zdrojové kódy.

 

hodnocení článku

0       Hodnotit mohou jen registrované uživatelé.

 

Všechny díly tohoto seriálu

6. Trocha matematiky pro 3D 11. 7. 2008
5. Klávesnice a myš v XNA 30. 3. 2008
4. Textury a světla v XNA 24. 2. 2008
3. Generování terénu 20. 2. 2008
2. Vykreslujeme 3D model v XNA 17. 2. 2008
1. Seznámení s XNA frameworkem 14. 2. 2008

 

Mohlo by vás také zajímat

Řešené příklady v ASP.NET - díl 2.: Aplikace pro zamlouvání sedadel (část 2)

V této části si vysvětlíme základy používání LINQ to SQL a napíšeme si jednoduchou třídu, která bude vracet data, která potřebujeme ve stránce, a rezervovat jednotlivá sedadla.

Windows Presentation Foundation (WPF) - díl 4.: Architektura a objektový model WPF

Na jaké kompromisy museli architekti WPF frameworku přistoupit, aby nabídli vývojářům pohodlný vývoj ve vyšších programovacích jazycích a zároveň odpovídající výkon výsledného uživatelského prostředí? Tento článek se věnuje architektuře WPF frameworku.

Windows Presentation Foundation (WPF) - díl 8.: Canvas, StackPanel, WrapPanel

Článek se věnuje dalším široce používaným pozicovacím komponentám WPF. Canvas pro absolutní pozicování, StackPanel pro skládání elementů vedle sebe nebo nad sebe a WrapPanel zalamující jejich tok do řádků nebo sloupců.

 

 

Nový příspěvek

 

Diskuse: Vstup - klávesnice a myš

Ahoj, postupoval jsem podle tvého návodu a sestavil stejný projekt Vše funguje perfektně za což ti chci poděkovat.

Doplnil jsem si tam však text pomocí SpriteBatch a tím mi dojde k rozhození textury:( Nevíš čím by to mohlo být? Díky

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Vstup - klávesnice a myš

Dobrý den chci se zeptat, jestli znáte nějaký dobrý tutoriál na materiály. Kdybych chtěl třeba naleštit toho jednorožca.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Vstup - klávesnice a myš

myslím že když nebude ukazatel vidět, bude hra realičtištější. ve třídě game v metodě New změnte řádek

.IsMouseVisible = true                      ' systémový kurzor myši je vidět, pokud je v okně

za

.IsMouseVisible = False                      ' systémový kurzor myši není vidět, pokud je v okně

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Diskuse: Vstup - klávesnice a myš

Dobry den predne diky za pekne clanky a ve vlastnim zajmu doufam, ze nam vydrzite :)

Chtel byc se zeptat jak je resena v XNA animace objektu.

podporuje bipedy nebo kosti z 3D studia? pripadne jak volat animacni sekvence ...

s pozdravem a pranim pekneho dne Sumar

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Modely bones umí, vydržte do dalšího dílu.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diky za bleskovou odpoved ... budu se tedy tesit

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Diskuse: Vstup - klávesnice a myš

Pokud sedím za hřívou našeho jednorožce, projížďka vypadá celkem obstojně, toliko není poznat, na čem to vlastně sedím.

Pokud chci mít o scéně trochu lepší přehled, pak si trochu oddálím kameru a dám ji mírně z boku a vidím, jak se mi jednorožec prohání po pláních....

Leč má to dva drobné nedostatky.

Na straně jedné se mi kobyla stále brodí takřka po kolena hustým podrostem. To nebylo až tak problematické odstranit - model má evidentně vkládací bod v těžišti jednorožce, které je v úrovni cca 0.39 nad plochou kopyt - stačilo o tuto hodnotu zvýšit pozici oře.

Komplikovanějším problémem ale je, že i když se prochází zvlněnou krajinou, vůbec si toho nevšímá, takže jednou do podrostu zanoří svůj zadek, podruhé tam vstrčí celou hlavu až po...

Řešení by bylo celkem snadné. Nezadávat polohu jako souřadnice těžiště [X,Y,Z] a úhel natočení v horizontální rovině, ale zjistit si polohu, na které se právě nacházejí přední kopyta a polohu, na které se nacházejí zadní kopyta, pro obě polohy zjistit výšku a na základě těchto 2 prostorových bodů jednorožce vykreslit.

A tu má otázka. Vládne XNA nějakým nástrojem, který by mi byl schopen říci absolutní velikost modelu (v mých modelových jednotkách), abych věděl, jestli jsou nohy vytrčeny o 0.5 , 2 či 15 jednotek dopředu a dozadu vůči vkládacímu bodu? Samozřejmě mi XNA asi neřekne polohu kopyta - ale nedá se nějak zjistit třeba rozměry opsaného kvádru modelu, nebo si to musí autor modelu zaznačit jako externí informaci o modelu?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Absolutní velikost modelu asi nepomůže, ve skutečnosti se pracuje s tzv. bounding boxem, což je nejmenší možný kvádr (s hranami rovnoběžnými se souřadnicovými osami), do kterého se jednorožec ještě vejde (něco jako opsaná kružnice u trojúhelníka). Pokud se nepletu, dá se zjistit veliksot tohoto kvádru a podle toho jednorožce napozicovat. Aby to vypadalo reálně, museli bychom mít samozřejmě animovaný model a spočítat si výšku terénu v místě předních nohou a v místě zadních nohou jednorožce a podle toho mu nastavit rotaci podle osy X (a až potom ho rotovat podle osy Y). A samozřejmě by bylo vhodné zakázat, aby mohl lézt do strmých svahů.

Jak spočítat bounding box najdete třeba na adrese http://andyq.no-ip.com/blog/?p=16 , víceméně jen projdete seznam vrcholů v modelu a hledáte minima a maxima jednotlivých souřadnic.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Dík - to je přesně ono nač jsem se tázal (pouze jsem si to laicky (a česky) nazval "opsaný kvádr" - taky mě mohlo řešení napadnout samotného - projít si souřadnice celého modelu a zjistit maxima a minima.

Uvažujete v některém z příštích dílů o XNA kouknout se také na práci s animovanými modely? Toho "naklápěného" jednorožce jsem zvládl (jenom jsem musel ty jednotlivé délky zkusmo tipnout, proto jsem se ptal na cestu, jak zjistit exaktní hodnoty a "nehádat") - vypadá to, samozřejmě, nepoměrně lépe, ale nemohu si pomoci, to zvíře mi připadá stále nějaké prkenné - nebylo by od věci, kdyby sem tam i nohou hejblo!

A ještě bych se zeptal trochu obecně. Existují v XNA i něco jako lokální souřadnice, vázané třeba na toho jednorožce? (aby se například transformace dalších objektů -sedla, jezdce,...) mohly vztahovat k těmto lokálním souřadnicím, nebo to "načítání" transformací (k transformaci jednorožce se vhodným způsobem přičte transformace objektu na něm závislá) si musí plně obsloužit programátor a pro všechny objekty na scéně musí spočítat jejich globální transformační matici?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Vstup - klávesnice a myš

Dobrý den,předem bych chtěl pogratulovat,zdá se že máté lebší znalost matematiky a dúvtipu než má učitelka :o).Dále bych se chtěl zeptat jestli se budeme zaobírat i onou hranicí,pokud koněm (mimochodem krásná projížďka na "čerstvém vzduchu" potěší)"vyjedu z mapy" vyhodí to hlašku "index mimo hranice pole".A malinko mi scházel posun kamery nahoru a dolu jak to ve hrách bývá ale v tomto příkladu to nejspíš ani nebylo potřeba.A děkuji za krásný článek.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

I já přeji dobrý večer. Z větší části se připojuji k předchozímu pisateli, i když musím přiznat, že v té pasáži výpočtu výšky jednorožce (lineární interpolace z lineárně interpolovaných hodnot....) jsem se docela pěkně ztratil :-) (ještě že se jednalo o jednu z mála pasáží u které jsem plně chápal proč to tak je).

Jinak jsem se při projížďce velice, ale skutečně velice pobavil a to hlavně ve chvíli, kdy jsem chtěl hru ukončit :-)))).

Pěkný chyták a taky pěkná ukázka toho, jak XNA dokáže krásně znásilnit myš. Ještě že my starší pamatujeme doby, kdy se ne všechno řešilo myší, takže známé Alt+F4 pomohlo.

Druhou pomocí, jak se z programu dostat, pak byla ta výše zmiňovaná neošetřená chybka - pokud se jezdci podařilo vyjet z mapy správným směrem (nefunguje to na všechny směry), pak se díky chybě podařilo z projížďky odejít.

Jinak bych se ale přimlouval (zvláště pro ty, kteří neznají Alt+F4 případně podobné fígle, aby si do třídy Game, tam, kde testují stav klávesnice, přidali ještě jedno ElseIf:

ElseIf .IsKeyDown(Input.Keys.Escape) Then 'konec
       Application.Exit()

Jinak ale děkuji za pokračování a těším se, že brzy uzříme další díl.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Musím se přiznat,nechal jsem se taktéž nachytat,a to i když alt+F4 znám,v nadšenosti jsem si na něj ani nevzdechl a nenapadla mne jiná možnost nežli se odhlásit (ani správce uluh mi to nevypl,nemohl jsem to označit a zaroveň ukončit proces).No a ta matematika,samozřejmě jsem se ztratil jak Alenka v říši...

Ale článek krásný.Jdu se ještě projet.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

No, je pravda, že mě vůbec nenapadlo, že někdo bude mít problé s Alt-F4. Já aplikace ukončují víceméně výhradně přes Alt-F4, málokdy klikám na křížek. Do článku to doplním.

Stejně tak chyba při vyjetí z mapy, vím o ní a opravil jsem si ji u sebe, ale už jsem zapomněl opravit kód v článku.

Co se týče té matematiky, doufal jsem, že lineární interpolaci pochopí všichni, spíš bych se bál o ty siny a cosiny, ale v příštím díle se na tu matematiku zaměřím víc a budu se to snažit vysvětlit nějak pořádně. Problém je, že matematika se ve školách učí špatně a pak se jí většina lidí bojí a neví, jak o ní mají přemýšlet, aby to pochopili.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Promiňte mi mou troufalost ale nešlo by ony "nedokonalosti" jako je vyjetí z mapy a vypínání ošetřit,pro některé programátory jistě zajímavou formou,aktualizace?Nevím co je k tomu zapotřebí vždy sem si myslel že aktualizace nebo ony opravné .exe soubory jen přepisují knihovny ale nejsem si jist,v tom případě by aktualizace nejspíše nešla.Děkuji.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

To by byla zbytečná komplikace, která jenom odvádí pozornost od XNA, je to naprosto mimo téma tohoto seriálu.

Ale můžete zkusit poprosit některého z redaktorů, aby na toto téma napsal článek, já mám rozdělaných seriálů už dost, teď bude na řadě další díl o ASP.NET.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Ale ne, dobrý je to. Já jen chtěl říct, kdybych to trošičku přehnal :-), že jsem věděl, co je to lineární interpolace do té doby, než jsem si přečetl to Vaše vysvětlení :-))).

Je mi zcela jasné, co tím básník chtěl říci a je mi i jasná složitost vysvětlení tak triviální záležitosti za pomoci laické nematematické mluvy.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Kdo ví, co je to lineární interpolace, tomu je to jasné, kdo to neví, snad to z mého neumělého nematematického výkladu pochopí. Vím, že je to nepřesné, ale na pochopení principu to lépe vysvětlit neumím.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Nic ve zlém, já vím, že to není jednoduché.

Spíše bych měl jednu drobnost k použité metodice výpočtu. Dost mi vrtalo hlavou, proč do celého problému (linaární interpolace) zatahujete chudáka (nelineárního) Pythagora. Osobně bych ho nechal odpočívat v pokoji.

Vy totiž uvádíte, že "neznáme délku čárkované úsečky" (za účelem lineární interpolace po ní) - k tomu užijeme pythagorovu větu.

Ano, délku této úsečky asi jednodušeji nezjistíme, ale potřebujeme ji vůbec? K čemu?

Vždyť neznáme ani délku části této úsečky (z námi hledaného bodu do bodu 1) - tu taky počítáte pomocí pythagora. Jenomže ani tu nepotřebujeme znát - nám stačí znát pouze poměr délek (bod1 - hledaný bod)/(bod1 - bod Z) a tento poměr je kupodivu stejný, jako je poměr rx / 1 (=délka strany čtverce) (vyplývá to z podobnosti trojúhelníků).

Jinak řečeno, pokud si vrcholy našeho trojúhelníka označím (pro zjednodušení) 1 - 2 - 3 (po směru hodinovývh ručiček), H je výška v daném bodě (tj. funkce heights(souř. bodu), délka strany čtverce je rovna 1, pak vycházejí (lineární) vztahy:

Hz=H2+(H3-H2)*rZ/rX    ' výška v bodě "Z" (na svislici mezi body 2 a 3)
' a z toho:
H=H1+(Hz-H1)*rX        ' hledaná výška

Nebo ten Pythagoras tam má nějaký jiný, mně skrytý význam?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Pythagorova věta se používá na určení toho poměru, jde to samozřejmě spočítat i z X, ale je dobré, aby si čtenáři uvědomili, jak se počítá vzdálenost mezi dvěma body.

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback