Tvorba her v C/C++ 2.část (ve výstavbě)

Tvorba her v C/C++ 2.část (ve výstavbě)

Aktualizováno: 03.05.2009


Předmluva

Před čtením tohoto článku je nutné znát základy programování v jazyce C a okrajově v C++. Jinak nejdříve navštivte některou z následujících stránek:

Případně použijte některý z dostupných vyhledávačů (www.seznam.cz, www.google.com, www.altavista.com nebo www.yahoo.com).

Doporučuji si též pořídit knihu Učebnice jazyka C (280 stran, 179Kč). Jsou v ní názorně vysvětleny všechny příkazy programovacího jazyka C a jejich použití. Navíc si v odkazu na knihu můžete stáhnout zdrojové soubory příkladů. Autorem je Ing. Pavel Herout.

Tvorba hry

V předchozím článku Tvorba her v C/C++ 1.část jsme se zabývali pouze instalací a konfigurací jednotlivých programů. Nyní si při tvorbě jednoduché hry ukážeme práci s těmito programy.

Postup je rozdělen na několik kroků. Na konci každého kroku je k dispozici odladěný zdrojový kód ke stažení nebo shrnutí výše řečeného pro úplné pochopení každého kroku.

1. Definování hry

Ze všeho nejdříve si musíme nadefinovat parametry naší hry. Těm se pak podřídí grafika a vlastní kód hry.

Není na škodu si během definování hry psát poznámky na papír. Uteče Vám tak méně informací, které zpravidla během designování hry zapomenete pro jiné stejně důležité věci.

Shrnutí parametrů námi vytvářené hry:
  • Pracovní název hry: stroje (podle něj se pojmenuje pracovní adresář)

  • Skutečný název hry: Nadvláda strojů

  • Příběh: Stroje kdesi na ostrově spustí energetický štít kolem Země. Tím ožijí stroje na celém světě a zabíjejí lidi. Chlapec se vydá na cestu plnou překážek (z města, přes moře, na ostrov, skrz vodní kanál k základně), aby vypnul generátor energetického štítu kolem Země. Stroje pak znehybní a lidstvo je zachráněno.

  • Hlavní menu: ano

    • Start hry

    • Instrukce

    • Konec

  • Intro: ano (Stroje kdesi na ostrově spustí energetický štít kolem Země. Tím ožijí stroje na celém světě.)

  • Outro: ano (Chlapec vypne generátor energetického štítu kolem Země. Stroje znehybní a lidstvo je zachráněno.)

  • Rozlišení: 640 x 480 pixelů (full screen)

  • Hloubka barev: 16bit (65535 barev)

  • Typ: plošinovka (všesměrová)

  • Grafika: cartoon

  • Počet najednou se vykreslujících rovin: 3

    • mapa hry

    • 1. pozadí

    • 2. pozadí (nepohyblivé)

  • Počet úrovní: 3

    • 1.úroveň: město

    • 2.úroveň: moře

    • 3.úroveň: ostrov

  • Počet hlavních postav: 1

    • Počet životů: 3 (sníží se po každém kontaktu s překážkou nebo tvorem)

    • Počet snímků pro animaci: v každém směru 3, celkem tedy 4*3=12 snímků

  • Počet tvorů: 2

    • Motor

      • Počet snímků pro animaci: 5

    • Zbíječka

      • Počet snímků pro animaci: 3

    • Počet snímků pro animaci: 3

  • Počet statických překážek: 3

  • Počet animovaných překážek: 1

    • Počet snímků pro animaci: 3

  • atd.

Dle výše popsaného je představa o hře následující:

game_idea_mini.jpg

2. Kreslení grafiky

K vytvoření potřebných obrázků do naší hry můžeme použít některý z následujících programů:

Námi vytvořené obrázky budou v bezestrátovém formátu (bmp nebo png). Důvod pro použití bezestrátového formátu je velice prostý. Tento formát nám posktuje cennou informace o zabraném místě ve video paměti. To se rovná celkovému součtu jednotlivých velikosti souborů.

