id:fslashtさんのMIZU GAMEをSilverlightに移植しました。動作確認とソースのダウンロードは以下です。
オリジナルを初めて起動したとき、流れるような水の表現に圧倒されました。それを再現するため、SDL.NETを使用している部分はWriteableBitmapで書き換えています。
移植の流れ
オリジナルはSDL.NETを使用しています。依存するDLLの数が多くアンマネージのものも含まれているため、これらをまともに移植するのは無理です。まずSDL.NET依存を解消するため、MIZU GAMEで使用しているSDL.NETのAPIを抽出して、Windows Formsで再実装しました。以下はSdlDotNet.DLLを差し替えて不要になったDLLを削除したものです。EXEはオリジナルのままで、再ビルドなどは行っていません。
さすがにDirectXを使用しているSDLには及びませんが、それでも悪くない速度で動きます。これをid:n7shi:20090730で開発したWindows Formsエミュレーションを使用してSilverlightで動かしてみました。一応動きましたが、まったくお話にならない速度です。
オリジナルのソースに手を加えずに移植するのは諦めて、Silverlightに移植することにしました。
ShapeとWriteableBitmap
CanvasにShape(Image/Rectangle)を並べて画面を構築する方法で移植してみました。Windows Formsエミュレーションよりは速度は出ましたが、それでもまだ遅いです。不要な書き換えを減らすため、壁は一度だけ描いて変更しないようにしました。
水は、碁盤の目のようにRectangleを並べて、必要ないものはVisibilityで隠したり、色が変わったときだけFillを変更するようにしてみました。これはとんでもなく遅くて1fpsすら出ませんでした。あくまで体感ですが、動作速度はCanvas上のオブジェクトの数にO(n^2)で比例していて、Visibilityは関係ないようです。そのためオブジェクトが一定数を超えたあたりから急激に遅くなります。
不要なRectangleは取り除いて、色が変わったときだけFillを変更するようにすると、かなり改善しました。しかし定期的に引っ掛かるような動作がどうしても直りません。デモ画面のスクロールも絶望的に遅いです。Shapeを並べる方法ではこれが限界のようです。
壁や水はWriteableBitmapに描画して、主人公などはスプライト的にImageを使うという形にしてみました。劇的に改善しました。これが冒頭で公開したSiliverlight移植版です。WriteableBitmapへの書き込みは単純な配列書き換えのためアクセラレーションが期待できませんが、想像していた以上に速度が出て驚きました。
WriteableBitmap.Invalidate()
WriteableBitmapのPixelsをいじった後はInvalidate()しないとImageに反映されません。これに気付くまでChildren.Add()/Remove()を繰り返したりと試行錯誤してしまいました。
System.Drawing.Bitmapに比べてLockしたりマーシャリングしたりしなくて良いのでとても楽です。検索するとWriteableBitmapでもLockするような情報が出てきたりもしますが、これはSilverlight 3βまでの仕様で、正式版では削除されたようです。