![SDL入門教程(十三).doc_第1頁](http://file.renrendoc.com/FileRoot1/2020-1/11/fa7a87aa-eef5-4263-9267-5123df75f14e/fa7a87aa-eef5-4263-9267-5123df75f14e1.gif)
![SDL入門教程(十三).doc_第2頁](http://file.renrendoc.com/FileRoot1/2020-1/11/fa7a87aa-eef5-4263-9267-5123df75f14e/fa7a87aa-eef5-4263-9267-5123df75f14e2.gif)
![SDL入門教程(十三).doc_第3頁](http://file.renrendoc.com/FileRoot1/2020-1/11/fa7a87aa-eef5-4263-9267-5123df75f14e/fa7a87aa-eef5-4263-9267-5123df75f14e3.gif)
![SDL入門教程(十三).doc_第4頁](http://file.renrendoc.com/FileRoot1/2020-1/11/fa7a87aa-eef5-4263-9267-5123df75f14e/fa7a87aa-eef5-4263-9267-5123df75f14e4.gif)
![SDL入門教程(十三).doc_第5頁](http://file.renrendoc.com/FileRoot1/2020-1/11/fa7a87aa-eef5-4263-9267-5123df75f14e/fa7a87aa-eef5-4263-9267-5123df75f14e5.gif)
已閱讀5頁,還剩9頁未讀, 繼續(xù)免費閱讀
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
SDL入門教程(十三):1、多線程,從動畫說起 作者:龍飛1.1:簡單動畫游戲離不開動畫。我們考慮最簡單的情況:將一個角色從一個位置移動到另外一個位置。這個行為表述給電腦就是,將一個surface不斷的blit(),從起始位置的坐標(biāo),移動到結(jié)束位置的坐標(biāo)。移動速度取決于每次blit()的坐標(biāo)差和blit()的時間間隔(v = ds/dt )。我們來設(shè)計一個函數(shù)實現(xiàn)這個簡單的動畫。我們需要的數(shù)據(jù)有:起始坐標(biāo)(int beginX, int beginY),結(jié)束坐標(biāo)(int endX, int endY),以及作為SDL基礎(chǔ)的ScreenSurface窗口(const ScreenSurface& screen)。一般的考慮是,將這5個數(shù)據(jù)以參數(shù)的方式傳入函數(shù);但是一種更加通用一點的方式是,將這5種數(shù)據(jù)合并成一個結(jié)構(gòu),這樣函數(shù)的參數(shù)形式會更加的統(tǒng)一,這正是觸發(fā)多線程的函數(shù)所需要的。在SDL中,我們通過函數(shù):SDL_Thread *SDL_CreateThread(int (*fn)(void *), void *data);觸發(fā)多線程,其中所需要的函數(shù)指針形式為:typedef int (*fn)(void*);而void*類型的data就是函數(shù)(*fn)()需要的的數(shù)據(jù)。我們可以將任意的結(jié)構(gòu)體指針,轉(zhuǎn)化為void*,作為這個函數(shù)的第二個參數(shù)需要。因此,我們可以為我們需要的動畫函數(shù)定義一個結(jié)構(gòu)作為傳遞所有數(shù)據(jù)的載體:struct AmnArgint beginX;int beginY;int endX;int endY;const ScreenSurface& screen;AmnArg(int begin_x, int begin_y, int end_x, int end_y, const ScreenSurface& _screen): beginX(begin_x), beginY(begin_y), endX(end_x), endY(end_y), screen(_screen);這樣,我們可以將AmnArg對象的指針傳遞給動畫函數(shù)考慮到多線程函數(shù)的需要,我們再曲折一點:先將AmnArg*轉(zhuǎn)換成void*傳遞給函數(shù),在函數(shù)內(nèi)部再將其轉(zhuǎn)換回來以供調(diào)用。int amn(void* data)AmnArg* pData = (AmnArg*)data;PictureSurface stand(./images/am01.png, pData-screen);stand.colorKey();PictureSurface bg(./images/background.png, pData-screen);const int SPEED_CTRL = 300;int speedX = (pData-endX - pData-beginX) / SPEED_CTRL;int speedY = (pData-endY - pData-beginY) / SPEED_CTRL;for ( int i = 0; i beginX += speedX;pData-beginY += speedY;bg.blit(pData-beginX, pData-beginY, pData-beginX, pData-beginY, stand.point()-w, stand.point()-h, 2, 2);stand.blit(pData-beginX, pData-beginY);pData-screen.flip();return 0;注意:我們這里僅僅設(shè)定了每次blit()的位移差(ds)而沒有設(shè)定時間差(dt)。這并不意味著dt = 0,事實上,電腦處理數(shù)據(jù)是需要時間的,包括運算和顯示。我們這里事實上將dt的設(shè)定交給了電腦,也就是說,讓電腦以其最快的速度來完成。為什么要這么做呢?這是為了演示多線程的一個現(xiàn)象,賣個關(guān)子,后面解釋。:)1.2:動畫函數(shù)在主程序中的調(diào)用#include SurfaceClass.hpp#include amn.hppint main(int argc ,char* argv)/Create a SDL screen.const int SCREEN_WIDTH = 640;const int SCREEN_HEIGHT = 480;const Uint32 SCREEN_FLAGS = 0; /SDL_FULLSCREEN | SDL_DOUBLEBUF | SDL_HWSURFACEconst std:string WINDOW_NAME = Amn Test;ScreenSurface screen(SCREEN_WIDTH, SCREEN_HEIGHT, WINDOW_NAME, 0, SCREEN_FLAGS);PictureSurface bg(./images/background.png, screen);bg.blit(0);screen.flip();AmnArg test1(0, 250, 600, 250, screen);amn(void*)&test1);SDL_Event gameEvent;bool gameOver = false;while ( gameOver = false )while ( SDL_PollEvent(&gameEvent) != 0 )if ( gameEvent.type = SDL_QUIT )gameOver = true;if ( gameEvent.type = SDL_KEYDOWN )if ( gameEvent.key.keysym.sym = SDLK_ESCAPE )gameOver = true;screen.flip();return 0;當(dāng)這個程序運行的時候,我們會發(fā)現(xiàn)一些很明顯的問題:1、圖片移動的時候,界面不接受任何信息。這是因為必須把amn()執(zhí)行完畢才會運行到有事件響應(yīng)的事件輪詢循環(huán)。2、如果我們需要另外一張圖片移動起來,我們唯一能做的事情,是修改amn()函數(shù),而不是把amn()以不同的參數(shù)調(diào)用兩次如果以不同的參數(shù)調(diào)用兩次,那么移動總是有先后的是不可能完成“同時”移動的。1.3:創(chuàng)建線程如果要將這個程序從主線程(主進(jìn)程)調(diào)用函數(shù)修改為通過新創(chuàng)建的線程調(diào)用函數(shù),只需要做很小的修改,即將amn(void*)&test1);修改為:SDL_Thread* thread1 = SDL_CreateThread(amn, (void*)&test1);然后在return 0;之前加入清理線程的語句:SDL_KillThread(thread1);這樣,程序在執(zhí)行動畫的同時,事件輪詢就已經(jīng)開始,我們可以隨時結(jié)束程序,SDL界面也不會出現(xiàn)不響應(yīng)的情況。SDL入門教程(十三):2、初識多線程 作者:龍飛2.1:競爭條件(Race Conditions)我們在前面將一個普通函數(shù)調(diào)用轉(zhuǎn)換成了用線程調(diào)用,這意味著我們可以“同時”調(diào)用兩個以上的線程。例如,我們希望在屏幕的另外一個位置也播放這段簡單的動畫,我們只需要添加一個線程的調(diào)用就可以了。int main(int argc ,char* argv)/Create a SDL screen.const int SCREEN_WIDTH = 640;const int SCREEN_HEIGHT = 480;const Uint32 SCREEN_FLAGS = 0; /SDL_FULLSCREEN | SDL_DOUBLEBUF | SDL_HWSURFACEconst std:string WINDOW_NAME = Amn Test;ScreenSurface screen(SCREEN_WIDTH, SCREEN_HEIGHT, WINDOW_NAME, 0, SCREEN_FLAGS);PictureSurface bg(./images/background.png, screen);bg.blit(0);screen.flip();AmnArg test1(0, 250, 600, 250, screen);SDL_Thread* thread1 = SDL_CreateThread(amn, (void*)&test1);AmnArg test2(0, 0, 600, 0, screen);SDL_Thread* thread2 = SDL_CreateThread(amn, (void*)&test2);SDL_Event gameEvent;bool gameOver = false;while ( gameOver = false )while ( SDL_PollEvent(&gameEvent) != 0 )if ( gameEvent.type = SDL_QUIT )gameOver = true;if ( gameEvent.type = SDL_KEYDOWN )if ( gameEvent.key.keysym.sym = SDLK_ESCAPE )gameOver = true;screen.flip();SDL_KillThread(thread1);SDL_KillThread(thread2);return 0;這段程序看起來似乎沒有什么問題,但是運行的時候,不可預(yù)知的情況出現(xiàn)了:理論上我們幾乎同時調(diào)用了兩個線程,動畫似乎應(yīng)該是同步播放的,但是實際上,兩段動畫的播放并不同步,并且每次執(zhí)行的效果都不一樣有時候上面的圖片移動快,有時候下面的圖片移動快,并且速度不均勻。這就是典型的race conditions的表現(xiàn)。還記得我說過沒有定義dt嗎,我們讓電腦以其所能達(dá)到的最快速度決定dt,換句話說,我們每一個線程都試圖“咬死”CPU的運算,當(dāng)然,在實際中多任務(wù)的OS會幫助CPU分配任務(wù),但是如何分配卻是不確定的,因為OS并不知道哪些任務(wù)需要優(yōu)先執(zhí)行,所以,兩個線程實際上在競爭電腦的性能資源,產(chǎn)生的結(jié)果就是不確定的。2.2:松開“死咬”的CPUvoid SDL_Delay(Uint32 ms);解決race conditions的方法就是給CPU足夠的時間“休息”,而這正好也是我們自己定義dt所需要的。SDL_Delay()在這個時候就顯得意義重大了。當(dāng)今電腦的運算速度非常非??欤灾劣谀呐挛覀儍H僅給電腦0.01秒的時間“休息”(每次循環(huán)中),電腦都會顯得很輕松了。int amn(void* data)AmnArg* pData = (AmnArg*)data;PictureSurface stand(./images/am01.png, pData-screen);stand.colorKey();PictureSurface bg(./images/background.png, pData-screen);const int SPEED_CTRL = 300;int speedX = (pData-endX - pData-beginX) / SPEED_CTRL;int speedY = (pData-endY - pData-beginY) / SPEED_CTRL;for ( int i = 0; i beginX += speedX;pData-beginY += speedY;bg.blit(pData-beginX, pData-beginY, pData-beginX, pData-beginY, stand.point()-w, stand.point()-h, 2, 2);stand.blit(pData-beginX, pData-beginY);pData-screen.flip();SDL_Delay(10);return 0;說到這里,我們不得不提及之前一直所忽略的一個問題:我們之前凡是涉及循環(huán)等待事件輪詢的程序總是占用100%的CPU,這并不是因為我們真正用到了100%的CPU性能,而是我們讓CPU陷入了“空等”(Busy Waiting)的尷尬境地。輪詢事件得到響應(yīng)相對于循環(huán)等待來說,是發(fā)生得非常緩慢的事情,我們在循環(huán)中,哪怕是讓電腦休息0.01秒,事情都會發(fā)生本質(zhì)性的改變:while ( gameOver = false )while ( SDL_PollEvent(&gameEvent) != 0 )if ( gameEvent.type = SDL_QUIT )gameOver = true;if ( gameEvent.type = SDL_KEYDOWN )if ( gameEvent.key.keysym.sym = SDLK_ESCAPE )gameOver = true;screen.flip();SDL_Delay(10);當(dāng)我們重新運行新程序的時候,我們可以看到程序?qū)PU的占用從100%驟降到了0%!這當(dāng)然并不意味著程序就用不上CPU了,而是說,這些運算對于我們的CPU來說,實在是小菜一碟了,或者從數(shù)據(jù)上說,處理這些運算的時間與0.01秒來比較,都幾乎可以忽略不計!2.3:GUI線程與worker線程我們的另外一項試驗是將事件輪詢放到動畫線程中,程序就不多寫了,大家可以自己試下。我直接說結(jié)論:動畫線程中無法響應(yīng)事件輪詢。一般提倡的模式,是將GUI事件都寫在主線程中,而將純粹的運算才寫到由主線程創(chuàng)建的線程中,后者也就是所謂的worker線程。從另外一個概念看,只有主線程控制著“當(dāng)前窗口”,其它線程也許在后臺,也許雖然也是在前臺但是并非是我們可見的,所以,輪詢事件找不到接口。對于拋出的線程與主線程之間的通訊,我們可以通過他們共享的數(shù)據(jù)來進(jìn)行控制,所以,盡管事件輪詢不能直接影響worker線程,但是我們?nèi)匀皇强梢酝ㄟ^主線程進(jìn)行間接影響的。SDL入門教程(十三):3、封裝多線程 作者:龍飛SDL創(chuàng)建多線程的函數(shù)SDL_CreateThread()所調(diào)用的是函數(shù)指針,這意味著我們不可以傳入(非靜態(tài))成員函數(shù)的指針。關(guān)于兩種函數(shù)指針我們之前已經(jīng)討論過:函數(shù)指針與成員函數(shù)指針,我們可以有兩種方法能讓具有普通函數(shù)指針(函數(shù)指針以及靜態(tài)成員函數(shù)指針)的函數(shù)調(diào)用類的私有成員,一是友元函數(shù),另外就是靜態(tài)成員函數(shù)。而能夠受到類私有保護(hù)的,只有靜態(tài)成員函數(shù)。所以,我們可以通過靜態(tài)成員函數(shù)調(diào)用一個對象數(shù)據(jù)的形式,實現(xiàn)對于創(chuàng)建多線程函數(shù)的封裝。另外,我們希望測試在主線程中讀寫線程數(shù)據(jù)的效果,所以添加了兩個方法show() 和reset(),多線程演示的類源代碼如下:#include #include SurfaceClass.hppclass AmnArgprivate:int beginX;int beginY;int endX;int endY;const ScreenSurface& screen;/static int amn(void* pThat);public:AmnArg(int begin_x, int begin_y, int end_x, int end_y, const ScreenSurface& _screen);SDL_Thread* createThrd();void show() const;void reset();其中SurfaceClass.hpp請參考:/lf426/archive/2008/04/14/47038.html實現(xiàn)函數(shù)如下:#include amn.hppAmnArg:AmnArg(int begin_x, int begin_y, int end_x, int end_y, const ScreenSurface& _screen):beginX(begin_x), beginY(begin_y), endX(end_x), endY(end_y), screen(_screen)SDL_Thread* AmnArg:createThrd()return SDL_CreateThread(amn, (void*)this);void AmnArg:show() conststd:cout Now x at: beginX screen);stand.colorKey();PictureSurface bg(./images/background.png, pData-screen);const int SPEED_CTRL = 300;int speedX = (pData-endX - pData-beginX) / SPEED_CTRL;int speedY = (pData-endY - pData-beginY) / SPEED_CTRL;for ( int i = 0; i beginX += speedX;pData-beginY += speedY;bg.blit(pData-beginX, pData-beginY, pData-beginX, pData-beginY, stand.point()-w, stand.point()-h, 2, 2);stand.blit(pData-beginX, pData-beginY);pData-screen.flip();SDL_Delay(10);return 0;最后,我們修改了主演示程序,并測試了show()和reset()的效果。我們可以看到,直接修改線程數(shù)據(jù)的reset()的結(jié)果也是不可預(yù)知的,所以,我們似乎更應(yīng)該通過改變線程“流”的效果,而不是直接對數(shù)據(jù)進(jìn)行修改。這個我們以后再討論了。#include SurfaceClass.hpp#include amn.hppint game(int argc ,char* argv);int main(int argc ,char* argv)int mainRtn = 0;try mainRtn = game(argc, argv);catch ( const ErrorInfo& info ) info.show();return -1;catch ( const char* s ) std:cerr s std:endl;return -1;return mainRtn;int game(int argc ,char* argv)/Create a SDL screen.const int SCREEN_WIDTH = 640;const int SCREE
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 汽車智能化的移動互聯(lián)網(wǎng)技術(shù)探討
- 現(xiàn)代餐飲業(yè)的線上線下融合策略
- 未來教育模式基于AI技術(shù)的智能學(xué)習(xí)系統(tǒng)研究
- 物流管理在醫(yī)療電子商務(wù)中的重要性
- 現(xiàn)代經(jīng)濟(jì)預(yù)測模型的發(fā)展趨勢及挑戰(zhàn)
- Unit 3 Toys Story Time(說課稿)-2023-2024學(xué)年人教新起點版英語一年級下冊
- 班組長決策能力與戰(zhàn)略思維培養(yǎng)
- 現(xiàn)代物流技術(shù)與裝備的未來展望
- 七年級地理下冊 第七章 我們鄰近的國家和地區(qū) 7.3 印度說課稿 (新版)新人教版
- 北京2025年北京小湯山醫(yī)院招聘筆試歷年參考題庫附帶答案詳解
- 2025江蘇南京市金陵飯店股份限公司招聘高頻重點提升(共500題)附帶答案詳解
- 公共政策分析 課件匯 陳振明 第0-9章 導(dǎo)論、緒論:政策科學(xué)的“研究綱領(lǐng)”- 政策監(jiān)控
- C語言程序設(shè)計 教案
- 2025年牛津譯林版英語七年級下冊全冊單元重點知識點與語法匯編
- 《小學(xué)作文指導(dǎo)》課件
- 小學(xué)六年級數(shù)學(xué)方程應(yīng)用題100道及答案解析
- 2025新譯林版英語七年級下單詞表
- 海洋工程設(shè)備保溫保冷方案
- 文藝演出排練指導(dǎo)服務(wù)合同
- 人教版(2024新版)一年級上冊數(shù)學(xué)第一單元《數(shù)學(xué)游戲》單元整體教學(xué)設(shè)計
- 魏寧海超買超賣指標(biāo)公式
評論
0/150
提交評論