A nyní už jednotlivé obrázky:

  • jeden veliký barevný obrázek ve formátu bmp (samozřejmě lze i jiný bezestrátový formát např.: png) obsahující všechny objekty:

    game_idea_mini.jpg
  • a jeden veliký dvoubarevný obrázek ve formátu bmp (samozřejmě lze i jiný bezestrátový formát např.: png) obsahující masku pro všechny objekty:

    game_idea_mini.jpg

Je to z důvodu lepší práce s grafikou ve hře. Celý obrázek, tvořen jednou bitmapou, pak nahrajeme do videopaměti. V procesu vykreslování jednotlivých pozadí a objektů na obrazovku je to pak rychlejší.

3. Vytvoření projektu

Nejdříve vytvoříme pracovní adresář C:\tvorba\c\stroje. Jelikož je zapotřebý výsledný zdrojový kód přeložit do spustitelného souboru s příponou exe, budeme pracovat v projektu, ke kterému přiřadíme kompilátor. Postup je následující:

  • a) Spustíme textový editor PSPad.

  • b) V menu Projekt zvolíme položku Nový projekt. Tím založíme nový projekt.

  • c) Rovněž v menu Projekt zvolíme volbu Nastavení projektu a v záložce Obecné zadáme do položky Výchozí adresář: cestu k našemu pracovnímu adresáři. Viz následující obrázek:

    pspad_nastaveni_projektu_obecne.jpg
  • d) Pak klikneme na záložku Kompilátor kde vyplníme následující položky:

    • Kompilátor: C:\MinGW\bin\g++.exe

    • Parametry: main.c -o stroje.exe -lalleg (tuto položku budeme postupně doplňovat o další naše knihovny)

    • Výchozí adresář: C:\Tvorba\C\stroje

    Jak je též patrné z obrázku níže:

    pspad_nastaveni_projektu_kompilator.jpg

    Pak nastavení potvrdíme kliknutím na tlačítko OK (nebo klávesou ENTER).

  • e) Založíme hlavní soubor. V menu Soubor zvolíme položku Nový... a v následujícím dialogovém okně vybereme jako typ souboru C/C++. Potvrdíme kliknutím na tlačítko OK. V editoru se otevře prázdný soubor Novy1.c.

    Nyní jej ještě musíme přidat do našeho projektu. V menu Projekt zvolíme volbu Přidat otevřené soubory. Tím se soubor přiřadí k našemu projektu. Zkontrolovat si to můžeme v okně Nástrojový panel, který vyvoláme/skryjeme klávesovou zkratkou CTRL + F2. Dále je ještě třeba celý náš projekt pojmenovat a uložit do našeho pracovního adresáře. Použijeme klávesovou zkratkou SHIFT + CTRL + S. Zobrazí se dialogové okno Uložit jako, kde nastavíme pro položku Uložit do: náš pracovní adresář stroje a dále zadáme název projektu stroje do položky Název souboru: a potvrdíme tlačítkem Uložit. Viz též následující obrázek:

    pspad_projekt_ulozit_jako_mini.jpg

    Pak ještě musíme uložit hlavní soubor. Stiskneme klávesovou zkratku CTRL + S. Opět se vyvolá dialogové okno Uložit jako, kde zadáme do položky Název souboru: jméno hlavního souboru main a potvrdíme tlačítkem Uložit.

    Pak je ještě nutné vložit do projektu hlavní hlavičkový soubor main.h (stejným způsobem jako main.c).

    Postup pro přidání dalších souborů v budoucnu je stejný jako v tomto bodě.

Tím jsme založili náš projekt a vytvořili jsme hlavní soubory main.c a main.h v našem projektu, kam budeme psát kód hry. V budoucnu přibude ještě několik souborů. Ale teď nebudu předbíhat.

4. Programování

Zde se již dostáváme k samotnému programování.

Lekce 1: Základní použití Allegra

Nejdříve si ukážeme, jak se používá knihovna Allegro.

Zdrojový kód je velmi jednoduchý a lze z něho lehce pochopit základní použití knihovny. Jednotlivé klíčové bloky jsou okomentovány.

