5. díl - OOP v C++ - Dokončení bojovníka a rozpracování arény

C++ Objektově orientované programování OOP v C++ - Dokončení bojovníka a rozpracování arény

V minulém dílu seriálu o C++ jsme rozpracovali bojovníka. Toho teď dokončíme a začneme pracovat na aréně.

Zprávy

O útocích a obraně budeme uživatele informovat výpisem na konzoli. Výpis nebude provádět samotná třída Bojovnik, ta bude jen vracet zprávy jako textové řetězce. Jedna možnost by byla nastavit návratový typ metod Utoc() a BranSe() na string a při jejich volání vrátit i zprávu. Problém by však nastal v případě, když bychom chtěli získat zprávu od metody, která již něco vrací. Metoda samozřejmě nemůže jednoduše vrátit 2 věci.

Pojďme na věc univerzálněji, zprávu budeme ukládat do privátní proměnné zprava a uděláme metody pro její uložení a navrácení. Samozřejmě bychom mohli udělat proměnnou veřejnou, ale není zde důvod, proč umožnit zvenčí zápis do zprávy a také by skládání složitější zprávy uvnitř třídy mohlo být někdy problematické.

K atributům třídy tedy přidáme:

string zprava;

Nyní si vytvoříme dvě metody. Privátní NastavZpravu(), která bere jako parametr text zprávy a slouží pro vnitřní účely třídy, kde nastaví zprávu do privátní proměnné:

void NastavZpravu(std::string zprava)//pod private
{
        this.zprava = zprava;
}

Nic složitého. Podobně jednoduchá bude veřejná metoda pro navrácení zprávy:

std::string VratPosledniZpravu()//pod public
{
        return zprava;
}

O práci se zprávami obohatíme naše metody Utoc() a BranSe(), nyní budou vypadat takto:

void Utoc(Bojovnik &souper)
{
        int uder = utok + kostka.hod();
        std::string zp = jmeno;
        zp += " útočí s úderem za ";
        zp += IntToString(uder);
        zp += " hp";
        NastavZpravu(zp);
        souper.BranSe(uder);
}

a takto:

void BranSe(int uder)
{
        std::string zp;
        int zraneni = uder - (obrana + kostka.hod());
        if (zraneni > 0)
        {
                zivot -= zraneni;

                zp += jmeno;
                zp += " utrpěl poškození ";
                zp += IntToString(zraneni);
                zp += " hp";

                if (zivot <= 0)
                {
                        zivot = 0;
                        zp += " a zemřel";
                }
        }
        else
        {
                zp = jmeno;
                zp += " odrazil útok";
        }
        NastavZpravu(zp);
}

Aby kód fungoval, musíme na začátek souboru přidat metodu pro převod řetězce na číslo:

#include <strstream>

std::string IntToString(int number)
{
   std::strstream ss;
   ss << number << '\0';
   return ss.str();
}

Vše si opět vyzkoušíme, tentokrát již vytvoříme druhého bojovníka:

Kostka kostka(10);
Bojovnik bojovnik("Zalgoren", 100, 20, 10, kostka);

cout << "Život: " << bojovnik.GrafickyZivot().c_str(); // test GrafickyZivot();

// útok na našeho bojovníka
Bojovnik souper("Shadow", 60, 18, 15, kostka);
souper.Utoc(bojovnik);
cout << souper.VratPosledniZpravu().c_str();
cout << bojovnik.VratPosledniZpravu().c_str();

cout << "Život: " << bojovnik.GrafickyZivot().c_str();

_getch();
Boj v objektové aréně v C++

Máme kostku i bojovníka, teď již chybí jen aréna. Takže jdeme na to.

Potřebujeme napsat nějaký kód pro obsluhu bojovníků a výpis zpráv uživateli. Samozřejmě ho nebudeme bušit rovnou do Source.cpp, ale vytvoříme si objekt Arena, kde se bude zápas odehrávat. Source.cpp potom jen založí objekty a o zbytek se bude starat objekt Arena. Přidejme k projektu tedy poslední třídu a to Arena.h (+ Arena.cpp).

Třída bude víceméně jednoduchá, jako atributy bude obsahovat 3 potřebné instance: 2 bojovníky a hrací kostku. V konstruktoru se tyto atributy naplní z parametrů. Kód třídy bude tedy následující (komentáře si dopište):

//Arena.h
#pragma once
#include "Kostka.h"
#include "Bojovnik.h"

class Arena
{
private:
        Bojovnik &bojovnik1;
        Bojovnik &bojovnik2;
        Kostka &kostka;
public:
        Arena(Bojovnik &bojovnik1, Bojovnik &bojovnik2, Kostka &kostka)
                :bojovnik1(bojovnik1), bojovnik2(bojovnik2), kostka(kostka){}
};

a hlavičkový soubor:

//Arena.cpp
#include "Arena.h"

Arena::Arena(Bojovnik &bojovnik1, Bojovnik &bojovnik2, Kostka &kostka)
        :bojovnik1(bojovnik1), bojovnik2(bojovnik2), kostka(kostka){}

Zamysleme se nad metodami. Z veřejných metod bude určitě potřeba jen ta k simulaci zápasu. Výstup programu na konzoli uděláme trochu na úrovni a také umožníme třídě Arena, aby přímo ke konzoli přistupovala. Rozhodli jsme se, že výpis bude v kompetenci třídy, jelikož se nám to zde vyplatí. Naopak kdyby výpis prováděli i bojovníci, bylo by to na škodu. Potřebujeme tedy metodu, která vykreslí obrazovku s aktuálními údaji o kole a životy bojovníků. Zprávy o útoku a obraně budeme chtít vypisovat s dramatickou pauzou, aby byl výsledný efekt lepší, uděláme si pro takový typ zprávy ještě pomocnou metodu. Začněme s vykreslením informační obrazovky:

void Arena::Vykresli()
{
        system("cls");
        cout << "-------------- Aréna -------------- \n" << endl;
        cout << "Zdraví bojovníků: \n" << endl;
        cout << bojovnik1 << bojovnik1.GrafickyZivot().c_str() << endl;
        cout << bojovnik2 << bojovnik2.GrafickyZivot().c_str() << endl;
}

Zde asi není co řešit, můžete si ještě obrazovku vyzdobit barevně, když budete chtít. Díky smazání konzole pomocí system("cls") docílíme hezké informační obrazovky namísto klasického konzolového textu, kde se plná obrazovka roluje dolů. Metoda je privátní, budeme ji používat jen uvnitř třídy. Funkce system by se neměla používat, ale v tomhle případě se perfektně hodí.

Další privátní metodou bude výpis zprávy s dramatickou pauzou:

void Arena::VypisZpravu(string zprava)
{
        cout << zprava.c_str() << endl;
        Sleep(500);
}

Kód je zřejmý až na funkci Sleep(), která uspí program na daný počet milisekund. Abychom mohli funkci použít, musíme přidat na začátek souboru Arena.h #include <windows.h>.

Obě metody vlastně jen vypisují na konzoli, připadá mi zbytečné je zkoušet, přesuneme se tedy již k samotnému zápasu. Metoda Zapas() nebude mít žádné parametry a nebude ani nic vracet. Uvnitř bude cyklus, který bude na střídačku volat útoky bojovníků navzájem a vypisovat informační obrazovku a zprávy. Metoda by mohla vypadat takto:

void Arena::Zapas()
{
        cout << "Vítejte v aréně!" << endl;
        cout << "Dnes se utkají" << bojovnik1 << "s " << bojovnik2 << "! \n" << endl;
        cout << "Zápas může začít..." << endl;
        _getch();
        // cyklus s bojem
        while (bojovnik1.Nazivu() && bojovnik2.Nazivu())
        {
                bojovnik1.Utoc(bojovnik2);
                Vykresli();
                VypisZpravu(bojovnik1.VratPosledniZpravu()); // zpráva o útoku
                VypisZpravu(bojovnik2.VratPosledniZpravu()); // zpráva o obraně
                bojovnik2.Utoc(bojovnik1);
                Vykresli();
                VypisZpravu(bojovnik2.VratPosledniZpravu()); // zpráva o útoku
                VypisZpravu(bojovnik1.VratPosledniZpravu()); // zpráva o obraně
                cout << endl;
        }
}

Kód vypíše jednoduché informace a po stisku klávesy přejde do cyklu s bojem. Jedná se o while cyklus, který se opakuje, dokud jsou oba bojovníci naživu. První bojovník zaútočí na druhého, jeho útok vnitřně zavolá na druhém bojovníkovi obranu. Po útoku vykreslíme obrazovku s informacemi a dále zprávy o útoku a obraně pomocí naší metody VypisZpravu(), která po výpisu udělá dramatickou pauzu. To samé provedeme i pro druhého bojovníka.

Přesuňme se do Source.cpp, vytvořme patřičné instance a zavolejme na aréně metodu Zapas():

// vytvoření objektů
        Kostka kostka(10);
        Bojovnik zalgoren("Zalgoren", 100, 20, 10, kostka);
        Bojovnik shadow("Shadow", 60, 18, 15, kostka);
        Arena arena(zalgoren, shadow, kostka);
        // zápas
        arena.Zapas();

Charakteristiky hrdinů si můžete upravit dle libosti. Program spustíme:

Objektová aréna v C++ – simulace zápasu ve stolní hře

Výsledek je docela působivý. Objekty spolu komunikují, grafický život ubývá jak má, zážitek umocňuje dramatická pauza. Aréna má ještě nějaké nedostatky, ale ty opravíme příště.


 

Stáhnout

Staženo 210x (19.08 MB)
Aplikace je včetně zdrojových kódů v jazyce C++

 

  Aktivity (2)

Článek pro vás napsal Zdeněk Pavlátka
Avatar
Autor se věnuje spoustě zajímavých věcí :)

Jak se ti líbí článek?
Celkem (2 hlasů) :
55555


 


Miniatura
Předchozí článek
OOP v C++ - Bojovník do arény
Miniatura
Následující článek
OOP v C++ - Dokončení arény

 

 

Komentáře

Avatar
Samuel Bachar:

Čauko chcel by som sa spýtať v čom spočíva nasledujúci príkaz :

Arena(Bojovnik &bojovnik1, Bojovnik &bojovnik2, Kostka &kostka)
:bojovnik1(bo­jovnik1), bojovnik2(bojov­nik2), kostka(kostka){} <--- tento

Posielam vlastne inštanciu ako parameter. potom začína príkaz : bojovnik1(bojov­nik1)
Niekde si písal že sa jedna o referenciu . Chápem to tak že mám vlastne 2 inštancie na tú istú triedu ? Jednu deklarovanú v Source.cpp (main) a druhú v triede Bojovnik ? A aby som mohol využiť tu v Bojovnik musím ju referencovať skrz tu instanciu ktorá je predávaná v parametry ?

 
Odpovědět 8.10.2015 12:21
Avatar
Zdeněk Pavlátka
Tým ITnetwork
Avatar
Odpovídá na Samuel Bachar
Zdeněk Pavlátka:

Pomocí tohoto zápisu se dají nastavovat hodnoty proměnných. Třída Arena dostane odkazy (reference) na instance vytvořené v souboru Source.cpp a uloží si je do proměnných.

Odpovědět 8.10.2015 12:55
Kolik jazyků umíš, tolikrát jsi programátor.
Avatar
Samuel Bachar:

Neskôr som si urobil podobný záver ale vďaka vašej správy mi to je ešte jasnejšie .

Ďakujem za odpoveď.

 
Odpovědět 8.10.2015 19:11
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 3 zpráv z 3.