článek

Udělej si vlastní hru – VII. část

Udělej si vlastní hru – VII. část

S mírným zpožděním vám přinášíme další díl našeho seriálu z cyklu, v redaktorské hantýrce nazvaného "urob si sám". :) Tentokrát se bude jednat o díl poslední se zaměřením na zvuky.

V závěrečném dílu tohoto seriálu již mnoho nového, co by se zároveň přímo týkalo programování hry neprobereme. Jen pro jakousi kompletnost si v rychlosti ukážeme, jak hře zajistit základní ozvučení - pomocí oblíbené knihovny fmod - ale možných řešení se opět, podobně jako třeba v případě grafického rozhraní, nabízí spousta, takže toto rozhodně nikomu nevnucuji.



Jako další si ukážeme ještě jednoduchý timer, čili jakýsi měřák času a věcí s tím souvisejících. timer také není věc, která přímo souvisí s herními mechanismy, nicméně většina her ho různými způsoby využívá (ať už to je jen k výpočtu FPS, nebo i v míře větší).



Na úplný závěr můžeme udělat takové malé shrnutí a také naznačit, co by se ještě do hry slušelo a patřilo dodělat, aby s ní potenciální vývojář mohl "jít ven" :-).



Zvuk



Jak jsem již několikrát uvedl, použijeme knihovnu fmod. Zvuková knihovna je poměrně dost oblíbená, mimo jiné i pro to, že je multiplatformní. Základní informace i dokumentaci, ale i instalátor vývojářského API můžete získat na adrese www.fmod.org . My použijeme jen základy - načteme několik zvuků, které v okamžiku, kdy k tomu nastane vhodná doba, přehrajeme. Podrobně nebudu práci jednotlivých funkcí rozebírat (jako jsem to nedělal ani u funkcí grafického API), k tomu slouží jejich dokumentace. Nejprve si vytvoříme datovou strukturu SOUND, která bude sloužit k reprezentaci jednotlivých zvuků v paměti. Tato struktura vypadá následovně:



struct SOUND
{

FSOUND_SAMPLE *pSound; //ukazatel na zvukový objekt

int soundChannel; //kanál pro přehrávání zvuku

unsigned timer, len; //časovač a délka zvuku

};




Proměnné pSound a soundChannel slouží knihovně fmod pro práci se zvukem při jeho přehrávání, proměnná timer slouží při cyklickém přehrávání zvuku (např. kroky při chůzi) k časování (podobně jako při animaci) a proměnná len udává délku trvání daného zvuku (v milisekundách).



Na začátku je potřeba zvuky načíst, to provedeme funkcí LoadSounds:



void LoadSounds(void)
{

if(FSOUND_Init(44100, 32, FSOUND_INIT_GLOBALFOCUS))

{

music.pSound = FSOUND_Sample_Load (FSOUND_FREE, "data/sound/bgmusic.mp3",0,0);



boom.pSound = FSOUND_Sample_Load(FSOUND_FREE,"data/sound/boom.wav",0,0);

step.pSound = FSOUND_Sample_Load(FSOUND_FREE,"data/sound/step.wav",0,0);



step.len = 450;

boom.len = EXPLOSION_TIME / 3;

music.len = 126000;

}

else

{

MessageBox(NULL,"Selhala inicializace zvuku!","SOUND ERROR",MB_OK | MB_ICONWARNING);

}

}



Zde načítáme celkem 3 zvuky, a to hudbu (music), zvuk výbuchu (boom) a zvuk kroku (step). Před tím jsme tyto zvuky samozřejmě deklarovali v globálních proměnných. Po jejich načtení ještě "ručně" nastavíme jejich délku - ta by šla ovšem zjišťovat i některou funkcí, vypadalo by to i elegantněji...



Nyní si ukážeme ještě funkci PlaySounds, která již podle svého názvu slouží k přehrávání jednotlivých zvuků během hry:



void PlaySounds(void)
{

if(Mario.walking && GetTickCount() - step.timer >= step.len)

{

step.timer = GetTickCount();

step.soundChannel = FSOUND_PlaySound(FSOUND_FREE,step.pSound);

}



for(int i=0; i < BOMB_TYPES; ++i)

{

if(bombs[i].explosion_st == 1 && GetTickCount() - boom.timer >= boom.len)

{

boom.timer = GetTickCount();

boom.soundChannel = FSOUND_PlaySound(FSOUND_FREE,boom.pSound);

}

}



if(GetTickCount() - music.timer >= music.len)

{

music.timer = GetTickCount();

music.soundChannel = FSOUND_PlaySound(FSOUND_FREE,music.pSound);

}

}



Funkce PlaySounds je volána cyklicky před každým zavoláním funkce Render.
Nejprve zjišťujeme, zda se má přehrát zvuk chůze. Tato situace nastane pokud se Mario pohybuje (walking je true) a zároveň již skončilo minulé přehrávání tohoto zvuku (k tomu nám poslouží proměnné timer a len). Dále prověříme. zda se má přehrát zvuk explodující bomby - to nastane tehdy, pokud některá bomba má explosion_st roven 1 - tedy právě začala její exploze. Nakonec zkontrolujeme, zda se má znovu začít přehrávat doprovodná hudba, pokud ano, tak ji začneme přehrávat znovu.



Zvuky výbuchu a kroku jsem převzal z freewarových zdrojů, hudbu si můžete doplnit dle vlastního vkusu, nezapomeňte však nastavit její správnou délku ve funkci LoadSounds.




Timer



Pro funkci timeru si zavedeme několik globálních proměnných:




__int64 lastTime, m_timerStart, m_frequency, m_lastTime, m_currentTime;

float m_resolution;

double m_frameTime,m_fpsCounter,m_fps,m_fpsMax;

int m_frames;




Funkcí CreateTimer provedem jeho vytvoření (inicializaci). Tato funkce budiž volána např. ve funkci InitD3D nebo jinde na začátku programu.



void Create_timer()
{

if (QueryPerformanceFrequency((LARGE_INTEGER*)&m_frequency))

{

QueryPerformanceCounter((LARGE_INTEGER*)&m_timerStart);

m_resolution = (float)(1.0 / (double) m_frequency) * 1.0f;

}

}



Funkce QueryPerformanceFrequency a QueryPerformanceCounter jsou deklarovány ve windows.h. My vytvoříme timer o frekvenci, která bude uložena v m_frequency, počáteční čas (počet tiků) ve chvíli vytvoření timeru uložíme do m_timerStart.



Na čas se v případě potřeby budeme dotazovat funkcí GetTime



double GetTime()
{

__int64 timeElapsed;



QueryPerformanceCounter((LARGE_INTEGER*)&timeElapsed);

timeElapsed -= m_timerStart;


return timeElapsed * m_resolution;

}



Její práce je vcelku zřejmá - vrátí čas, který uplynul od vytvoření timeru. Ještě budeme používat funkci UpdateTimer, která bude sloužit k průběžnému počítání FPS:



void UpdateTimer()
{

m_currentTime = (__int64)GetTime();



m_frameTime = (double)(m_currentTime - m_lastTime) / 1.0;



m_frames++;

m_fpsCounter += m_frameTime;

if (m_fpsCounter >= 0.25)

{

m_fps = (m_frames / m_fpsCounter);



m_fpsCounter = 0.0;

m_frames = 0;



if (m_fps > m_fpsMax)

{

m_fpsMax = m_fps;

}

}



m_lastTime = m_currentTime;

}



Její funkce je též celkem zřejmá - funkcí zjistíme jednak čas potřebný na jeden snímek a zároveň i počet snímků za sekundu (tedy FPS).



A jako poslední ukážu deklaraci funkce FPSLimit, která bude sloužit k omezení počtu FPS, aby hra na některých počítačích neběžela příliš rychle:



void FPSLimit(int FPSmax)
{

if(FPSmax!=NULL)

{

if (m_frameTime < (float)(1.0/FPSmax))

{

double a=0.0,lim=GetTime();

while(a-lim<(float)(1.0/FPSmax)-m_frameTime)

{

a=GetTime();

}

}

}

}



Pokud je hodnota FPS příliš vysoká, pak funkce "pozdrží" každý snímek tak dlouho, aby hodnota FPS klesla na požadovanou mez - tímto tedy nahradíme dosavadně používanou funkci Wait.



Funkce FPSLimit i funkce UpdateTimer jsou cyklicky volané během kreslení každého snímku - tedy opět při každém volání funkce Render.




Závěr



Tímto jsme se tedy dopracovali až na úplný konec našeho seriálu. Ukázali jsme si implementaci všech důležitých herních mechanismů a i té nejnutnější "omáčky" okolo. Ná Vás je již buď další kosmetické vylepšení této herní kostry - např. vytvořit úvodní menu, jednotlivé levely, počítání skore apod. , nebo se můžete jen inspirovat a od základů vybudovat čistě Váš herní projekt...



Přeji Vám mnoho úspěchů a málo bugů!



Hudební soubory: 322_sedma_cast.zip




Související odkazy:








jan_kohout

autor
/ jan_kohout

Publikováno: 27.06.2007


další články této kategorie





diskuze

odeslat

Nejsi automat? Napiš výsledek 4 + 5 =

phanka

phanka | 21.04.15 v 21:29

raději to nechám odborníkům

m-&gt; 29 | 12.11.09 v 20:59

Ja som skôr myslel zdrojové súbory na články "Udělej si vlastní hru – #. část" Linky na články "TVORBA: Vytvoř si svou bludišťovku – #" mi fungujú :-)

Freegame | 12.11.09 v 00:44

Odkaz na ZIP s priklady je zde:

http://download1.freegame.cz/bludistovka_zdroj/bludistovka_zdroje.zip

m-&gt; 29 | 10.11.09 v 22:13

No, neviem či to tu už nie je mŕtve, alebo ako, ale nejdú mi stiahnuť zdrojové kódy v žiadnom z článkov. Nemôže ich niekto niekam uploadnúť alebo poslať mi na mail? Najlepšie by ale bolo opraviť linky ;-) Dík moc

MUDr. Mstibor Háborů | 15.03.09 v 12:49

A ten exáč by byl k čemu, prosím pěkně? Smyslem článku je ukázat, jak se hry programují.

Bildo | 14.03.09 v 23:32

Taky si myslim, ze na zaver by se mozna hodil i exac? Nebo nee?

Nixk | 05.10.08 v 18:39

a Ten progra by nebyl???