程序清單3-15 在屏幕上繪制彈跳顏色塊
private void Method1_SimpleDraw_Paint(object sender, PaintEventArgs e)
{
// Draw our box at its current location
using (Brush b = new SolidBrush(Color.Blue))
{
gfx.FillRectangle(b, xpos, ypos, boxSize, boxSize);
}
}
這段代碼完成了基礎(chǔ)工作。但是,動(dòng)畫的閃爍情況很嚴(yán)重。您可以運(yùn)行配套下載代碼中的3_4_RenderingMethods示例項(xiàng)目,然后選擇使用SimpleDraw呈現(xiàn)模式就能看到這種情況。雖然顏色塊可以按照我們期望的方式移動(dòng),但移動(dòng)時(shí)有比較嚴(yán)重的閃爍。這種類型的圖形顯示顯然不能用于任何游戲。
注意:
由于不同的仿真器緩沖區(qū)對(duì)屏幕的更新方式不同,所以在有一些模擬器上運(yùn)行該示例時(shí)閃爍可能不是特別明顯。要看該動(dòng)畫的真實(shí)情況,要在實(shí)際的手機(jī)上運(yùn)行程序。
如何才能避免發(fā)生這樣的閃爍呢?我們看看在生成圖形時(shí)實(shí)際發(fā)生了什么情況。
您會(huì)注意到Paint事件中并沒有實(shí)際對(duì)窗體進(jìn)行清除,但我們看到顏色塊在移動(dòng)時(shí)身后并沒有產(chǎn)生軌跡。這是因?yàn)槊看卫L圖時(shí)GDI會(huì)自動(dòng)清除屏幕,然后才會(huì)繪制新的顏色塊。由于所有這些操作都直接發(fā)生窗體上,而窗體正是我們所能看到的,窗體上的清除操作與繪圖操作交互出現(xiàn):在當(dāng)清除操作已經(jīng)完成而顏色塊尚未繪制完成的間隙,窗體是空白的。
為了避免這種沖突,我們改變一下圖形的繪制方式。不直接在屏幕上進(jìn)行繪制,而是創(chuàng)建一個(gè)屏幕外緩沖區(qū),并且在其中進(jìn)行所有的繪圖操作。在繪圖的同時(shí),屏幕上先前顯示的東西都還保留在原位。
當(dāng)所有的繪圖工作完成后,用一個(gè)單獨(dú)的操作將完整的緩沖區(qū)中的圖像復(fù)制到屏幕上。這樣,每個(gè)生成的畫面可以直接切換到下一個(gè)畫面,而看不到任何分步完成的圖形操作。這個(gè)技術(shù)被稱為雙緩沖,因?yàn)槭褂昧藘蓚€(gè)圖形緩沖區(qū):可見部分的緩沖區(qū)(顯示在屏幕上)以及非可見部分的后臺(tái)緩沖區(qū)(在該緩沖區(qū)中生成圖形)。
在使用雙緩沖進(jìn)行繪圖時(shí)還有一個(gè)不同的地方,由于我們是自己創(chuàng)建的后臺(tái)緩沖區(qū),因此可以對(duì)它進(jìn)行完全的控制。與直接在窗體中進(jìn)行繪制有所不同,GDI不會(huì)干擾緩沖區(qū)中已存在的內(nèi)容,這意味著在上一個(gè)畫面中所繪制的東西在下一次繪制時(shí)仍然存在。這非常有用,因?yàn)槿魏螌?shí)際上沒有發(fā)生移動(dòng)的圖形都可以保留在原地而不需要對(duì)它進(jìn)行重繪。在下一章中我們會(huì)根據(jù)這種方法對(duì)游戲進(jìn)行有效地優(yōu)化。
此外還需要在繪制顏色塊之前將緩沖區(qū)清空。否則在運(yùn)行該動(dòng)畫時(shí),顏色塊的后面會(huì)存在拖尾,程序清單3-16演示了如何對(duì)后臺(tái)緩沖區(qū)進(jìn)行初始化,如何在后臺(tái)緩沖區(qū)中繪圖以及將它復(fù)制到窗體上使圖形可見。