Na závěr této lekce si ukážeme, jak zkompilovat náš zdrojový kód do spustitelného exe souboru.

Po spuštění program přepne zobrazování do grafického módu a vypíše bílý text doprostřed černé obrazovky. Ukončení programu se provede klávesou F10:


// Lekce 1: Zakladni pouziti Allegra
/*
    Tento kod osvetluje zakladni pouziti Allegra.
    Po spusteni se zobrazi cerna obrazovka s bilym textem uprostred.
    Program se ukonci stiskem klavesy F10.
 */
 
// Vlozeni knihoven
#include <stdio.h>
#include "allegro.h"

// Definice globalnich konstant
// Rozliseni hry a hloubka barev
#define SCREEN_WIDTH      640
#define SCREEN_HEIGHT     480
#define SCREEN_BPP        16

// Potrebujeme inicializovat allegro a nahrat nase data
int InitAll()
{
    if ( allegro_init() != 0 ) {
  		  fprintf(stderr, "Allegro se nepodarilo inicializovat.\n");
		    exit(1);
    }
    install_keyboard();

    /* Nastavime hloubku barev a graficky rezim. V pripade neuspechu se vypise na obrazovku varovna hlaska a program se ukonci. */
    set_color_depth( SCREEN_BPP );
    if ( set_gfx_mode( GFX_AUTODETECT_WINDOWED, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0 ) != 0 ) {
            set_gfx_mode( GFX_TEXT, 0, 0, 0, 0 );
            allegro_message( "Pozadovany graficky mod neni dostupny!\n %s\n" , allegro_error );
            return(-1);
    }

    clear_keybuf ();
    return 0;
}

// Pred ukoncenim hry musime uvolnit nase data z pameti
void DeleteAll()
{
	allegro_exit();
}

// main funkce
int main()
{
    if ( InitAll() < 0 ) return -1;

    clear_keybuf ();
    
    // Vypis bily text na cernem pozadi doprostred obrazovky
    textout_centre_ex( screen, font, "Pro ukonceni programu stiskni F10!", SCREEN_W/2, SCREEN_H/2, makecol( 255 , 255 , 255 ), makecol( 0, 0, 0 ) );

    // Stiskni F10 pro ukonceni hry
    do {
    } while (!key[KEY_F10]);

    DeleteAll();

    return 0;
}
END_OF_MAIN();

Po zkopírování výše vypsaného kódu do našeho main.c (na hlavičkový soubor main.h se dostaneme až v třetím kroku) spustíme kompilátor klávesovou zkratkou CTRL + F9.

Proběhne kompilace našeho zdrojového kódu a její výsledek se zobrazí v okně LOG ve spodní části PSPad editoru. V případě, že kompilace proběhla bezchybně, zobrazí se následující text:

pspad_log_window.jpg

V opačném případě, tj. že překlad neproběhl správně, se v LOG okně vypíše příslušná chyba včetně čísla řádku a funkce, kde se chyba nalézá. Např. při překlepu při zadávání předdefinované hodnoty KEY_F10:

pspad_log_window_bad_msg.jpg

Spustitelný soubor stroje.exe se nachází po zkompilování ve stejného adresáři jako náš zdrojový kód.


> zakladni_pouziti_allegra.zip <


Během programování lze použít též manuál k Allegru, který je distribuován spolu s knihovnou. Je k dispozici hned v několika formátech. Doporučuji však používat html verzi (je v adresáři C:\allegro\docs\html\). Díky barevnému provedení je přehlednější. Spouští se souborem allegro.html.

Lekce 2: Časovač, double buffering

Použít Allegro už tedy umíme. Nyní se zaměříme na plynulou animaci a potažmo i stejně rychlý běh naší hry na všech počítačích. K tomu slouží časovač v našem PC, který bude spouštět náš algoritmus na výpočet nové polohy objektů.

Dále pro vykreslování grafiky použijeme techniku zvanou double buffering. První bitmapa se vykresluje na obrazovku a do druhé kreslíme naše objekty. Když jsme hotovi, vykreslíme druhou na obrazovku a kreslime objekty do prvni. Obraz je tak stálý a nepříjemně nebliká.

