程序清單3-11 繪制多幀動畫中單獨的一幀
// 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;
}
接下來對函數(shù)DrawImage中傳遞的參數(shù)進(jìn)行解釋:
● 第一個參數(shù)為需要在屏幕上進(jìn)行繪制的Bitmap對象(myBitmap)。
● 接下來指定圖像所要顯示的位置,用x坐標(biāo)和y坐標(biāo)的形式,在本例中為(100,100)。
● 接下來再指定源圖像中要繪制的區(qū)域的位置及大小(srcRect)。
● 與該函數(shù)的桌面版一樣,其.NET CF版也讓我們提供GraphicsUnit來測量Rectangles。由于現(xiàn)在的.NET CF版本中只支持像素,所以我們只能將GraphicsUnit.Pixel作為該參數(shù)的值。
2. 縮放
除了能夠通過一個矩形來讀取指定源圖像的某個區(qū)域,我們還可以提供另一個矩形來指定繪制目標(biāo)區(qū)域,而不像以前那樣簡單地使用坐標(biāo)。如果目標(biāo)矩形與原始矩形大小不同,那么位圖會被縮放來適應(yīng)目標(biāo)矩形的尺寸。
這個功能具有潛在的作用,但是,對源位圖進(jìn)行縮放是個相當(dāng)慢的操作,可能會影響游戲的運行速度。偶爾適當(dāng)?shù)厥褂靡幌驴s放會產(chǎn)生有用的效果,但不能將它作用于大量的圖像上,否則游戲的幀率會大幅下降。
要使用該功能的話,需要像指定源Rectangle對象和目標(biāo)Rectangle對象,如程序清單3-12所示。如果兩個矩形尺寸不一致,那么圖像就會根據(jù)情況進(jìn)行縮放。
程序清單3-12 將位圖的寬與高放大到原來的兩倍
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ù)最后要提到的這個功能可能是最重要的一個功能:繪制圖像時使圖像的某個區(qū)域透明。我們現(xiàn)在為止所看到的示例都是將圖像完全不變地復(fù)制到屏幕的矩形區(qū)域中,將該區(qū)域原來的東西完全覆蓋。絕大部分情況下,我們都會希望要繪制的圖像與已存在的圖像重疊時,不要出現(xiàn)那些矩形的空白。
圖3-14展示了DrawImage函數(shù)標(biāo)準(zhǔn)的繪圖行為。您可以看到第二個圓形圖像的左側(cè)將第一個圖像剪切出了一個空白區(qū)域。而在右邊的圖中,這兩個圓互不妨礙地重疊在一起。
圖3-14 在繪圖時沒有采用顏色鍵的效果(左圖)與采用顏色鍵的效果(右圖)
使用一個顏色鍵可以得到圖3-14右圖的效果,我們將指定源圖像中的某一種想要使之成為透明的顏色,然后將該顏色傳遞給DrawImage函數(shù)。在屏幕上繪圖時任何一個與該顏色匹配的像素都會變?yōu)橥该?。這些透明的像素不只會像本例中那樣只是出現(xiàn)在圖像的外部,它們可以出現(xiàn)在任何需要進(jìn)行透明處理的地方。因此,您需要選擇一個圖像中還沒有使用的顏色。
顏色鍵只能使位圖像素完全透明(對于那些與顏色鍵相匹配的像素)或者完全不透明(對于所有其他像素)。它不支持GDI提供的透明度或者半透明繪制(在第10章介紹OpenGL ES時您就會看到在繪圖中如何處理透明度)。
要指定顏色鍵,需要創(chuàng)建一個ImageAttributes對象。這又是一個桌面版.NET類的精簡版本,實際上,該類中只保留了SetColorKey和ClearColorKey這兩個有用的函數(shù)。
通過調(diào)用SetColorKey函數(shù)來指定要透明化的顏色。您會發(fā)現(xiàn)該函數(shù)實際要接受兩個Color類的參數(shù),參數(shù)名分別為colorLow和colorHigh。其原因是要與其桌面版.NET函數(shù)保持一致,在桌面版的.NET函數(shù)中可以指定一個顏色范圍。然而,.NET CF只支持單個顏色,所以要為這兩個參數(shù)指定同一個顏色。程序清單3-13向屏幕繪制圖像時令所有白色的像素為透明。