[OpenGL] 遊戲開發的簡單demo - myWarcraft

完成時間:2016年08月23日(大三上)

博客時間:2017年04月19日

程序截圖:

 

 

 

簡介:

       這個程序是我大二爲《軟件工程》課程的作業而編寫的,採用C++/OpenGL開發。因爲只是一個作業,實現的比較簡單,但是還是運用了一些設計思想,比較有參考價值吧。現在過了將近半年纔回來填這個坑,主要也是因爲涉及到的內容太多了(其實是我太懶 (。・`ω´・)

       這篇博客可能更多地側重於遊戲的設計思想,如果想要交流歡迎評論或者私信哦

 

遊戲開發的幾點重要策略:

1.   高效的遊戲循環(Game Loop)

     方法一:一個最簡單粗暴但相當劣質的處理方式是:用一種能跑多快跑多快的方式進行遊戲循環。簡單的用代碼表示一下:

 

int main()   
{
	while(true)    // 一種不好的方式
	{
		processInput();  // CPU處理輸入
		update();        // CPU修改狀態
		
		render();       // GPU渲染畫面
	}
}

       不難發現,在快的機器上,遊戲循環可能快得令玩家看不清遊戲在做什麼;在慢的機器上,遊戲則會變得又慢又卡。

 

       方法二:我們稍加一下改進:你想讓時間以60fps的速度運行,也就是間隔MS_PER_UPDATE=16毫秒進行一個遊戲循環,那麼則可以以一個穩定的幀率來跑遊戲。What you should do is to wait for next frame.簡單的用代碼表示一下:

 

int main()
{
	while(true)  // 維持相對穩定的幀率的方法
	{
		double start = getCurrentTime();

		processInput();
		update();
		render();

	 	// 等待一段時間,湊夠16ms
		sleep( MS_PER_UPDATE - (getCurrentTime() - start));
	}
}

 

       這種方法,通過引入的一個sleep()方法幫助我們維持了一個相對穩定的fps。但是,我們也能發現一個問題:若每次實際用於更新的時間長於固定的間隔時間MS_PER_UPDATE,那麼遊戲同樣會變慢。例如,當需要16ms以上的時間去更新fps=16ms的遊戲時,就會無法維持運行速度。

      
       方法三: 讓我們試一下稍微複雜點的方法。爲了解決方法二中出現的問題,我們以這一幀與上一幀的實際時間間隔來作爲更新步長。幀處理花費的實際時間越長,這個步長也就越長。這個方法捨棄了固定的MS_PER_UPDATE,而是採用實際間隔時間elapsed來作爲更新依據。這個方法使得遊戲總會越來越接近於實際的時間。因此也被稱爲變值時間步長。

 

int main()
{
	double lastTime = getCurrentTime();

	while(true)  // 維持相對穩定的幀率的方法
	{
		double current = getCurrentTime();
		double elapsed = current - lastTime;

		processInput();
		update(elapsed);
		render();

		lastTime = current;
	}
}

     這種遊戲循環雖然有了很大的提高,但是也有潛在的問題(可以參考給出的參考資料)。

 

     方法四:最後的改進,通過引入一個新的變量lag來表示遊戲時鐘相對於現實時間落後的差量。接着用一個內部循環更新遊戲,每次以固定時長MS_PER_UPDATE進行,直到追上現實時間(此處的MS_PER_UPDATE不是視覺上的幀速,而是更新遊戲update()的間隔)

 

int main()   // 一個比較好的方案:可以追回因爲render()落後的時間
{
	double lastTime = getCurrentTime();
	double lag = 0.0;

	while(true)
	{
		double current = getCurrentTime();
		double elapsed = current - lastTime;
		lastTime = current;
		lag += elapsed;

		processInput();

		// 內部循環:以固定時長更新遊戲以趕上落後的時間。
		while(lag >= MS_PER_UPDATE)
		{
			double startUpdate = getCurrentTime();
			
			update();
			lag -= MS_PER_UPDATE;

			sleep(MS_PER_UPDATE - (getCurrentTime()-startUpdate));
		}

		render();
	}
}

 


2. 場景管理Scene Management

        3D遊戲中場景管理的方法有很多:四叉樹、八叉樹、BSP樹、KD樹等。方法各有優劣,適用的情形各不相同。但是原理較爲複雜,這裏也不過多描述,需要的可以自己去google。

 

        例如:使用八叉樹/kd樹,可以以很高的效率進行空間查詢:

                 (1) 鄰近查詢(proximity query):如查詢玩家周圍的npc、掉落物品等。

                 (2) 可見性判斷(view frustum culling):剔除不可見的物體

                 (3) 粗略的碰撞檢測:找到潛在的可能碰撞的對象。

 

       下圖便是採用k-d樹的空間劃分結構,爲每個單位劃分一個區域。

3. 人工智能單位 AI

        其實,對於AI單位的管理,應當歸於Scene Management。但是AI單位有自己的特殊之處,受到攻擊時會追擊、拉開距離後停止追趕。

這裏的話,需要進行碰撞、攻擊判定等。可能會用到的技術有:AABB包圍盒等。

 

4. 大規模地形渲染

         這是一個比較複雜的東西,但是如果使用下面提到的技術會大大提高你的渲染效率。我們在render large terrains時,經常採用的便是LOD(level of detail)的技術,根據距離確定細節層次。

         詳情可以看一下我翻譯的另一片博客:How to rendering large terrains

 

5. 參考資料:

    1.  [Book] Game Programming Patterns - Robert Nystrom

    2.  [LINK] http://gameprogrammingpatterns.com/game-loop.html

    3.  [LINK]http://www.koonsolo.com/news/dewitters-gameloop/

 

6. 寫在後面

      希望我的文章,能夠爲有志於開發遊戲的同志有所幫助。我也還只是一個普通的本科生,歡迎不幸點開這篇文章的諸位大神批評指正!!!

      這是一個比較簡單的demo,歡迎評論或者私信討論。另外我之前做的一個遊戲仿製《minecraft》的資料還有演示程序可以在我的其他博客中翻到~ (ง •̀_•́)ง。   

       我使用OpenGL仿製的一款《Minecraft》:仿製《Minecraft》

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章