..::Plynulß animace v MFC 3::..

Jestli jst u₧ zaΦali pou₧φvat postupy z minul²ch dvou dφl∙, mo₧nß jste si vÜimli dvou chyb. Ta prvnφ nenφ vß₧nß a pouze znep°φjemnφ ₧ivot programßtorovi. Zkrßtka a jednoduÜe pokud podle mΘho nßvodu z prvnφho dφlu p°epφÜete funkci Run, p°estanou vßm ve vaÜφ aplikaci fungovat klßvesovΘ zkratky (accelerators). Ta druhß je mnohem horÜφ a pravd∞podobn∞ na ni p°ijdete teprve a₧ zaΦnete testovat svou aplikaci na jinΘm PC. Pokud podle mΘho nßvodu zßrove≥ s p°ekreslenφm p°epoΦφtßvßte i pozice vykreslovan²ch objekt∙ tak rychlost jejich pohybu bude zßviset na ryhclosti PC. Tj. na n∞jakΘm starÜφm PC vßm hra p∙jde tou sprßvnou rychlostφ, a kdy₧ ji spustφte na n∞jakΘm extrav²konΘm poΦφtaΦi tak ani nebudete staΦit sledovat co se na obrazovce d∞je. (Jestli pamatujete tak stejn² problΘm byl i s hrami pro DOS.)

Ale nezoufejte. Ob∞ chyby jdou pom∞rn∞ jednoduÜe odstranit. ZaΦneme tou jednoduÜÜφ.

KlßvesovΘ zkratky se nep°eklßdajφ v procedu°e okna, ale jeÜt∞ p°edtφm ne₧ se zprßva do procedury okna dostane ve funkci PreTranslateMessage. A tφm jak jsme p°epsali funkci Run jsme zßrove≥ zruÜili jejφ volßnφ. Na odstran∞nφ je jednoduch² recept. Prost∞ tam to volßnφ p°idßme a funkce Run pak vypadß takto:

int CTstApp::Run()

{

// TODO: Add your specialized code here and/or call the base class

MSG msg;

 

while(1)

{

if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))    // Pokud je ve front∞ zprßva zpracujeme ji

{

if (msg.message==WM_QUIT) break;    // Pokud je zprßva WM_QUIT ukonΦφme smyΦku (a tφm i aplikaci)

// Zavolßme funkci PreTranslateMessage. Ta vrßtφ TRUE pokud zprßvu zpracovala a nenφ t°eba ji posφlat do procedury okna.

if (!PreTranslateMessage(&msg))    

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}

else    // Jinak vyvolßme p°ekreslenφ

{

if (pView) pView->Redraw();

}

}

 

return 0;

}

Druhß chyba je horÜφ a to i na odstran∞nφ. Ty rozdφlnΘ rychlosti jsou zp∙sobeny tφm, ₧e se p°ekreslenφ volß v nekoneΦnΘm cyklu a ka₧d² poΦφtaΦ jej stihne provΘst za jinou dobu. Pomoc je takovßto. P°ekreslenφ vyvolat jen pokud ub∞hl urΦit² Φas. Te∩ je ale problΘm s tφm jak m∞°it ub∞hl² Φas s dostateΦnou p°esnostφ. Nabφdnu vßm dv∞ mo₧nosti. (Ale popφÜi jen tu jednoduÜÜφ.) K dostateΦn∞ p°esnΘmu m∞°enφ Φasu m∙₧ete pou₧φt bu∩ funkci timeGetTime, kterß vracφ Φas ub∞hl² od startu Windows v milisekundßch nebo dvojici funkcφ, kterΘ m∞°φ jeÜt∞ p°esn∞ji, ale jejich fungovßnφ zßvisφ na hardwaru a to QueryPerformanceFrequency (pro zjiÜt∞nφ frekvence) a QueryPerformanceCounter (pro zjiÜt∞nφ hodnoty kterß je na poΦφtadle, d∞lenφm tΘto hodnoty frekvencφ zφskßte Φas v sekundßch).

Funkce timeGetTime je deklarovßna v hlaviΦkovΘm souboru mmsystem.h a musφte jeÜt∞ vlo₧it lib soubor winmm.lib.

Potom bude funkce Run vypadat takto:
(Nßsledujφcφ k≤d p°edpoklßdß, ₧e mßte ve svΘ t°φd∞ p°idßny prom∞nnΘ time_start a interval (typu DWORD) a prom∞nnou interval v konstruktoru nastavenou na po₧adovan² interval p°ekreslenφ. M∞lo by staΦit asi 25 (ms).)

int CTstApp::Run()

{

// TODO: Add your specialized code here and/or call the base class

MSG msg;

 

time_start = timeGetTime();

 

while(1)

{

if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))    // Pokud je ve front∞ zprßva zpracujeme ji

{

if (msg.message==WM_QUIT) break;    // Pokud je zprßva WM_QUIT ukonΦφme smyΦku (a tφm i aplikaci)

// Zavolßme funkci PreTranslateMessage. Ta vrßtφ TRUE pokud zprßvu zpracovala a nenφ t°eba ji posφlat do procedury okna.

if (!PreTranslateMessage(&msg))    

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}

else    // Jinak vyvolßme p°ekreslenφ

{

if (pView)

{

if ((timeGetTime()-time_start)>=interval) // Pokud vyprÜel interval

{

pView->Redraw();                                    // P°ekreslφme

time_start = timeGetTime();                    // Resetujeme interval

}

}

}

}

 

return 0;

}

Obdobn∞ je t°eba upravit i funkci vlßkna, pokud jej pou₧φvßte mφsto p°epsßnφ Run.

Nebo pro m∞°enφ Φasu m∙₧ete pou₧φt moji t°φdu CPeriod, kterou si m∙₧ete stßhnout zde a kterß umo₧≥uje m∞°enφ i pomocφ t∞ch p°esn∞jÜφch funkcφ.