Doplněný kód je zvýrazněn zelenou barvou:


// Lekce 2: Casovac, double buffering
/*
    Pouzijeme casovac pro dosazeni stejneho behu hry na vsech PC.
    Pro vykresleni objektu na obrazovce pouzijeme techniku 'double buffering'.
 */

// Vlozeni knihoven
#include <stdio.h>
#include "allegro.h"

// Definice globalnich konstant
// rozliseni hry a hloubka barev
#define SCREEN_WIDTH      640
#define SCREEN_HEIGHT     480
#define SCREEN_BPP        16

// Rychlost hry
#define GAME_SPEED 	      50

// Deklarace globalnich promennych
// deklarace 3 ukazatelu na BITMAPu, 1 promenna pro casovac
BITMAP  *back = NULL;
BITMAP  *page_1, *page_2;
volatile int game_time;

// Citac - po kazdem vyvolani teto funkce se promenna 'game_time' zvysi o 1
void game_timer()
{
    game_time++;
}
END_OF_FUNCTION(game_timer);

// propocitej nove pozice vsech objektu ve hre
void MoveAll()
{

}

// Vykresli vse na obrazovku
/*
    Vse kreslime (pro jednoduchost je to opet jen bily text) do BITMAPy, na kterou
    je aktualne nastaven ukazatel 'back'. Pak se vysledek zobrazi na obrazovce
    a ukazatel se nastavi na druhou BITMAPu, ktera byla az do ted zobrazovana.
    Proces se stale opakuje.
 */
void DrawAll()
{

    // Vypis bily text na cernem pozadi doprostred stranky, na kterou ukazuje 'back'
    textout_centre_ex( back, font, "Pro ukonceni programu stiskni F10!", SCREEN_W/2, SCREEN_H/2, makecol( 255 , 255 , 255 ), makecol( 0, 0, 0 ) );

    // zobraz stranku na obrazovce
    show_video_bitmap(back);

    // nastav ukazatel na druhou stranku
    if (back == page_1) back = page_2;
    else back = page_1;
}

// Potrebujeme inicializovat allegro a nahrat nase data
int InitAll()
{
    if ( allegro_init() != 0 ) {
  		  fprintf(stderr, "Allegro se nepodarilo inicializovat.\n");
		    exit(1);
    }

    install_timer();  // Nainstalujeme casovac
    install_keyboard();

    /* Nastavime hloubku barev a graficky rezim. V pripade neuspechu se vypise na obrazovku varovna hlaska a program se ukonci. */
    set_color_depth( SCREEN_BPP );
    if ( set_gfx_mode( GFX_AUTODETECT_WINDOWED, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0 ) != 0 ) {
            set_gfx_mode( GFX_TEXT, 0, 0, 0, 0 );
            allegro_message( "Pozadovany graficky mod neni dostupny!\n %s\n" , allegro_error );
            return(-1);
    }

    // Uzamkneme citac a jeho promennou
    LOCK_FUNCTION(game_timer);
    LOCK_VARIABLE(game_time);

    // Nastavime citac na preruseni od casovace v nasem PC a zadame mu nami zvolenou rychlost hry
    install_int (game_timer, GAME_SPEED);

    // Vytvorime 2 stranky ve video pameti - obe stejne velke jako rozliseni hry
    // Vytvor 1. stranku (pri neuspechu program skonci)
    page_1 = create_video_bitmap(SCREEN_WIDTH, SCREEN_HEIGHT);
    if (page_1 == NULL) {
        allegro_message( "Nedostatek video pameti pro prvni stranku!\n");
        destroy_bitmap(page_1);
        exit(1);
    }

    // Vytvor 2. stranku (pri neuspechu zrusime 1.stranku a program skonci)
    page_2 = create_video_bitmap(SCREEN_WIDTH, SCREEN_HEIGHT);
    if (page_2 == NULL) {
        allegro_message( "Nedostatek video pameti pro druhou stranku!\n");
        exit(1);
    }

    // Promenne nastavime na pocatecni hodnotu
    back = page_1;
    game_time = 0;
    clear_keybuf ();
    return 0;
}

