程序清單3-11 繪制多幀動(dòng)畫(huà)中單獨(dú)的一幀
// A variable to store the current animation frame.
int animFrame = 0;
Private void Form1_Paint(object sender, PaintEventArgs e)
{
const int frameWidth = 75; // The width of each animation frame
const int frameHeight = 75; // The height of each animation frame
// Create the source rectangle.
// This will have a width and height of 75 (the size of our animationframe).
// The x-coordinate will specify the position within the source image
// from which we want to copy. Multiplying the animation frame number by
the frame width
// results in a coordinate at the left of the frame that we are going to
// copy.
Rectangle srcRect = new Rectangle(animFrame * frameWidth, 0, frameWidth, frameHeight);
// Draw the bitmap at coordinate (100, 100)
e.Graphics.DrawImage(myBitmap, 100, 100, srcRect, GraphicsUnit.Pixel);
// Move to the next animation frame for the next Paint
animFrame += 1;
}
接下來(lái)對(duì)函數(shù)DrawImage中傳遞的參數(shù)進(jìn)行解釋:
● 第一個(gè)參數(shù)為需要在屏幕上進(jìn)行繪制的Bitmap對(duì)象(myBitmap)。
● 接下來(lái)指定圖像所要顯示的位置,用x坐標(biāo)和y坐標(biāo)的形式,在本例中為(100,100)。
● 接下來(lái)再指定源圖像中要繪制的區(qū)域的位置及大小(srcRect)。
● 與該函數(shù)的桌面版一樣,其.NET CF版也讓我們提供GraphicsUnit來(lái)測(cè)量Rectangles。由于現(xiàn)在的.NET CF版本中只支持像素,所以我們只能將GraphicsUnit.Pixel作為該參數(shù)的值。
2. 縮放
除了能夠通過(guò)一個(gè)矩形來(lái)讀取指定源圖像的某個(gè)區(qū)域,我們還可以提供另一個(gè)矩形來(lái)指定繪制目標(biāo)區(qū)域,而不像以前那樣簡(jiǎn)單地使用坐標(biāo)。如果目標(biāo)矩形與原始矩形大小不同,那么位圖會(huì)被縮放來(lái)適應(yīng)目標(biāo)矩形的尺寸。
這個(gè)功能具有潛在的作用,但是,對(duì)源位圖進(jìn)行縮放是個(gè)相當(dāng)慢的操作,可能會(huì)影響游戲的運(yùn)行速度。偶爾適當(dāng)?shù)厥褂靡幌驴s放會(huì)產(chǎn)生有用的效果,但不能將它作用于大量的圖像上,否則游戲的幀率會(huì)大幅下降。
要使用該功能的話,需要像指定源Rectangle對(duì)象和目標(biāo)Rectangle對(duì)象,如程序清單3-12所示。如果兩個(gè)矩形尺寸不一致,那么圖像就會(huì)根據(jù)情況進(jìn)行縮放。
程序清單3-12 將位圖的寬與高放大到原來(lái)的兩倍
private void Form1_Paint(object sender, PaintEventArgs e)
{
// Create the source rectangle to match the size of the bitmap.
Rectangle srcRect = new Rectangle(0, 0, myBitmap.Width, myBitmap.Height);
// Create the destination rectangle at double the size of the source rectangle.
Rectangle destRect = new Rectangle(100, 100, srcRect.Width * 2, srcRect.Height * 3);
// Draw the bitmap
e.Graphics.DrawImage(myBitmap, destRect, srcRect, GraphicsUnit.Pixel);
}
3. 顏色鍵
DrawImage函數(shù)最后要提到的這個(gè)功能可能是最重要的一個(gè)功能:繪制圖像時(shí)使圖像的某個(gè)區(qū)域透明。我們現(xiàn)在為止所看到的示例都是將圖像完全不變地復(fù)制到屏幕的矩形區(qū)域中,將該區(qū)域原來(lái)的東西完全覆蓋。絕大部分情況下,我們都會(huì)希望要繪制的圖像與已存在的圖像重疊時(shí),不要出現(xiàn)那些矩形的空白。
圖3-14展示了DrawImage函數(shù)標(biāo)準(zhǔn)的繪圖行為。您可以看到第二個(gè)圓形圖像的左側(cè)將第一個(gè)圖像剪切出了一個(gè)空白區(qū)域。而在右邊的圖中,這兩個(gè)圓互不妨礙地重疊在一起。
圖3-14 在繪圖時(shí)沒(méi)有采用顏色鍵的效果(左圖)與采用顏色鍵的效果(右圖)
使用一個(gè)顏色鍵可以得到圖3-14右圖的效果,我們將指定源圖像中的某一種想要使之成為透明的顏色,然后將該顏色傳遞給DrawImage函數(shù)。在屏幕上繪圖時(shí)任何一個(gè)與該顏色匹配的像素都會(huì)變?yōu)橥该?。這些透明的像素不只會(huì)像本例中那樣只是出現(xiàn)在圖像的外部,它們可以出現(xiàn)在任何需要進(jìn)行透明處理的地方。因此,您需要選擇一個(gè)圖像中還沒(méi)有使用的顏色。
顏色鍵只能使位圖像素完全透明(對(duì)于那些與顏色鍵相匹配的像素)或者完全不透明(對(duì)于所有其他像素)。它不支持GDI提供的透明度或者半透明繪制(在第10章介紹OpenGL ES時(shí)您就會(huì)看到在繪圖中如何處理透明度)。
要指定顏色鍵,需要?jiǎng)?chuàng)建一個(gè)ImageAttributes對(duì)象。這又是一個(gè)桌面版.NET類的精簡(jiǎn)版本,實(shí)際上,該類中只保留了SetColorKey和ClearColorKey這兩個(gè)有用的函數(shù)。
通過(guò)調(diào)用SetColorKey函數(shù)來(lái)指定要透明化的顏色。您會(huì)發(fā)現(xiàn)該函數(shù)實(shí)際要接受兩個(gè)Color類的參數(shù),參數(shù)名分別為colorLow和colorHigh。其原因是要與其桌面版.NET函數(shù)保持一致,在桌面版的.NET函數(shù)中可以指定一個(gè)顏色范圍。然而,.NET CF只支持單個(gè)顏色,所以要為這兩個(gè)參數(shù)指定同一個(gè)顏色。程序清單3-13向屏幕繪制圖像時(shí)令所有白色的像素為透明。