IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 5 - 3D bludiště v XNA - Dokončení editoru map

V minulém tutoriálu, 3D bludiště v XNA - Mapy, zdi a podlaha, jsme si vytvořili komponenty, ze kterých se bude naše bludiště skládat.

Dnes editor dokončíme a zprovozníme. Jako první dokončeme naši třídu Mapa, ve které nám chybí implementovat její vykreslení.

Vykreslení mapy

Metoda k vykreslení mapy bude tedy také ve třídě Mapa.cs. V parametru metody si předáme Graphics, na který se má kreslit. Stejně tak si předáme i velikost hrany políčka. Různé hodnoty nám umožní vykreslovat zvětšenou či zmenšenou mapu. Jelikož nejsme žádní začátečníci, ukažme si opět kód metody a záhy si jej popišme.

public void Vykresli(Graphics g, int hrana)
{
    // mřížka
    for (int j = 0; j <= Vyska; j++)
    {
        for (int i = 0; i <= Sirka; i++)
        {
            g.DrawLine(Pens.Gray, new Point(0, j * hrana), new Point(Sirka * hrana - 1, j * hrana)); // -
            g.DrawLine(Pens.Gray, new Point(i * hrana, 0), new Point(i * hrana, Vyska * hrana - 1)); // |
        }
    }

    // Políčka
    for (int j = 0; j < Vyska; j++)
    {
        for (int i = 0; i < Sirka; i++)
        {
            switch (policka[i, j])
            {
                // Zeď
                case 1:
                    g.FillRectangle(Brushes.CornflowerBlue, i * hrana, j * hrana, hrana, hrana);
                break;
                // Start
                case 99:
                    g.FillEllipse(Brushes.GreenYellow, i * hrana, j * hrana, hrana, hrana);
                    g.DrawString("S", new Font("Arial", hrana / 2), Brushes.Green, i * hrana + (hrana / 6), j * hrana + (hrana / 6));
                break;
                // Cíl
                case 100:
                    g.FillEllipse(Brushes.Purple, i * hrana, j * hrana, hrana, hrana);
                    g.DrawString("C", new Font("Arial", hrana / 2), Brushes.Red, i * hrana + (hrana / 6), j * hrana + (hrana / 6));
                break;
            }
        }
    }
}

První 2 cykly vykreslí na daný Graphics čtvercovou síť, aby se nám mapa lépe designovala. První kreslí vodorovné čáry, druhý svislé. Zde asi není co vysvětlovat.

Obdobně vykreslujeme v dalších 2 cyklech i políčka. Typ políčka rozlišíme switchem, zeď je vykreslena jako čtverec, políčka start a cíl jako barevná kolečka s nápisy S a C. Souřadnice nápisu na políčkách i velikost nápisu jsou pronásobeny velikostí hrany, aby při zoomování mapy zůstal text přibližně stejně velký a na stejné pozici.

Třídu Mapa můžeme prohlásit za hotovou.

Vizuální část

Logika je hotová, zprovozněme vizuální část editoru, tedy tu formulářovou.

Jako první si do třídy FormEditor přidejme proměnnou mapa, kde budeme mít uloženou instanci mapy, se kterou v editoru aktuálně pracujeme:

Mapa mapa;

Do konstruktoru formuláře přidejme vytvoření nové instance mapy velikosti 16x16. Pokud editor spustíme, bude v něm tedy připravena tato prázdná mapa:

mapa = new Mapa(16, 16);

Vybereme v designu mapaPictureBox a naklikneme mu událost Paint(). V té jednoduše zavoláme vykreslení mapy, kde v parametrech předáme Graphics PictureBoxu a šířku hrany z hranaNumericUpDown.

mapa.Vykresli(e.Graphics, Convert.ToInt32(hranaNumericUpDown.Value));

Můžeme spustit:

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

Vidíme vykreslenou prázdnou mapu, tedy mřížku 16x16. PictureBox však není roztáhnutý na velikost, kterou by měl mít. Tu můžeme jednoduše spočítat, pojďme přidat do formu metodu, kterou budeme mapu obnovovat. Ta kromě překreslení mapy ještě změní velikost PictureBoxu. Přidejme do FormEditor.cs metodu metodu PrekresliMapu():

private void prekresliMapu()
{
    mapaPictureBox.Size = new Size(mapa.Sirka * Convert.ToInt32(hranaNumericUpDown.Value) + 1, mapa.Vyska * Convert.ToInt32(hranaNumericUpDown.Value) + 1);
    mapaPictureBox.Refresh();
}

Velikost mapy jednoduše spočítáme podle rozměrů mapy a velikosti hrany vykreslovaného políčka. Formuláři přidáme událost Load a v ní překreslíme mapu:

prekresliMapu();
Editor levelů bludiště v C# .NET - 3D bludiště v XNA

PictureBox se nám krásně roztáhl a pokud je form menší, zobrazí se u panelu posuvníky a můžeme mapou skrolovat. To jsme přesně chtěli. Do události Load připišme výběr výchozího políčka v typPolickaComboBox:

typPolickaComboBox.SelectedIndex = 0;

hraNumericUpDown naklikneme událost ValueChanged a v ní překreslíme mapu:

prekresliMapu();

Nyní naklikneme na mapaPictureBox událost MouseClick. Do ní umístíme následující kód:

int hrana = Convert.ToInt32(hranaNumericUpDown.Value);
int x = e.X / hrana;
int y = e.Y / hrana;
// Hodnoty v pořadí, jako jsou popisky políček v ComboBoxu
int[] hodnoty = {1, 99, 100, 0};

// Kontrola správnosti souřadnic
if ((x >= 0) && (y >= 0) && (x < mapa.Sirka) && (y < mapa.Vyska))
{
    // Levé myšítko přidá zeď
    if (e.Button == MouseButtons.Left)
        mapa.policka[x, y] = hodnoty[typPolickaComboBox.SelectedIndex];
    // Pravé myšítko vymaže zeď
    if (e.Button == MouseButtons.Right)
        mapa.policka[x, y] = 0;
    prekresliMapu();
}

Prvně si zjistíme ze souřadnic myši políčko na mapě, na které se kliklo. To je jednoduché, stačí je jen vydělit velikostí políčka. Dále si připravíme pole hodnot, které bude představovat hodnoty pro jednotlivá políčka v typPolickaComboBox. Je důležité, aby hodnoty měly to samé pořadí, jako mají itemy v ComboBoxu. Vidíme, že zeď má hodnotu 1, start 99, cíl 100 a prázdno 0. Vypočítané souřadnice je nutno otestovat, jelikož uživatel mohl kliknout mimo mapu a sahali bychom tak za hranice pole. Nyní pouze otestujeme, které tlačítko bylo stisknuté. Pokud levé, vložíme na příslušené políčko na mapě hodnotu dle vybraného itemu v ComboBoxu. Pokud bylo stisknuto pravé tlačítko, vložíme prázdné políčko (pravým tlačítkem tedy mažeme). Nakonec mapu překreslíme a máme hotovo. MouseClick jsme použili z důvodu možnosti odlišení tlačítek narozdíl od události Click.

Můžete vyzkoušet. Bylo by skvělé, kdybychom mohli na mapu pokládat políčka i tažením myši, nejen klikáním. Stačí pouze, když metodu mapaPictureBox_Mou­seClick() vybereme i u události MouseMove. Nyní se mapa vytváří opravdu jednoduše:

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

Vytvoření nové mapy

Přejděme k formuláři pro vytvoření nové mapy. Do jeho třídy si přidáme veřejný atribut s instancí mapy.

public Mapa mapa;

Při kliknutí na tlačítko "Vytvořit" do atributu vytvoříme novou instanci mapy požadované velikosti a formulář zavřeme:

mapa = new Mapa(Convert.ToInt32(sirkaUpDown.Value), Convert.ToInt32(vyskaUpDown.Value));
Close();

Formu naklikneme událost Shown, kde vždy nastavíme tuto instanci na null:

mapa = null;

Při každém zobrazení dialogu se nám tedy mapa vymaže. Díky tomu poznáme, zda jsme formulář opustili kliknutím na tlačítko "Vytvořit" (v mapě je instance mapy) nebo jen zavřeli křížkem (v mapě je null).

Vytvoření formu a následné vytvoření mapy nakonec naklikneme do položky Nová v MenuStrip:

FormNovaMapa formNovaMapa = new FormNovaMapa();
formNovaMapa.ShowDialog();
if (formNovaMapa.mapa != null)
{
    mapa = formNovaMapa.mapa;
    prekresliMapu();
}

Můžete si zkusit založit novou mapu.

Ukládání a načítání

Dokončení editoru vrcholí. Přidejme si z Toolboxu dialogy pro otevření a uložení souboru. Nejprve přidejme SaveFileDialog pojmenovaný mapaSaveFileDialog. Nastavíme mu DefaultExt (výchozí příponu) na map. To bude přípona našich souborů s mapou. Dále nastavíme Filter na:

Mapy (*.map)|*.map

Stejně přidáme i nastavíme mapaOpenFileDialog. U něj ještě vymažeme vlastnost FileName (necháme prázdnou hodnotu).

V MenuStrip rozklikneme položku Otevřít a vložíme logiku pro zobrazení dialogu a načtení mapy:

if (mapaOpenFileDialog.ShowDialog() == DialogResult.OK)
{
    mapa.Nacti(mapaOpenFileDialog.FileName);
    prekresliMapu();
}

Obdebně to uděláme i u položky Uložit:

if (mapaSaveFileDialog.ShowDialog() == DialogResult.OK)
{
    mapa.Uloz(mapaSaveFileDialog.FileName);
    prekresliMapu();
}

Jako symbolickou třešinku na dortu přidáme vyvolání MessageBoxu při kliknutí na položku "O programu":

MessageBox.Show("Editor k tutoriálu na 3D bludiště v C# XNA z programátorské sociální sítě www.itnetwork.cz");

Editor levelů pro bludiště je hotový :) Za domácí úkol si můžete omezit, aby šlo vložit pouze jedno startovní a cílové pole, i když tato ochrana není nutně potřeba.

Příště, 3D bludiště v XNA - Podlahy podruhé a kolize, si s oslíkem načtete vaší krásnou mapu do enginu a můžete se v ní projít.


 

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

 

Předchozí článek
3D bludiště v XNA - Mapy, zdi a podlaha
Všechny články v sekci
3D bludiště v XNA
Přeskočit článek
(nedoporučujeme)
3D bludiště v XNA - Podlahy podruhé a kolize
Článek pro vás napsal David Hartinger
Avatar
Uživatelské hodnocení:
1 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity