Silverlight 1.0 でゲームを作る
Silverlight で作られているゲームが、いろいろ登場しています。たとえば、"Zero Gravity"(※Silverlight 1.1 Alpha が必要です)は、デザインもゲームプログラムとしても、なかなか凝って作られていて楽しめます。実のところ、こうしたゲームには Silverlight 1.1 Alpha 版を使って作成されているものも多いのですが、その理由は「.NET によるパフォーマンス」よりも「.NET 言語を使えることによる手軽さ」にあるのではないかと思います。というのも、Silverlight 1.0 も 1.1 も「描画性能」に違いはなく、キャラクタが動き回る程度の(思考ルーチンなどを持たない)ゲームであれば、JavaScript のパフォーマンスでも十分な場合もあるからです。
そこで、Silverlight 1.0 で「ものすごく単純」なゲームを作ってみました。題材にしたのはテレビゲームの元祖とも言える「テニス」です(もちろん、昨今のコントローラを振り回して遊ぶものとはまったく違います。30年くらい前は、こんなものでも立派に「テレビゲーム」と呼んでいたのです^_^;)。

※グレーの領域をマウスクリックすると、その場所からボールが移動します。左ラケットの移動は [A][Z] キー、右ラケットの移動は [K][M] キーです。
このゲームに必要な処理は、ボールの移動や衝突の処理、キー入力にともなうラケット(板)の移動処理などです。このアプリケーションで使っている XAML は以下の通りです。
<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="640" Height="480" Background="Darkgray" x:Name="Page">
<Canvas.Resources>
<Storyboard x:Name="NextFrame">
<DoubleAnimation x:Name="animBallX" BeginTime="00:00:00" Duration="0:0:0.05" From="320" To="330" Storyboard.TargetName="Ball" Storyboard.TargetProperty="(Canvas.Left)" />
<DoubleAnimation x:Name="animBallY" BeginTime="00:00:00" Duration="0:0:0.05" From="240" To="250" Storyboard.TargetName="Ball" Storyboard.TargetProperty="(Canvas.Top)" />
</Storyboard>
</Canvas.Resources>
<Rectangle Width="10" Height="80" Fill="Black" Stroke="#FF000000" Canvas.Left="50" Canvas.Top="100" x:Name="Player1"/>
<Rectangle Width="10" Height="80" Fill="Black" Stroke="#FF000000" Canvas.Left="580" Canvas.Top="280" x:Name="Player2"/>
<Rectangle Width="10" Height="10" Fill="Black" Stroke="#FF000000" Canvas.Left="310" Canvas.Top="240" x:Name="Ball"/>
</Canvas>
まず、「処理を繰り返す」ために、ここでは非常に短い間隔のアニメーション(Storyboard)を使っています。ここでは「Duration="0:0:0.05"」(0.05秒)と指定していますので、アニメーションを開始した0.05秒後に終了イベント(Completed)を発生させることができます。これを繰り返すことで、ボールを随時移動させているわけです。ラケットの移動もここで処理していますが、ボールの移動が From/To を使ったアニメーションであるのに対し、ラケットは座標値を直接書き換えているだけなので、ボールに比べて“カクカク“動きます。キーを押しているかどうかについては、KeyDown と KeyUp というイベントを使い、すべてのキーの状態(押している=true)を保持する isPressed という配列を使っています。ボール処理のたびに、この配列を確認して、ラケットの上下移動を処理します。あとは、ボールと壁、ラケットの関係に基づいて跳ね返らせたり、ゲームオーバーにするだけです。
// Canvas の KeyDown に割り当てるイベントハンドラ
handleKeyDown: function(sender, args)
{
isPressed[args.Key] = true;
},
// Canvas の KeyUp に割り当てるイベントハンドラ
handleKeyUp: function(sender, args)
{
isPressed[args.Key] = false;
},
// Storyboard の Completed に割り当てるイベントハンドラ
handleFrameFinished: function(sender, args)
{
this.NextFrame.Stop();
this.animBallY.From = PY;
if (((PY + DY) < 0) || (this.rootElement.Height <= (PY + DY)))
DY = -DY;
PY += DY;
this.animBallY.To = PY;
this.animBallX.From = PX;
if (DX < 0) {
if ((this.Player1["Canvas.Left"] <= (PX + DX)) && ((PX + DX) < (this.Player1["Canvas.Left"] + this.Player1.Width))
&& (this.Player1["Canvas.Top"] <= PY) && (PY <= (this.Player1["Canvas.Top"] + this.Player1.Height)))
DX = -DX;
} else {
if ((this.Player2["Canvas.Left"] < (PX + DX + STEP)) && ((PX + DX + STEP) <= (this.Player2["Canvas.Left"] + this.Player2.Width))
&& (this.Player2["Canvas.Top"] <= PY) && (PY <= (this.Player2["Canvas.Top"] + this.Player2.Height)))
DX = -DX;
}
PX += DX;
if (((PX + STEP) < 0) || (this.rootElement.Width < PX)) // game over
return;
this.animBallX.To = PX;
var LeftRacket = this.Player1["Canvas.Top"];
if (isPressed[30]) LeftRacket -= STEP * 2;
if (isPressed[55]) LeftRacket += STEP * 2;
if ((0 <= LeftRacket) && ((LeftRacket + this.Player1.Height) <= this.rootElement.Height))
this.Player1["Canvas.Top"] = LeftRacket;
var RightRacket = this.Player2["Canvas.Top"];
if (isPressed[40]) RightRacket -= STEP * 2;
if (isPressed[42]) RightRacket += STEP * 2;
if ((0 <= RightRacket) && ((RightRacket + this.Player2.Height) <= this.rootElement.Height))
this.Player2["Canvas.Top"] = RightRacket;
this.NextFrame.Begin();
}
JavaScript ソースコード → http://develop.net/samples/tennis/Page.xaml.js
Silverlight Tennis → http://develop.net/samples/tennis/
さて、少し早いのですが、本年はこれが最後のエントリになる予定です。すでに MSDN サブスクリプションで公開がはじまった Visual Studio 2008 をはじめ、来年第1四半期に登場する Silverlight 2.0 Beta、さらに Windows Server 2008、SQL Server 2008 など、エキサイティングなテクノロジが目白押しです。来年もどうぞよろしくお願いします。
皆様も、よいお年を。