スペースウォー!(Spacewar!)は1962年、当時マサチューセッツ工科大学(MIT)の学生であったスティーブ・ラッセルを中心に開発された、宇宙戦争をモチーフとした対戦型コンピューターゲームです。世界初のシューティングゲームとされています。ゲヱム道館 – Gamedokanさん作成の動画を参考につくってみました。動画ではOpenGLを使用していますが、こちらではC# .NET Frameworkを使います。

当時のハードウェアの仕様で残像が出る部分もそれっぽくつくってみました。

プレイヤーの宇宙船をつくる

まずプレイヤーの宇宙船をつくります。片方はくさび形、もう一方はニードル型をしています。

ちょっと小さいので拡大すると

これをリソースとして追加しておきます。

単にビットマップを移動させるだけでなく残像になる部分も描画しなければならないのでアルファチャンネルを変えて複数のBitmapを描画します。

もとになるBitmapをつくる

もとになるBitmapを2倍のサイズで表示します。CreatePlayerBitmapでリソースのBitmapを読み込んで、背景を黒で画像ファイルでは黒い部分を白で表示できるようにしています。

拡大処理をするときに色が変化してしまわないようにInterpolationMode.NearestNeighborを指定し、Bitmap.GetPixelメソッドで取得した色がColor.Black.ToArgb()でないときは何も書き込まないようにしています。

残像にあたるBitmapを生成する

次に残像にあたる部分を描画するためのBitmapのリストを生成します。残像は32フレームのあいだ不透明度を減らしながら描画されます。ただしリストへは不透明度が低いものから追加しています。

CreateAfterimagePensメソッドは宇宙船後部のロケット噴射を描画するためのものです。これも32段階で不透明度が低いものからPenを生成してリストに追加しています。

宇宙船を描画する

宇宙船を描画する処理を示します。

自機死亡の場合は描画の処理は必要ないのでreturnしています。宇宙船は方向転換するのでアフィン変換をしてGraphics.DrawImageメソッドで描画します。宇宙船の中心座標とサイズから矩形の3点を求め、Matrix.TransformPointsメソッドに中心座標と角度を渡して変換された3点を取得します。配列には5点格納していますが、最後の2点はロケット噴射を描画するためのものです。

残像は古いものから先に描画しないといけないのでDrawメソッドが実行されるたびに新しい座標を先頭に追加して最新の32個を取得します。そして古い順に並べ替えて描画しています。

移動できるようにする

描画するだけでなく移動できるようにします。

ワープと減速の処理を示します。

弾丸を発射する

弾丸を発射する処理を示します。弾丸の移動と描画はあとで作成するBurretクラスで行ないます。

連射を無制限にできないようにCountUntilCanShootが0よりも大きいときは発射できない仕様にしています。前述のMoveメソッドのなかで減算され、弾丸を発射するとCountUntilCanShootMaxに戻ります。

弾丸は宇宙船が向いている方向に発射されますが、慣性の法則によって逆方向に進行しているときは弾丸の速度は相殺されます。

Form1クラスの処理

Form1クラスの処理を示します。

コンストラクタ内でリソースからプレイヤー(自機と敵機)を生成します。そしてタイマーでTickイベントを処理できるようにしておきます。

キー操作による自機の操作

キーが押されたら自機を操作することができます。← と → キーは方向転換ができるだけです。↑キーで加速します。減速するためには速度が自然に低下するのを待つか、逆方向を向いて加速するしかありません。操縦はしにくいです。

移動と描画

Timer.Tickイベントが発生したらどの方向キーが押されているかを調べて自機の運動を変化させ、Invalidateメソッドを呼び出して描画します。自機を移動させると残像もいい感じに描画されているのがわかります。