// Pred ukoncenim hry musime uvolnit nase data z pameti
void DeleteAll()
{
    destroy_bitmap(page_1);
    destroy_bitmap(page_2);
    allegro_exit();
}

// main funkce
int main()
{
    if ( InitAll() < 0 ) return -1;

    // Hlavni smycka hry
    /*
    V pravidelnych intervalech, ktere jsou dany periodou (rychlosti) generovani preruseni
    od casovace v PC, je volana funkce 'game_timer()' (nas citac), ktera pokazde zvysi
    promenou 'game_time' o jednicku. To se deje nezavisle na behu nasi hry. Pokud je tato
    promenna vetsi nez 0, objekty se posunou. V opacnem pripade se jen vykresli na obrazovku.
    Obecne plati, ze cim je 'game_time' vetsi, tim vice se objekty posunuji.
    Jinymi slovy: na pomalych PC se objekty posunuji stejne rychle jako na rychlych PC, ale na
    obrazovce se to projevy trhavymi pohyby.
    Stiskni F10 pro ukonceni hry
    */
    do {
        while (game_time > 0) {
            MoveAll();
            game_time--;
        }
        DrawAll();
    } while (!key[KEY_F10]);

    DeleteAll();
    
    return 0;
}
END_OF_MAIN();

> casovac_doublebuffering.zip <


Lekce 3: Hlavní postava

Dále do naší hry přidáme algoritmus na ovládání a vykreslování hlavní postavy. Bohužel neexistuje žádný univerzální pro všechny typy her. Rovněž to platí o algoritmu herní mapy a pozadí. Ty jsou zpravidla závislé na poloze hlavní postavy (to platí pro všesměrové plošinovky) a nebo se pohybují nezávisle na hlavní postavě (např. střílečky typu 1945, které se pohybují konstantní rychlostí jen v jednom směru). Pro ty druhé je algoritmus o něco jednodušší - ať hráč hraje nebo ne, herní mapa a pozadí se stále pohybují.

Nyní již přijde řada i na hlavičkový soubor main.h, který bude obsahovat tzv. globální proměnné, tj. proměnné, s nimiž budou pracovat i další naše knihovny. Jednu z nich si vytvoříme rovněž v tomto kroku.

Doplněný kód je zvýrazněn zelenou barvou:

ASI SMAZAT: Současný kód už umožňuje přidat algoritmy na řízení postavy. Jednotlivé obrázky hlavní postavy, tzv. frames, už máme připraveny.


// Lekce 3: Potřebujeme hlavní postavu

> rozpohybovani_hlavni_postavy.zip <


Lekce 4: Herní mapa

Dále je třeba si vytvořit program k editaci jednotlivých úrovní naší hry. To lze řešit buď jako samostatný program nebo jako součást hry. Druhé řešení má výhodu v okamžité editaci a následném otestování. Avšak nese to i jednu podstatnou nevýhodu. Pokud se rozhodnete editor nedistribuovat společně s hrou, musíte jej z kódu vymazat. V případě velkého a většinou i dost nepřehledného (to je závislé na Vašich zkušenostech) programu pak hrozí smazání nechtěných částí programu. Což může v lepším případě vést k nefunkčnosti hry, v horším se to nemusí povést ani odladit. Řešením je zapodmínkovat algoritmy související s editorem a provést podmíněný překlad. Ten se sám postará o odstranění nepotřebných algoritmů z výsledného kódu.

V našem příkladu proto zvolíme druhou možnost - editor úrovní bude součástí hry. A názorně si ukážeme jak se takový podmíněný překlad dělá.

Lekce 5: Pozadí

.

Lekce 6: Nepřátelé

.

Lekce 7: Intro, Hlavní menu a Outro

.

Lekce 8: Hudba a zvukové efekty

.

Statistika
Reklama
guestbook_button.jpg navy_button.jpg email_button.jpg