通過前面的課程,你已經對遊戲編程有了一個整體上的認識,就算不知道細節,但也足夠你出去「侃大山」了。從這一節內容開始,我們將要深入3D遊戲編程的細節。如果遊戲編程是一個複雜的機器,前面的課程已經幫你窺得全貌了,現在的你,只是機器中的原理和細節不太明白。
從現在開始,我們就開始講解這個機器中的原理和細節,內容比較多,也比較難理解,希望你多花點時間去「悟」。
我們是用Direct3D來處理示例程序中的3D世界的部分的,所以,我們必須在程序代碼中使用Direct3D。
由於DirectX是COM組件,它和函數庫中的函數不一樣,並不能直接使用,必須先初始化了才可以用。
我們在使用函數庫的時候,只需要直接調用函數就可以了,並沒有一個初始化的過程。比方說Windows框架代碼中,我們是直接使用CreateWindow來創建窗口的,並沒有初始化的過程。那麼,COM組件為什麼那麼特殊?非要初始化呢?
因為,COM組件是組件,它不是原始的代碼。
「學」的部分
繼續之前,請你再次熟悉Windows框架的內容,接下來的所有代碼,都是在這個框架的基礎上添加的。
一、遊戲代碼的運行過程
通過前面一些章節的講述,我想,你應該已經充分懂得了虛擬3D世界的大致內容,但是,那都是理論性的東西,主要是為了幫助你理解實踐中的代碼的。現在,我們要開始在框架的基礎上編寫遊戲代碼了。首先,我們要明白一個小問題:遊戲代碼是如何運行的呢?
我們已經知道,3D遊戲的過程是先創建一個虛擬的3D環境,然後把一切的東西添加進去後,再通過虛擬攝像機把虛擬場景轉化為2D圖像並顯示出來。這個過程在前面已經強調多次了,那麼,如何在代碼中體現這個過程呢?
為了加深你的理解,我把思考的過程寫出來。
通過練習Windows框架的編寫,你應該要總結出如下的一些編程基礎內容:
①程序是一行一行執行代碼的;
②當程序執行到最後一行代碼的時候,程序會結束;
③Windows框架代碼中,我們通過消息循環的方式來延緩程序結束的時間,讓窗口可以長時間的存在,用戶需要通過關閉按鈕才能結束消息循環,才能結束程序。
我們再延伸一下,如果我們把顯示出來的窗口當成一個「遊戲」的話,那麼,在消息循環之前的所有代碼都是為了這個「遊戲」做的準備工作,而消息循環的目的是為了「遊戲」可以長時間的存在。
也就是說,我們把虛擬攝像機拍攝的2D圖片放在消息循環中,那麼,虛擬的3D世界就能長時間存在於窗口中了。
遊戲的運行過程就是模仿這個消息循環的工作機制,整體來說是分成了2個步驟:
(1)在消息循環之前,把虛擬3D環境所要用到的所有內容都準備好,這樣,我們在消息循環中玩遊戲的時候,就不會因為有什麼東西沒有加載好而感覺到卡了;這個過程有一個專業術語——遊戲的初始化;
(2)遊戲初始化完畢之後,我們就可以在消息循環中把2D圖片顯示在窗口中了,由於是一個循環,這也有一個專業術語——遊戲循環;遊戲循環的目的,是把當前時間的3D世界轉化成2D圖像;由於消息循環會一直運行,2D圖像就會一直更新並顯示,我們在窗口中就能像看電影那樣看到遊戲畫面了。
我們繼續延伸一下。
每一個遊戲循環中,要處理的事情很多,計算機不可能立馬就計算完畢,程序執行完畢一個遊戲循環,需要消耗一定的時間t。而t是當前計算機計算出一個遊戲2D畫面所需要的時間,這個遊戲2D畫面也有專業術語——幀。
一般來說,t的單位是毫秒,我們用1000除以t,就得到了當前計算機運行這個遊戲程序的幀數。遊戲想要運行起來,最低的幀數是15,但是15幀的遊戲會有點卡。遊戲想要不卡,幀數要在30以上。
在很久以前,普遍的家用計算機性能都不怎麼樣,遊戲程式設計師都會想辦法把幀數控制在30,這樣,遊戲就不會卡了。而現在,由於計算機的性能飆升,所以,遊戲程式設計師再也不用管幀數的問題了,一般來說都不會限制幀數,只要你的計算機性能好,一個大型3A遊戲也能達到1000幀的水平。
扯遠了。
總結一下,遊戲代碼運行的重點是:
①在消息循環之前,把所有需要的內容都初始化好;
②在消息循環中,再把場景轉化成2D圖像(幀)並顯示出來。
二、初始化Direct3D的過程
我們已經知道,要在消息循環之前把遊戲的內容初始化好,那麼,究竟應該在什麼位置放置初始化的代碼呢?
答案可能出乎很多新手的預料:可以在任何地方進行遊戲的初始化,只要別在消息循環當中或者之後就行。