NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!
NOVINKA - Online rekvalifikační kurz Java programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.

Lekce 4 - 3D bludiště v XNA - Mapy, zdi a podlaha

V minulé lekci, 3D bludiště v XNA - Editor map, jsme si vytvořili první část editoru map.

Vítejte po patnácté. Jistě jste si všimli předchozího článku od zmijozeláka. Editor pro naše bludiště bude velmi potřeba, zrychlí tvorbu nových levelů. My se ale nebudeme zaobírat v tomto článku pokračováním v editoru, ale pohneme se hrou. Vytvoříme si komponentu s mapou a také komponenty pro zdi a podlahy. Pokusíme se také načíst soubor s mapou. Je to hodně práce, tak se do toho hned pustíme.

Zeď

První bude potřeba komponenta pro zdi. Nebude to nic zázračného, celý kód je velmi velmi krátký. Vytvoříme si tedy složku pro komponenty v naší hře. Zde si vytvoříme novou třídu, pojmenujme si ji třeba Zed. Učiníme ji veřejnou, upravíme jmenný prostor. Budeme dědit od třídy Model3D, která se nám modely reprezentuje. Do obsahu hry přidáme model podlaha, který budeme používat. Vytvoříme si konstruktor:

public Zed(int x, int z): base(new Vector3(x*20+10,0,z*20+10),Matrix.Identity,new Vector3(1.34f),"zed"){

}

Jako parametr předáváme souřadnice x a y v poli s bludištěm, které pak přepočteme na skutečné ve světě. Rotace nechceme žádné, měřítko jsem pokusně stanovil na 1.34x, i když jsem v Cinemě 4D nastavil velikost na přesně 100, tak jsou zde velikosti jiné. Zeď je prozatím hotova. Věci pro kolize přidáme příště.

Podlaha

Další komponenta pro průchozí podlahy, opět vytvoříme třídu stejně jako minule, uděláme ji veřejnou, dědíme od Model3D a zase vytvoříme konstruktor:

public Podlaha(int x, int z): base(new Vector3(x*20+10,0,z*20+10),Matrix.Identity,new Vector3(1.34f),"podlaha"){

}

Vše je prakticky stejné jako u zdi. Jen se změnilo jméno modelu. Jistě vás zaujal podivný výpočet polohy. Bude se hodit později. O tom, jak tento vzoreček funguje, se zmíním doleji, pokud na to nezapomenu.

Mapa

Třetí komponenta, se kterou budeme pracovat, je mapa. Mapa v sobě bude mít uložené všechny zdi a podlahy, bude je přidávat do herního okna a opět zase odebírat. Zkrátka bude mít na starosti podobu bludiště. Jak už zmijozelák naznačil ve svém článku, mapa levelu bludiště je uložená ve dvojrozměrném poli celých čísel. Každé číslo bude reprezentovat jeden typ políčka. V následující tabulce je souhrn:

0 volno
1 zeď
99 startovní pole
100 cilové pole

Startovní a cílové pole by se měly vyskytovat v každé mapě jen jednou. Jistě může být více cílů, jeden snadno dosažitelný a další hůře, ale to prozatím pro jednoduchost vynechme. Prostoru pro typy políček je tam mnoho. Můžete si vymyslet políčka, která hráče zbrzdí, násilně jej otočí, otočí mu kameru vzhůru nohama a pak zas naopak... Fantazii se meze nekladou. Pro začátek si vystačíme s tímto základem.

Opět si založíme soubor s třídou Mapa ve složce pro komponenty. Opět dědíme od třídy Component. Vytvoříme si seznam, ve kterém budeme uchovávat námi přidané komponenty:

private List<Component> Komponenty;

V konstruktoru jej vytvoříme:

public Mapa(){
  Komponenty = new List<Component>();
}

Vytvoříme si metodu Nacti, kde budeme načítat bludiště ze souboru. Jako parametr metody předáme cestu k souboru. Ale jelikož jsme programátoři a jsme líní psát něco co už jsme napsali znovu, tak se podíváme do zmijozelákova článku, najdeme stejně pojmenovanou metodu, nakopírujeme si ji a docela ji promázneme. Asi tak jak jsem to udělal já:

public void Nacti(string cesta){
  string[] radky = File.ReadAllLines(cesta);
  for (int j = 0; j < radky.Length; j++){
    // rozbití řádku podle separátoru
    string[] radek = radky[j].Split(',');
    // naparsování hodnot v řádku
    for (int i = 0; i < radek.Length; i++){
      int typ = int.Parse(radek[i]);
    }
  }
}

Prakticky zmizelo vše s ukládáním do pole a také si proparsovaný výsledek ukládáme do proměnné. Není to úplně bezpečný způsob, co když se nám tam dostane nějaký znak namísto číslice? Tak nám aplikace pochopitelně spadne, to ošetříme změnou metody z Parse na TryParse:

