2011-08-20 102 views
7

我在玩一個小遊戲項目,因爲我在TDD方面不是很有經驗,所以我很樂意在幾件事情上得到一些專家意見。TDD和遊戲物理

首先,我很早就意識到TDD對於遊戲開發來說似乎並不理想。看來這個主題的觀點差異很大。我最初沒有受過教育的意見是TDD好像對所有的遊戲邏輯都能很好地工作。我認爲,任何能夠處理視頻輸出和聲音的東西都會被抽象成可視化測試的類。

事情開始順利。目標是創建一個2D天體飛行遊戲(對於那些關心的小行星)。我爲Ship類創建了一系列單元測試。諸如初始化,旋轉之類的東西可以很容易地在一系列測試中使用,比如:GetRotation(),TurnRotateRightOn(),Update(1),GetRotation(),Expect_NE(rotation1,rotation2)。然後我遇到了第一個問題。

我對TDD的理解是,你應該寫測試你認爲應該如何使用這個類。我希望這艘船能夠移動,所以我寫了一個基本上講過的課。 GetCoordinates(),ThrustOn(),Update(1),GetCoordinates()。這很好,以確保船舶移動某處。但是,我很快意識到我必須確保船舶以正確的速度向正確的方向移動。接下來是75線單元測試,我基本上必須初始化旋轉,檢查座標,初始化推力,更新船舶,獲取新座標,檢查新的旋轉。更重要的是,我可以看到沒有必要在遊戲中獲得船的速度(只是座標,船應該更新自己)。正因爲如此,我沒有直接的方法來獲得速度。所以測試基本上必須重新計算速度應該是什麼,所以我可以確保它與更新後得到的座標相匹配。總而言之這是非常混亂,非常耗時,但工作。測試失敗,測試通過等。

這很好,直到後來我意識到我想將船的更新代碼重構爲抽象的「Actor」類。我意識到,儘管Actor的每個子類都需要能夠正確計算新的位置,但並非每個子類都必須以相同的方式更新其速度(有些碰撞,有些不會,有些具有靜態速度)。現在,我基本上面臨着複製和改變巨大而龐大的測試代碼的前景,我不禁想到應該有更好的方法。

有沒有人有處理單元測試這種複雜的黑匣子類型的工作經驗?看起來我基本上不得不在測試中編寫完全相同的物理代碼,所以我知道結果應該是什麼。這似乎是自我挫敗,我確信我錯過了這一切的一切。我非常感謝任何人可以提供的幫助或建議。

+0

這個問題不屬於gamedev SE嗎?他們可以在那裏更好地回答它。 – Spoike

+0

我沒有意識到gamedev SE!我會在未來提出類似的問題。謝謝! – Landon

回答

5

我建議你首先創建一個計算位置和方向的組件,給定一系列控制輸入。那個部分就是爲了測試而構成的「單位」。該組件的測試用例可以行使您可以想到的所有場景:零加速度,恆定的非零加速度,脈衝加速度命令等。如果應用程序不需要速度,那麼該組件不會公開任何功能與速度有關。

當生成預期產出以包含在測試中時,對於那些預期結果是否正確具有高置信度非常重要。出於這個原因,需要最小化生成期望的結果所需的代碼量。尤其是,如果您發現自己編寫的測試腳手架幾乎與被測組件一樣複雜,那麼出現測試本身的bug的前景就成爲一個嚴重的問題。

在這種情況下,我會直接從運動方程生成測試數據。我使用Mathematica來達到這個目的,因爲我可以直接輸入方程,解決它們,然後生成結果的圖表和表格。這些圖表讓我可以看到結果,從而確信它們是可信的。 Excel/OpenOffice/Google Apps可以用於相同的目的,也可以用於像Sage這樣的Mathematica的開源替代品。無論選擇什麼,關鍵的問題是能夠解決運動方程而不必編寫非平凡的代碼。

一旦我們有了一組好的測試用例以及預期的結果,我們就可以編寫單元測試。請注意,測試代碼非常簡單,本身不執行任何計算。它只是比較組件的輸出和我們之前獲得的硬編碼結果。通過測試用例,我們可以編寫組件本身,添加代碼直到測試全部通過。當然,在嚴格的TDD中,這些操作正是按照這個順序發生的。我承認,我不親自堅持瀑布,並傾向於在創建測試數據,編寫測試和編寫組件代碼之間來回反彈。

Mathematica或Excel文檔本身具有超出測試初始創建的有用壽命。當添加新功能或者(天堂禁止)稍後會發現錯誤時,可以再次使用它們。我會主張處理源代碼等文檔。

在本練習結束時,結果是一個「防爆炸」組件,我們相信自己會計算任何給定控制輸入集合下物體的正確位置和方向。從這個基礎上,我們可以構建更多使用該功能的組件,如船隻,小行星,碟子和鏡頭。爲了避免每個組件的測試用例出現組合式的爆炸,我將採用嚴格的黑盒測試方法。因此,例如,如果我們正在測試「ship」組件,我們會編寫測試,知道它使用位置/方向組件。使用這種白盒知識,我們可以避免重新測試與運動有關的所有角落案例。船舶單元測試可以執行「煙霧測試」來驗證船舶實際上是否對控制輸入作出響應,但主要關注的是測試船舶部件本身的任何獨特功能。

因此,要總結:

  • 化妝位置/姿態計算單個組件
  • 的責任產生的數據使用外部工具,讓高可信度的數據了一套全面的測試用例是在自己
  • 通過使用白盒知識
  • 躲閃的測試用例在組件層次結構中的組合爆炸測試正確
  • 避免複雜的計算邏輯3210
+0

這就是我正在尋找的!偉大的建議。謝謝! – Landon

1

你可能會貶低你的測試了一下。與其檢查正確的矢量和加速度,您可以簡單地檢查被測物體是否完全移動。在大多數遊戲中,無論如何你都會在物理模型中引入一些小的隨機性來保持有趣。

1

我認爲這可能會有所幫助,如果你採取更多的「插曲」方法。不是跟蹤你似乎正在做的連續體的座標和旋轉,你可以簡單地指定你的太空飛船應該在哪裏,以及在30個遊戲步驟之後的旋轉方向。如果這證明是正確的,那麼你的船可能在中間做了所有正確的事情。您將以這種方式編寫更少的測試代碼。

相同的想法通過定位碰撞的「情節」起作用。如果一個檯球打算從兩面牆壁彈開並擊中另一個球,那麼在最後一次碰撞發生時可以提起一個事件,並檢查碰撞的「入射角」。再一次,你沒有檢查其間的所有步驟。如果入射角度是正確的,那麼在擊中最後的球之前,球可能正確地從兩個牆壁反彈。

當然,你必須爲沒有發生碰撞的情況做好準備。您的測試可以計算每單位時間的遊戲點擊次數以達到最終碰撞。您將進行必要次數的遊戲點擊以實現碰撞。如果碰撞沒有在規定的點擊次數內發生,則測試可以正確地失敗。所有這些都是在遊戲點擊中完成的,而不是實時的,這樣測試可以立即發生,而不是等待預期的結果(就像你通常在玩遊戲時一樣)。