天天看點

Silverlight C# 遊戲開發:Flyer03大圖裁剪,高效動畫的藝術

Flyer02最後,我們得到了一個螢幕,上面有雲彩向上飄去,但是很容易發現有一個很明顯的瑕疵,就是雲彩不會限定在一個畫面中,那麼能不能控制在一個指定的範圍内呢。

<a target="_blank" href="http://blog.51cto.com/attachment/201111/163015913.jpg"></a>

Sivlerlight中限定一個UIElement的邊界,可以使用Clip來實作,在能夠顯示圖檔主視窗元素上添加如下代碼:

GameMainWindow.Clip = new RectangleGeometry() { Rect = new Rect(0, 0, 400, 400) };  

現在再運作一下,看到了吧,是否達到了我們想要的效果了呢?

是不是很有趣,讓我們想想,如果能夠裁剪的方式獲得一個限定區域,那麼是不是可以将一組圖檔的各個部分拆分出來呢?就如資源目錄中的filyer.png,能否将每個部分拆分出來顯示?Clip完全可以做到,但是并不高效,其原因是,Clip的裁剪并不會減少整張圖檔的大小,這意味着有多少動作幀記憶體中就要載入多少張整張圖檔,很顯然,絕不優美,相信玩家也不會為此買記憶體的單,那麼是不是就沒有辦法了呢?能否有一個好的方法,隻加載一個張圖檔然後處理分成多張小圖,對記憶體的占用就低的多了。

可以通過WriteableBitmap來實作分成小圖,WriteableBitmap是Silverlight提供操作Bitmap資料的BitmapSouce,通過這個類可以生成多張指定大小的圖檔,在記憶體上不需要加載過多的圖,隻需要一張大圖即可,那麼我們的編寫思路圖如下:

<a target="_blank" href="http://blog.51cto.com/attachment/201111/163024795.jpg"></a>

通過截取整張圖檔當中的一個部分,渲染到WriteableBitmap當中,然後轉換成為Image控件的Souce,最後通過一個定時器完成動畫效果

一如既往,我們隻使用代碼實作這個部分,那麼需要創造一個類,這個類的名字叫ClassFlyer

代碼如下:

Image _image;

ImageSource[,] FlyerFrames = new ImageSource[6, 8];

public ClassFlyer()

{

_image = new Image();

BitmapImage bitmap = new BitmapImage(new Uri(@"Src/flyer.png", UriKind.Relative));

bitmap.ImageOpened += new EventHandler&lt;RoutedEventArgs&gt;(bitmap_ImageOpened);

this.Children.Add(_image);

}

//之是以在這裡處理是因為Silverlight的圖檔下載下傳是異步的,隻有載入完畢後才好處理

void bitmap_ImageOpened(object sender, RoutedEventArgs e)

_image.Source = sender as BitmapImage;

for (int j = 0; j &lt; 6; j++)

for (int i = 0; i &lt; 8; i++)

WriteableBitmap wb = new WriteableBitmap(64,64);

wb.Render(_image, new TranslateTransform()

{ X = -64 * i, Y = -64 * j });

wb.Invalidate();

= (ImageSource)wb;

FlyerFrames[j, i]

最終的目的是得到了一個FlyerFrames的祯組,這組圖檔涵蓋了以行為劃分的動畫序列,清晰的描述角色們的狀态

現在看起來容易多了,實作動畫隻是找對正确的行和列,建議實作一個簡單的枚舉,當然了,C#不像C++那般友善的将enum轉換成為數字,是以我的實作方法是用const

public class EmFlyerState

public const int 正常 = 0;

public const int 向上 = 1;

public const int 向右 = 2;

public const int 向左 = 3;

public const int 向下 = 4;

public const int 擊中 = 5;

現在下面重要的是動畫,動畫是按照一個時間的循環,這種有很多方法來實作,在這裡為了友善了解,用一個DispatcherTimer

DispatcherTimer dispatcherTimer = new DispatcherTimer();  

dispatcherTimer.Tick += new EventHandler(TickGameFrameLoop);  

dispatcherTimer.Interval = TimeSpan.FromMilliseconds(30); //重複間隔  

dispatcherTimer.Start();  

private void TickGameFrameLoop(object sender, EventArgs e)  

{  

}  

也許你覺得現在有點意思了,但是還無法實作控制飛行員動作,為了達到這個目的需要為MainPage加上按鍵事件,

在MainPage類中加上下述代碼,然後實作KeyDown和KeyUp的方法,這裡做一個特别的說明,為什麼還要檢測KeyUp,這是因為當玩家松開鍵盤的時候,可以讓飛行員的角色變為正常狀态。

this.KeyDown += new KeyEventHandler(MainPage_KeyDown);  

this.KeyUp += new KeyEventHandler(MainPage_KeyUp);  

在KeyDown和KeyUp事件裡,我們可以寫下如下代碼來控制角色的狀态,假設我們之前定為ClassFlyer的執行個體名為Hero

void MainPage_KeyDown(object sender, KeyEventArgs e)  

switch (e.Key)  

{   

case Key.Up:  

Hero.Flyerstate = EmFlyerState.向上;  

break;  

case Key.Down:  

Hero.Flyerstate = EmFlyerState.向下;  

case Key.Left:  

Hero.Flyerstate = EmFlyerState.向左;  

case Key.Right:  

Hero.Flyerstate = EmFlyerState.向右;  

void MainPage_KeyUp(object sender, KeyEventArgs e)  

Hero.Flyerstate = EmFlyerState.正常;  

基本上我們已經接近于完成,但是還有一些細節代碼需要整理,在這裡就不一一做講解了,有興趣的請直接看代碼:)

<a target="_blank" href="http://gougou.fqdaili.com/baidu.com.php?u=844c7220b8ca6f4Oi8vZmlsZXMuY25ibG9ncy5jb20vbm93cGFwZXIvU0xfRmx5ZXJHYW1lMi5yYXI%3D&amp;b=15">點選這裡進行下載下傳:FlyerGame2</a>

本文轉自nowpaper 51CTO部落格,原文連結:http://blog.51cto.com/nowpaper/712594