int typ=-1;
int.TryParse(radek[i],out typ);

Jak to celé jinak funguje se dočtete v předcházejícím článku. Nám už jen zbývá přidat příslušnou komponentu na dané místo, to se bude dělat velmi snadno, použijeme switch, ač bych tam nejraději nacpal stromeček if-else, ale pro výukové potřeby se obětuji:

Component c=null;
switch (typ){
  case 0:{
    c=new Podlaha(i, j);
    break;
  }
  case 1:{
    c=new Zed(i, j);
    break;
  }
}

A pokud bude proměnná c rozdílná od null, tak ji přidáme do našeho seznamu a zároveň i do herního okna:

if (c != null){
  Parent.AddComponent(c);
  Komponenty.Add(c);
}

Tady je vidět mírná nedomyšlenost enginu jako takového. Bylo by příhodnější a lepší, kdyby mohla mapa sama řídit vykreslování součástí bludiště. Sama si je spravovat, přidávat a mazat aniž by musela komponenty dávat do herního okna. Engine na to ale není připravený, ale jelikož se bude hodit i pro jiné případy, tak si tuto vlastnost dopíšeme někdy v nějakém jiném dílu. Ještě je tam jeden menší zádrhel. Proměnná c bude vytvářena pokaždé při průchodu vnitřním cyklem. Pokud budeme mít bludiště 10x10, tak to bude 100x. Což není úplně zdravé. Přesuneme deklaraci před oba cykly a v každém kolečku ji jen vynulujeme. Potřeba bude také metoda, která nám promaže prvky bludiště. Vytvoříme si tedy metodu Promaz, která se nám o to postará:

public void Promaz(){
  foreach (Component c in Komponenty){
    Parent.RemoveComponent(c);
  }
  Komponenty.Clear();
}

A tuto metodu zavoláme v metodě Nacti jako úplně první věc. To nám zajistí zmizení starého bludiště v případě načtení nového. Bystřejší z Vás si všimli, že zatím nepřidáváme žádnou startovní ani cílovou podlahu. Je to z toho důvodu, že vytvoření těchto tříd v sobě skrývá jedno malé úskalí a proto si je ponechám na příště.

Kompletujeme

Zde by mohl tento článek končit, ale jelikož chci ukázat, že naše snaha nebyla zbytečná a že již v tuto chvíli si lze bludiště ve hře projít, přemístíme se do našeho herního okna a promažeme vše kromě kamery, mřížky a samozřejmě barevného pozadí. Vytvoříme si komponentu s mapou, přidáme ji do seznamu našich komponent a až potom načteme soubor přízračně nazvaný ddd.map. Já jsem to jméno nevymyslel, to jiní. Tento soubor si přemístíme do složky, kde se nalézá zkompilovaný exe soubor, já jej mám ve složce Debug.

Mapa mapa = new Mapa();
AddComponent(mapa);
mapa.Nacti("ddd.map");

U mřížky upravíme rastr na 20 okének se šířkou také 20:

AddComponent(new Mrizka(20,20));

Kupodivu je vše hotovo. Pokud se nám vše povedlo udělat správně, tak by při spuštění měl být vidět takovýto nějaký výsledek:

3D bludiště v C# .NET XNA - 3D bludiště v XNA

Díry nám zatím zůstávají pro startovní a koncovou dlaždici.

Příště si doplníme startovní a koncovou dlaždici a začneme uvažovat nad tím, jak zabránit průchodu zdí. Bude potřeba si vytvořit jakýsi kolizní manažer, který je obslouží. Zdrojový kód s celým projektem najdete na obvyklém místě pod článkem. Navíc jsem do něj přidal měření FPS. Mě se drží kolem šedesátky, určitě napište kolik máte vy třeba v komentářích pod článkem, je jich totiž jako šafránu, zdá se tedy že všichni všemu rozumí, všechno chápou, což je super, jenže bez zpětné vazby se mi funguje špatně. Proto prosím, pokud tento článek čtěte a líbil se vám nebo se vám nelíbil tak to dole v komentářích vyjádřete.

Děkuji a těším se na vás v rámci příští lekce, 3D bludiště v XNA - Dokončení editoru map.


 

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 247x (1.74 MB)
Aplikace je včetně zdrojových kódů v jazyce C# XNA

 

Předchozí článek
3D bludiště v XNA - Editor map
Všechny články v sekci
3D bludiště v XNA
Přeskočit článek
(nedoporučujeme)
3D bludiště v XNA - Dokončení editoru map
Článek pro vás napsal vodacek
Avatar
Uživatelské hodnocení:
3 hlasů
Vodáček dělá že umí C#, naplno se již pět let angažuje v projektu ŽvB. Nyní studuje na FEI Upa informatiku, ikdyž si připadá spíš na ekonomice. Není mu také cizí PHP a SQL. Naopak cizí mu je Java a Python.
Aktivity