已閱讀5頁(yè),還剩9頁(yè)未讀, 繼續(xù)免費(fèi)閱讀
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
SDL入門教程(十三):1、多線程,從動(dòng)畫說起 作者:龍飛1.1:簡(jiǎn)單動(dòng)畫游戲離不開動(dòng)畫。我們考慮最簡(jiǎn)單的情況:將一個(gè)角色從一個(gè)位置移動(dòng)到另外一個(gè)位置。這個(gè)行為表述給電腦就是,將一個(gè)surface不斷的blit(),從起始位置的坐標(biāo),移動(dòng)到結(jié)束位置的坐標(biāo)。移動(dòng)速度取決于每次blit()的坐標(biāo)差和blit()的時(shí)間間隔(v = ds/dt )。我們來(lái)設(shè)計(jì)一個(gè)函數(shù)實(shí)現(xiàn)這個(gè)簡(jiǎn)單的動(dòng)畫。我們需要的數(shù)據(jù)有:起始坐標(biāo)(int beginX, int beginY),結(jié)束坐標(biāo)(int endX, int endY),以及作為SDL基礎(chǔ)的ScreenSurface窗口(const ScreenSurface& screen)。一般的考慮是,將這5個(gè)數(shù)據(jù)以參數(shù)的方式傳入函數(shù);但是一種更加通用一點(diǎn)的方式是,將這5種數(shù)據(jù)合并成一個(gè)結(jié)構(gòu),這樣函數(shù)的參數(shù)形式會(huì)更加的統(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*,作為這個(gè)函數(shù)的第二個(gè)參數(shù)需要。因此,我們可以為我們需要的動(dòng)畫函數(shù)定義一個(gè)結(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對(duì)象的指針傳遞給動(dòng)畫函數(shù)考慮到多線程函數(shù)的需要,我們?cè)偾垡稽c(diǎn):先將AmnArg*轉(zhuǎn)換成void*傳遞給函數(shù),在函數(shù)內(nèi)部再將其轉(zhuǎn)換回來(lái)以供調(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è)定時(shí)間差(dt)。這并不意味著dt = 0,事實(shí)上,電腦處理數(shù)據(jù)是需要時(shí)間的,包括運(yùn)算和顯示。我們這里事實(shí)上將dt的設(shè)定交給了電腦,也就是說,讓電腦以其最快的速度來(lái)完成。為什么要這么做呢?這是為了演示多線程的一個(gè)現(xiàn)象,賣個(gè)關(guān)子,后面解釋。:)1.2:動(dòng)畫函數(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)這個(gè)程序運(yùn)行的時(shí)候,我們會(huì)發(fā)現(xiàn)一些很明顯的問題:1、圖片移動(dòng)的時(shí)候,界面不接受任何信息。這是因?yàn)楸仨毎補(bǔ)mn()執(zhí)行完畢才會(huì)運(yùn)行到有事件響應(yīng)的事件輪詢循環(huán)。2、如果我們需要另外一張圖片移動(dòng)起來(lái),我們唯一能做的事情,是修改amn()函數(shù),而不是把a(bǔ)mn()以不同的參數(shù)調(diào)用兩次如果以不同的參數(shù)調(diào)用兩次,那么移動(dòng)總是有先后的是不可能完成“同時(shí)”移動(dòng)的。1.3:創(chuàng)建線程如果要將這個(gè)程序從主線程(主進(jìn)程)調(diào)用函數(shù)修改為通過新創(chuàng)建的線程調(diào)用函數(shù),只需要做很小的修改,即將amn(void*)&test1);修改為:SDL_Thread* thread1 = SDL_CreateThread(amn, (void*)&test1);然后在return 0;之前加入清理線程的語(yǔ)句:SDL_KillThread(thread1);這樣,程序在執(zhí)行動(dòng)畫的同時(shí),事件輪詢就已經(jīng)開始,我們可以隨時(shí)結(jié)束程序,SDL界面也不會(huì)出現(xiàn)不響應(yīng)的情況。SDL入門教程(十三):2、初識(shí)多線程 作者:龍飛2.1:競(jìng)爭(zhēng)條件(Race Conditions)我們?cè)谇懊鎸⒁粋€(gè)普通函數(shù)調(diào)用轉(zhuǎn)換成了用線程調(diào)用,這意味著我們可以“同時(shí)”調(diào)用兩個(gè)以上的線程。例如,我們希望在屏幕的另外一個(gè)位置也播放這段簡(jiǎn)單的動(dòng)畫,我們只需要添加一個(gè)線程的調(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;這段程序看起來(lái)似乎沒有什么問題,但是運(yùn)行的時(shí)候,不可預(yù)知的情況出現(xiàn)了:理論上我們幾乎同時(shí)調(diào)用了兩個(gè)線程,動(dòng)畫似乎應(yīng)該是同步播放的,但是實(shí)際上,兩段動(dòng)畫的播放并不同步,并且每次執(zhí)行的效果都不一樣有時(shí)候上面的圖片移動(dòng)快,有時(shí)候下面的圖片移動(dòng)快,并且速度不均勻。這就是典型的race conditions的表現(xiàn)。還記得我說過沒有定義dt嗎,我們讓電腦以其所能達(dá)到的最快速度決定dt,換句話說,我們每一個(gè)線程都試圖“咬死”CPU的運(yùn)算,當(dāng)然,在實(shí)際中多任務(wù)的OS會(huì)幫助CPU分配任務(wù),但是如何分配卻是不確定的,因?yàn)镺S并不知道哪些任務(wù)需要優(yōu)先執(zhí)行,所以,兩個(gè)線程實(shí)際上在競(jìng)爭(zhēng)電腦的性能資源,產(chǎn)生的結(jié)果就是不確定的。2.2:松開“死咬”的CPUvoid SDL_Delay(Uint32 ms);解決race conditions的方法就是給CPU足夠的時(shí)間“休息”,而這正好也是我們自己定義dt所需要的。SDL_Delay()在這個(gè)時(shí)候就顯得意義重大了。當(dāng)今電腦的運(yùn)算速度非常非??欤灾劣谀呐挛覀儍H僅給電腦0.01秒的時(shí)間“休息”(每次循環(huán)中),電腦都會(huì)顯得很輕松了。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;說到這里,我們不得不提及之前一直所忽略的一個(gè)問題:我們之前凡是涉及循環(huán)等待事件輪詢的程序總是占用100%的CPU,這并不是因?yàn)槲覀冋嬲玫搅?00%的CPU性能,而是我們讓CPU陷入了“空等”(Busy Waiting)的尷尬境地。輪詢事件得到響應(yīng)相對(duì)于循環(huán)等待來(lái)說,是發(fā)生得非常緩慢的事情,我們?cè)谘h(huán)中,哪怕是讓電腦休息0.01秒,事情都會(huì)發(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)我們重新運(yùn)行新程序的時(shí)候,我們可以看到程序?qū)PU的占用從100%驟降到了0%!這當(dāng)然并不意味著程序就用不上CPU了,而是說,這些運(yùn)算對(duì)于我們的CPU來(lái)說,實(shí)在是小菜一碟了,或者從數(shù)據(jù)上說,處理這些運(yùn)算的時(shí)間與0.01秒來(lái)比較,都幾乎可以忽略不計(jì)!2.3:GUI線程與worker線程我們的另外一項(xiàng)試驗(yàn)是將事件輪詢放到動(dòng)畫線程中,程序就不多寫了,大家可以自己試下。我直接說結(jié)論:動(dòng)畫線程中無(wú)法響應(yīng)事件輪詢。一般提倡的模式,是將GUI事件都寫在主線程中,而將純粹的運(yùn)算才寫到由主線程創(chuàng)建的線程中,后者也就是所謂的worker線程。從另外一個(gè)概念看,只有主線程控制著“當(dāng)前窗口”,其它線程也許在后臺(tái),也許雖然也是在前臺(tái)但是并非是我們可見的,所以,輪詢事件找不到接口。對(duì)于拋出的線程與主線程之間的通訊,我們可以通過他們共享的數(shù)據(jù)來(lái)進(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)用一個(gè)對(duì)象數(shù)據(jù)的形式,實(shí)現(xiàn)對(duì)于創(chuàng)建多線程函數(shù)的封裝。另外,我們希望測(cè)試在主線程中讀寫線程數(shù)據(jù)的效果,所以添加了兩個(gè)方法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請(qǐng)參考:/lf426/archive/2008/04/14/47038.html實(shí)現(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;最后,我們修改了主演示程序,并測(cè)試了show()和reset()的效果。我們可以看到,直接修改線程數(shù)據(jù)的reset()的結(jié)果也是不可預(yù)知的,所以,我們似乎更應(yīng)該通過改變線程“流”的效果,而不是直接對(duì)數(shù)據(jù)進(jìn)行修改。這個(gè)我們以后再討論了。#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. 本站所有資源如無(wú)特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度企業(yè)知識(shí)產(chǎn)權(quán)質(zhì)押貸款合同-@-2
- 課題申報(bào)參考:能源轉(zhuǎn)型下居民親環(huán)境行為的變遷趨勢(shì)及提升路徑研究
- 課題申報(bào)參考:面向韌性發(fā)展的城市群醫(yī)療資源供需適配研究
- 2025年個(gè)人無(wú)息借款合同樣本:無(wú)息借款協(xié)議:扶持文化藝術(shù)項(xiàng)目2篇
- 二零二五版民政局批準(zhǔn)離婚協(xié)議書范本8篇
- 2025年度綠色能源項(xiàng)目?jī)?nèi)部股東權(quán)益轉(zhuǎn)讓合同4篇
- 二零二五年度南京市房產(chǎn)局制定的房屋抵押權(quán)登記合同模板4篇
- 2025年度戀愛期間共同理財(cái)規(guī)劃與投資合同4篇
- 2025年度個(gè)人信用借款擔(dān)保合同范本3篇
- 2025版車輛抵押借款合同(含貸款利率調(diào)整)4篇
- 護(hù)理飲食指導(dǎo)整改措施及方案
- 項(xiàng)目工地春節(jié)放假安排及安全措施
- 印染廠安全培訓(xùn)課件
- 紅色主題研學(xué)課程設(shè)計(jì)
- 胸外科手術(shù)圍手術(shù)期處理
- 裝置自動(dòng)控制的先進(jìn)性說明
- 《企業(yè)管理課件:團(tuán)隊(duì)管理知識(shí)點(diǎn)詳解PPT》
- 移動(dòng)商務(wù)內(nèi)容運(yùn)營(yíng)(吳洪貴)任務(wù)二 軟文的寫作
- 英語(yǔ)詞匯教學(xué)中落實(shí)英語(yǔ)學(xué)科核心素養(yǎng)
- 《插畫設(shè)計(jì)》課程標(biāo)準(zhǔn)
- 高中英語(yǔ)名詞性從句講解
評(píng)論
0/150
提交評(píng)論