主程式(the application host)
為了添加我們自己的程式控制層,我們將以Direct3d sample framewrok提供類為基礎來簡曆我們自己的類。架構類CD3Dapplication將作為我們的基類,我們使用它來初始化和枚舉視頻裝置,建立顯示模式和處理基本視窗訊息。在這個類之上,我們將建立我們自己的資源和裝置管理類,控制我們程式的執行和渲染我們的世界。我們通過見了我們的主程式類cGameHost來做到以上幾點。
CgameHost類有許多目的。 最重要的是,它是我們整個引擎的核心。我們在設計類的時候採用可管理的方式,建立特殊的單一實例(single-instance)類來管理我們引擎的關鍵方面。例如管理類將處理這些事情:渲染管線,使用者輸入等。這些自包含的管理類需要一個線程,一個程式訪問他們及與他們互動的方法。cGameHost就作為一個所有管理類的容器並且提供重新得到介面存取方法。
建立這個類我們使用singleton聲明方式來確保只建立唯一一個cGameHost類執行個體,並且程式有全域方法來訪問這個介面。關於singleton方式的類在附錄A中有詳盡的細節“Gaia Utility Classes”。對於程式可擴充性的考慮,使用singleton的類同樣允許類繼承。如果需要自訂的主程式功能,那麼可以蟲cGameHost派生一個特別的遊戲主程式對象來執行附加的動作。使用singleton聲明方式的最大好處就是可以在程式的任何地方,包括在管理類自身,cGameHost對象都提供對引擎中使用的的管理對象的存取方法。
除了在管理類之間提供一個互動的匯流排介面,cGameHost類也作為整個程式的核心類。這個類作為整個程式的殼(shell),包含了所有與主機作業系統的互動。在我們的例子中,這就以為這cGameHost對象接管了包含程式的桌面視窗,所有發送到視窗的程式都由它來處理。我們可以通過從由Direct3D simple framework中提供的CD3Dapplication類派生我們自己的類來的到這個便利。然而,從該類中派生自己的類有利於我們控製程序的某些特定的方面。
作為開始,我們將以一種與DirectX範例稍不同的方式更新我們的的遊戲世界。DirectX範例在更新他們的世界狀態和渲染每一幀之間維護一個一對一的關係(one-to-one relationship)。在每個過程中,跟新整個程式狀態同時渲染一個新的幀。這些更新過程在沒有任何類型的管理的情況下發生,所以即時值必須用來決定在每次更新中有多少個物體要移動或者是動畫。
我們採用一種更加以符合遊戲的方式來控制時間,把時間分成很小的步子,我們稱之為”滴答數”(ticks),每個tick代表一個固定的時間間隔。因此,我們每次執行一個tick,我們就知道經過的確切時間。這個採用固定時間步長的方法可以使我們不必去見識一個即時的時鐘以在我們的時間裡執行更加複雜的可變時間更新(variable-time)。
一個直覺的關於使用這種固定時間方式的批評就是他不能讓動畫像可變時間方式那樣平滑的運行。這是一個有價值的擔心。如果我們讓我們的遊戲世界在某個特定的時間間隔更新,那麼我們的動畫絕不可能像時間間隔允許的那樣平滑的運行。但是,固定時間方式沒有要求只能使用一個時間步長,我們在我們的程式中使用多個更新tick.
例如,我們可以使用一個頻率更形我們的遊戲狀態,然後在一個更高的頻率更新我們的動畫。這讓我們能簡化我們更新程式世界使用的任何狀態機器(state-machine)和邏輯操作,同時提供平滑的,富有細節的動畫。對我們的簡單引擎來說,我們規定我們的ticks為一秒的1/30,也就大約33毫秒。我們同樣使用這個頻率跟新動畫,但是如果我們願意,可以讓門以一個更高的頻率開啟。
我們的時間步長(time-step)方法是在我們重載(overload)的CD3Dapplication的成員函數FrameMove()中實現的,程式清單4-1。我們同時增加了了一些線程管理函數來是我們的程式通其他windows程式和平的同步。我們的程式將會空閑知道一個完整的tick過去。當這段時間過去,我們更新我們的遊戲狀態,然後繼續回到空間狀態。如果我們估計我們的更新不需要耗費一個tick的時間來處理更新,我們的程式仍然花費等量的時間空間著。通過在執行完每個tick後降低我們線程的優先權和放棄剩餘的時間片段來讓其他的線程有機會更新。
如果沒有這些線程核查,我們的程式將會耗費100%的可用CPU。這將導致其他等待啟動並執行線程掛起,給作業系統一個不必要的負擔來讓所有的線程平滑的運行。增加這些措施協助作業系統高效的實行線程管理並且確保我們會在我們最需要的時候得到運行優先權。