摘要: 工程項(xiàng)目中不是講究新鮮的語(yǔ)言技巧、語(yǔ)法規(guī)范。不要華麗的新技術(shù)。要的就是正常而穩(wěn)定,穩(wěn)定壓倒一切。 閱讀全文
我想在博客里記錄一些學(xué)習(xí)DirectX的筆記。這是第一篇。
一直以來(lái)對(duì)于DirectX的一套沒(méi)有花時(shí)間去學(xué)習(xí),3D圖形api也是學(xué)習(xí)了OpenGL,相當(dāng)長(zhǎng)的一段時(shí)間里,總是認(rèn)為自己不會(huì)去接觸這些。到公司寫了快一年的游戲邏輯了,才明白邏輯固然很重要,但是寫邏輯寫一年和寫兩年的區(qū)別不大。做游戲,做網(wǎng)游不就那幾個(gè)大塊么,圖形,網(wǎng)絡(luò),數(shù)據(jù)庫(kù),io并發(fā)。寫邏輯是要寫的,但終究需要在某一領(lǐng)域有所專長(zhǎng),才是正道。
言歸正傳吧。
DirectInput是一個(gè)不依賴硬件的虛擬輸入系統(tǒng),是建立于硬件抽象層(HAL)之上的接口。
微軟的DirectX一套均采用COM開(kāi)發(fā),所以無(wú)論DDraw還是DirectInput的構(gòu)建、設(shè)置、使用,代碼都相差無(wú)多。基本步驟都是建立xxx接口對(duì)象,建立xxx設(shè)備,設(shè)置xxx相關(guān)屬性(參數(shù)),使用之。
我們要在應(yīng)用程序中使用DirectInput,分以下三步走。
1)初始化
2)獲取設(shè)備狀態(tài)
3)根據(jù)設(shè)備狀態(tài),進(jìn)行你的自定義處理。
我這里給出一個(gè)簡(jiǎn)單的例子。該例子就是在標(biāo)準(zhǔn)的windows應(yīng)用程序中使用DirectInput所需的步驟。
首先需要包含必要的宏定義和頭文件
1 #define INITGUID
2 #include <objbase.h>
3 #include <dinput.h>
相關(guān)的全部變量:
LPDIRECTINPUT g_dinput = NULL;
LPDIRECTINPUTDEVICE g_Keyboard = NULL;
建立初始化函數(shù):
1 BOOL InitDirectInput(HINSTANCE hInstance)
2 {
3 // 創(chuàng)建DirectInput對(duì)象
4 if (DI_OK != DirectInputCreate(hInst, DIRECTINPUT_VERSION, &g_dinput, NULL))
5 return FALSE;
6
7 // 創(chuàng)建鍵盤設(shè)備
8 if (DI_OK != g_dinput->CreateDevice(GUID_SysKeyboard, &g_Keyboard, NULL))
9 return FALSE;
10
11 // 設(shè)置協(xié)作等級(jí)
12 if (DI_OK != g_Keyboard->SetCooperativeLevel(g_hWnd, DISCL_NONEXCLUSIVE|DISCL_BACKGROUND))
13 return FALSE;
14
15 // 設(shè)置數(shù)據(jù)格式
16 if (DI_OK != g_Keyboard->SetDataFormat(&c_dfDIKeyboard))
17 return FALSE;
18
19 // 獲取設(shè)備
20 if (DI_OK != g_Keyboard->Acquire())
21 return FALSE;
22
23 return TRUE;
24 }
在哪里使用呢?我們?cè)趙indows消息循環(huán)里面,處理完消息之后:
1 unsigned char keyboard_state[256];
2 // Main message loop:
3 while (GetMessage(&msg, NULL, 0, 0))
4 {
5 if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
6 {
7 TranslateMessage(&msg);
8 DispatchMessage(&msg);
9 }
10
11 g_Keyboard->GetDeviceState(256, (LPVOID)keyboard_state);
12 if (keyboard_state[DIK_UP])
13 {
14 ::MessageBox(NULL, "up", "msg", MB_OK);
15 }
16 }
基本就是這些了。
我這里主要是作為學(xué)習(xí)筆記留在blog上,說(shuō)的不清楚或者不專業(yè)或者其他原因讓你沒(méi)有看明白的,請(qǐng)看
《windows游戲編程大師技巧》一書(shū)。
在工作中遇到不少情況使用singleton模式,下面采用的是最簡(jiǎn)單的一種形式:
1 class Foo
2 {
3 public:
4 static Foo& getSingleton()
5 {
6 static Foo foo;
7 return foo;
8 }
9
10 private:
11 Foo();
12 };
這種實(shí)現(xiàn),在單線程情況下,簡(jiǎn)單而有效。
對(duì)于線程安全的singleton的實(shí)現(xiàn),網(wǎng)上有不少討論。這兩天看到boost庫(kù)中的一種實(shí)現(xiàn),沒(méi)有使用鎖機(jī)制,而是充分利用了C++的語(yǔ)言特性較好的解決了多線程情況下使用singleton的問(wèn)題。
boost的singleton的實(shí)現(xiàn)基于以下假設(shè):良好的設(shè)計(jì)在進(jìn)入main函數(shù)之前應(yīng)該是單線程的。
我們可以使用全局變量的方式來(lái)設(shè)計(jì)singleton,并且保證在使用該singleton之前其已經(jīng)被正確的初始化,如何做到?且看代碼:
1 template <typename T>
2 struct Singleton
3 {
4 struct object_creator
5 {
6 object_creator(){ Singleton<T>::instance(); }
7 inline void do_nothing()const {}
8 };
9
10 static object_creator create_object;
11
12 public:
13 typedef T object_type;
14 static object_type& instance()
15 {
16 static object_type obj;
17 create_object.do_nothing();
18 return obj;
19 }
20
21 };
漂亮而巧妙的實(shí)現(xiàn)。
但是上面的實(shí)現(xiàn)還是有一點(diǎn)小的缺憾,那就是只能調(diào)用類的默認(rèn)構(gòu)造函數(shù),不能調(diào)用帶參數(shù)的構(gòu)造函數(shù)。
附:
非常抱歉,上面這個(gè)代碼是有點(diǎn)問(wèn)題的。感謝各位童鞋及時(shí)回復(fù)并指出問(wèn)題所在。現(xiàn)在補(bǔ)上缺失的初始化部分。
1 template <typename T>
2 typename Singleton<T>::object_creator
3 Singleton<T>::create_object;
摘要: C++中placement new的標(biāo)準(zhǔn)使用方法及用途
閱讀全文
17號(hào)就從家做飛機(jī)返京,過(guò)春節(jié)就在家呆了一個(gè)禮拜,又要匆忙的回來(lái)工作了。
18號(hào)中午送走女友,一個(gè)人回到房里,上網(wǎng)一直到晚上,吃飯回來(lái)也是繼續(xù)上網(wǎng)。想今年搞點(diǎn)小成本的投資,google了半天,論壇也看了半天,未果。
晚上一個(gè)人出來(lái)吃飯,走在小區(qū)里和街上,聽(tīng)到振聾發(fā)聵的煙花爆竹的聲音,有點(diǎn)反感大城市里這種的煙花爆竹的聲音,經(jīng)過(guò)層層高層小區(qū)建筑的回音繼而擴(kuò)大,那聲音失去了原本的清亮與干脆。
新的一年,又要工作一年了。告訴自己好好干吧。
1. 做好現(xiàn)在的本職工作,并希望有一些突破。
2. 自己業(yè)余時(shí)間想做的一款游戲,也希望在今年年底之前給完成了。
3. 希望在網(wǎng)絡(luò)編程方面和微機(jī)系統(tǒng)方面的認(rèn)識(shí)與理解有所提高。
4. 學(xué)點(diǎn)中醫(yī)。
最近在寫一個(gè)小工具時(shí),需要用C++解析XML文件。使用了TinyXML這個(gè)精巧的C++庫(kù),使用起來(lái)確實(shí)比較方便,下面給出如何遍歷一個(gè)xml文件的方法,很好用哦,根據(jù)自己的需要可以修改該函數(shù),雖然簡(jiǎn)單,但是實(shí)用。
1 void
2 parseElement( TiXmlNode* pElem )
3 {
4 if ( NULL == pElem )
5 {
6 return;
7 }
8
9 TiXmlNode* pElement = pElem->FirstChild();
10
11 for ( ; pElement; pElement = pElement->NextSibling() )
12 {
13 int nType = pElement->Type();
14
15 switch ( nType )
16 {
17 case TiXmlNode::ELEMENT:
18 parseElement( pElement );
19 if ( 0 == stricmp( pElement->Value(), “Property” ) )
20 {
21 std::string strValue = pElement->ToElement()->Attribute( “Value” );
22 size_t pos = strValue.find( “set” );
23 if ( string::npos != pos )
24 {
25 std::cout << strValue << std::endl;
26 }
27 }
28 break;
29 case TiXmlNode::TEXT:
30 std::cout << pElement << std::endl;
31 break;
32 default:
33 break;
34 }
35 }
36 }
37
摘要: 說(shuō)說(shuō)09年的游戲界的兩匹黑馬,一個(gè)是《植物大戰(zhàn)僵尸》,一個(gè)是《偷菜》。
游戲太多了,現(xiàn)在僅網(wǎng)游成功的就有上百款。單機(jī)更是不勝其數(shù)。我一直在考慮,我們到底需要什么樣的游戲。
作為一個(gè)程序員,很自然的會(huì)從技術(shù)角度去先評(píng)估一下這些游戲,對(duì)比成功的與失敗的有什么不同。我思考良久,得到的結(jié)論是:技術(shù)非常重要,技術(shù)又很次要。 閱讀全文
為什么會(huì)出現(xiàn)select模型?
先看一下下面的這句代碼:
int iResult = recv(s, buffer,1024);
這是用來(lái)接收數(shù)據(jù)的,在默認(rèn)的阻塞模式下的套接字里,recv會(huì)阻塞在那里,直到套接字連接上有數(shù)據(jù)可讀,把數(shù)據(jù)讀到buffer里后recv函數(shù)才會(huì)返
回,不然就會(huì)一直阻塞在那里。在單線程的程序里出現(xiàn)這種情況會(huì)導(dǎo)致主線程(單線程程序里只有一個(gè)默認(rèn)的主線程)被阻塞,這樣整個(gè)程序被鎖死在這里,如果永
遠(yuǎn)沒(méi)數(shù)據(jù)發(fā)送過(guò)來(lái),那么程序就會(huì)被永遠(yuǎn)鎖死。這個(gè)問(wèn)題可以用多線程解決,但是在有多個(gè)套接字連接的情況下,這不是一個(gè)好的選擇,擴(kuò)展性很差。
再看代碼:
int iResult = ioctlsocket(s, FIOBIO, (unsigned long *)&ul);
iResult = recv(s, buffer,1024);
這一次recv的調(diào)用不管套接字連接上有沒(méi)有數(shù)據(jù)可以接收都會(huì)馬上返回。原因就在于我們用ioctlsocket把套接字設(shè)置為非阻塞模式了。不過(guò)
你跟蹤
一下就會(huì)發(fā)現(xiàn),在沒(méi)有數(shù)據(jù)的情況下,recv確實(shí)是馬上返回了,但是也返回了一個(gè)錯(cuò)誤:WSAEWOULDBLOCK,意思就是請(qǐng)求的操作沒(méi)有成功完成。
看到這里很多人可能會(huì)說(shuō),那么就重復(fù)調(diào)用recv并檢查返回值,直到成功為止,但是這樣做效率很成問(wèn)題,開(kāi)銷太大。
select模型的出現(xiàn)就是為了解決上述問(wèn)題。
select模型的關(guān)鍵是使用一種有序的方式,對(duì)多個(gè)套接字進(jìn)行統(tǒng)一管理與調(diào)度。
看核心代碼:(這里只給出服務(wù)端的)
while ( 1 )
{
// 初始化fdset
FD_ZERO( &fdsRead );
// 將server套接字添加到可讀集合中
FD_SET( sockServer, &fdsRead );
// 調(diào)用select
select( 0, &fdsRead, NULL, NULL, &tv );
// 判斷server套接字的狀態(tài),如果套接字還在可讀集合中,
// 說(shuō)明有數(shù)據(jù)可以讀入,則建立套接字可以成功
if ( FD_ISSET( sockServer, &fdsRead ) )
{
sockAccept = accept( sockServer, (sockaddr*)&addr, &nLen );
// 有數(shù)據(jù)可讀,進(jìn)行相關(guān)處理
}
當(dāng)然了,這里演示的只是最基礎(chǔ)的select的用法。網(wǎng)絡(luò)通信中的I/O復(fù)用的相關(guān)問(wèn)題還很多,還需要慢慢學(xué)習(xí)與深入。
下面這篇文章摘自鏈接:http://coolshell.cn/?p=1145
我認(rèn)為這篇文章寫得非常好!值得收藏。
對(duì)于程序開(kāi)發(fā)者來(lái)說(shuō),有兩種技術(shù)需要我們掌握,一個(gè)是技術(shù)上的能力,另一個(gè)是非技術(shù)上的能力。不幸的是,許多程序員過(guò)多地關(guān)注了技術(shù)上的能力,而忽
略了非技術(shù)上的能力的培養(yǎng),因此,我們的程序員們經(jīng)常會(huì)有一些很不好的習(xí)慣,這里我們例舉了程序員們最常犯的5個(gè)非技術(shù)的錯(cuò)誤,與大家共勉。
1.- 缺乏團(tuán)隊(duì)紀(jì)律
“Discipline is the bridge between goals and accomplishment.” Jim Rohn.
紀(jì)律是一個(gè)最有價(jià)值的技能,不僅僅只是在軟件開(kāi)發(fā)領(lǐng)域,同樣在其它領(lǐng)域也是一樣的。但對(duì)于現(xiàn)實(shí)來(lái)說(shuō),我們很難找到即有才華又有紀(jì)律的人。這正如足球
隊(duì)一樣,非洲的球員們才華相當(dāng)?shù)某霰姡上麄兛偸仟?dú)自為陣,團(tuán)隊(duì)紀(jì)律性不足,所以可以有好的成績(jī),但卻無(wú)法贏得最后的勝利;而德國(guó)隊(duì)的隊(duì)員個(gè)人技能平
平,但其有很強(qiáng)大的團(tuán)隊(duì)紀(jì)律性,所以,總是能打入最后的決賽并獲得冠軍。有人說(shuō)過(guò),個(gè)人英雄并不可怕,而有強(qiáng)大紀(jì)律性的團(tuán)隊(duì)才讓人可怕。這正是日本這個(gè)民
族的可怕之處。況且,軟件開(kāi)發(fā)從來(lái)都不是一個(gè)人可以完成的事情,所以團(tuán)隊(duì)工作中的紀(jì)律性會(huì)是非常重要的。
Steve Pavlina 強(qiáng)調(diào)了自律中5個(gè)因素:“承擔(dān), 毅力, 努力, 勤奮, 和堅(jiān)持。” 這里,我們強(qiáng)烈推薦你讀一讀Steve的 關(guān)于自律的文章。
下面是我們覺(jué)得程序應(yīng)該有的比較良好的習(xí)慣。
- 每天都有自己的to do list
- 在一個(gè)時(shí)間內(nèi)只做一個(gè)事
- 把事情做對(duì)了
- 事情沒(méi)有完全完成時(shí)不要輕易結(jié)束
- 慢點(diǎn)總比道歉好,道歉總比不做好
2.- 過(guò)度自負(fù)
我們的經(jīng)驗(yàn)告訴我們,過(guò)度的自負(fù)的人一般是意識(shí)不到自己的自負(fù),下面是一些過(guò)度自負(fù)的特征,希望你可以從中檢測(cè)一下自己是否過(guò)度自負(fù)了。
- 覺(jué)得自己是最牛的程序員
- 總是打斷談話
- 你要求Code Reivew不是要檢查代碼,而是向大家炫耀你的代碼
在網(wǎng)上有太多的文章關(guān)于程序員的自負(fù)的問(wèn)題,這里有兩篇,你可以看看:一篇是Mike Bernat的 Egoless programming(無(wú)自負(fù)編程) 還有一個(gè)是stackoverflow.com 上的一個(gè)貼子。
3.- 溝通不暢
“如果我要說(shuō)十分鐘,我需要一周做準(zhǔn)備;如果說(shuō)15分鐘,我需要3天做準(zhǔn)備;半個(gè)小時(shí),我需要兩天;如果說(shuō)一個(gè)小時(shí),我現(xiàn)在就準(zhǔn)備好了。” Woodrow Wilson
人類的溝通是我們最主要的活動(dòng)。成為一個(gè)好的溝通者是一件很難的事情,我們不斷地和別人交換關(guān)于設(shè)計(jì),編碼,文章的意見(jiàn),并且我們每天都在試圖說(shuō)服別人我們自己的設(shè)計(jì)和想法會(huì)更好,更有道理……
然后,好的溝通者是那些當(dāng)他們正在解釋一些事情的時(shí)候,他們的解釋是下面這個(gè)樣子的:
- 專注。不跑題,沒(méi)有廢話。
- 清晰. 很容易聽(tīng)懂。
- 簡(jiǎn)明. 加一點(diǎn)就覺(jué)得多,少一點(diǎn)都覺(jué)得不夠。
要有一個(gè)好的溝通技巧,我們的建議如下:
- 如果你覺(jué)得你溝通方面不夠好的話,請(qǐng)事先準(zhǔn)備你要表達(dá)的東西,努力做到專注,清晰和簡(jiǎn)明。
- 在交談中,先聽(tīng),后想,最后再說(shuō)。
- 永遠(yuǎn)從對(duì)方的角度思考問(wèn)題。
4.- 忘了用戶
“如果我們不關(guān)心我們的用戶……那么別人會(huì)”
你的存在,你工作的意思只有一個(gè)原因——你的用戶。我們?cè)诤芏鄷r(shí)間都會(huì)忘了這個(gè)事情。經(jīng)常,我們?cè)诠ぷ鳟?dāng)中,技術(shù)會(huì)取代用戶而占據(jù)了主要的位置,我
們可以花費(fèi)數(shù)月的時(shí)間來(lái)創(chuàng)建一個(gè)程序框架,但一個(gè)程序框架不會(huì)給用戶代來(lái)任何的價(jià)值,我們不是說(shuō)程序框架不重要,而是說(shuō),對(duì)于用戶的需求來(lái)說(shuō),這是其次重
要的東西。如果離開(kāi)了用戶的需求,我們所有的技術(shù),算法或是精妙的設(shè)計(jì)將會(huì)變得什么也不是。
5.- 不懂工作的輕重緩急
程序員總是喜歡去研究一些新的或自己感興趣的東西,但對(duì)于軟件工程來(lái)說(shuō),我們更需要知道所有事情的輕重緩急,要學(xué)會(huì)如何了解事情的優(yōu)先級(jí),這樣才會(huì)
讓我們的工作事半功倍,而我們的工作也會(huì)更有效。比如,當(dāng)用戶的站點(diǎn)出現(xiàn)問(wèn)題的時(shí)候,有些時(shí)候,我們的程序員過(guò)試地關(guān)注于問(wèn)題的重現(xiàn)和原因,而忘記了用戶
的站點(diǎn)正在流血,無(wú)法進(jìn)行生產(chǎn)。所以,一般來(lái)說(shuō),最重要的事情首先是恢復(fù)用戶站點(diǎn),然后才是去重現(xiàn)和調(diào)查問(wèn)題。在我們的日常工作中,我們要處理很多事情,
只有了解到了所有事情的輕重緩急,處理最重要最緊急的事情,我們才能夠更好的安排自己的工作,才能夠更好的完成我們的事情。不要以為這是一件很簡(jiǎn)單的事
情,這需要我們不斷地和別人溝通來(lái)了解事情的輕重緩急,事實(shí)證明,如果我們不懂工作中的輕重緩急,本來(lái)只有一件緊急的事情,如果處理不當(dāng),最后可能會(huì)演變
成多件緊急事情,其它本來(lái)不緊急的事,后來(lái)也會(huì)變得很緊急,最終程序員們顧此失彼,苦不堪言。希望大家切記。
植物大戰(zhàn)僵尸是09年非常風(fēng)靡的一款游戲。雖然是2D畫(huà)面,但是其游戲性、畫(huà)面的輕松可愛(ài)、恰到好處的音效使人愛(ài)不釋手。
最近想做一款類似的游戲,想先暫用其圖像資源與音樂(lè)資源來(lái),而專注于游戲程序編寫本身。發(fā)現(xiàn)其所有的資源都打包在main.pak包中。經(jīng)過(guò)一番努力,終于從中提取到所有的png圖像1800多張,ogg格式音樂(lè)文件300余首。現(xiàn)在將整個(gè)過(guò)程簡(jiǎn)要說(shuō)明。
1)該main.pak經(jīng)過(guò)了加密。其實(shí)只是通過(guò)0XF7進(jìn)行了一個(gè)簡(jiǎn)單的xor運(yùn)算。通過(guò)對(duì)源文件進(jìn)行xor運(yùn)算可以得到未加密的資源文件。我們這里叫做mainbak.pak。
2)寫一個(gè)程序?qū)ainbak.pak讀取,然后在文件(二進(jìn)制)中查找png和ogg文件格式的特征碼(魔數(shù))。循環(huán)讀取,就可以獲取所有的資源了。
附:
png文件格式開(kāi)頭:0x89 0x50 0x4E 0x47
png文件格式結(jié)尾:0x49 0x45 0x4E 0x44 后面還有四位CRC,不過(guò)選取這四位標(biāo)示結(jié)尾就可以了。算文件長(zhǎng)度的時(shí)候記得加上四位CRC就可以了。
ogg魔數(shù):0x4F 0x67 0x67 0x53 0x00 0x02 0x00 0x00 0x00 0x00
enjoy it !