Linuxでもc#でしょぼいシューティングゲームを制作してみる

はじめに

こんにちは、野村です。

今回は、しょぼいシューティングゲームをc#で書いてみます。
ゲームの概要はこんな感じ。

・複数の飛行物体が左から右へ移動するのでそれらを砲台で撃ち落とす。
・飛行物体が爆弾を落とすので、放題を左右に移動しながら避けなければいけない。

以上です。

Monoのインストール

Linix上でC#で書いたプログラムをビルド/実行するためには、Monoがインストールされている必要があります。
Monoというのは、.NET Framework互換の環境を実現するためのオープンソースのソフトウェア群です。

管理ユーザになって以下のコマンドを実行します(debianの場合)。

# apt install mono-devel

ソースコード

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using System.Linq;

public class MainWindow: Form
{
  private Random rnd;
  private Label btn00, dspMessage, dspLife;
  private Label[] ufo, bomb, ms;
  private int point, life;
  private Boolean canReplay;
  private System.Windows.Forms.Timer timer;

  public MainWindow()
  {
    this.Size = new Size (400, 400);
    this.Text = "shooting00";
    this.BackColor = Color.Black;

    rnd = new Random ();

    canReplay = true;

    dspMessage = new Label ();
    dspMessage.ForeColor = Color.White;
    dspMessage.Text = "PRESS Y START";
    dspMessage.Left = 150;
    dspMessage.Top = 230;
    this.Controls.Add (dspMessage);

    dspLife = new Label ();
    dspLife.ForeColor = Color.White;
    dspLife.Left = 320;
    dspLife.Top = 350;
    this.Controls.Add (dspLife);

    btn00 = new Label ();
    SetLabel (btn00, Color.Beige, 50, 20, 180, 300);
    this.Controls.Add (btn00);

    ms = new Label[3];
    for (int i=0; i<3; i++) {
      ms [i] = new Label ();
      SetLabel (ms [i], Color.Aqua, 1, 10, -1000, -1000);
      this.Controls.Add (ms[i]);
    }

    ufo = new Label [7];
    for (int i=0; i<7; i++) {
      ufo [i] = new Label ();
      SetLabel (ufo [i], Color.Aquamarine, 50, 20, rnd.Next (400), rnd.Next (200));
      this.Controls.Add (ufo[i]);
    }

    bomb = new Label[7];
    for (int i=0; i<7; i++) {
      bomb[i] = new Label();
      SetLabel (bomb [i], Color.Brown, 1, 10, -1000, -1000);
      this.Controls.Add (bomb[i]);
    }

    timer = new System.Windows.Forms.Timer();
    timer.Tick += new EventHandler(OnTick);
    timer.Interval = 60;

    this.KeyPreview = true;
    this.KeyPress += new KeyPressEventHandler (OnPress);
  }

  private void SetLabel(Label o, Color c, int w, int h, int l, int t){
    o.BackColor = c;
    o.Width = w;
    o.Height = h;
    o.Left = l;
    o.Top = t;
  }

  private void Start(){
    point = 0;
    life = 3;
    LMove (dspMessage, -1000, -1000);
    dspLife.Text = "LIFE: " + life.ToString ();
    canReplay = false;
    btn00.Text = point.ToString ();
    timer.Start ();
  }

  private void OnTick(object sender, EventArgs e){
    foreach (Label u in ufo) {
      u.Left += rnd.Next(10) + 5;
      if (u.Left >= 400) LMove (u, -50, rnd.Next (200));

      if (rnd.Next (10) != 0) continue;
      Label b = bomb.FirstOrDefault (c => c.Top == -1000);
      if (b != null) LMove (b, u.Left + 25, u.Top);
    }

    foreach (Label b in bomb.Where(c=>c.Top != -1000)) {
      b.Top += 10;
      if (b.Top >= 350) LMove(b, -1000, -1000);

      if ( !isColl(b, btn00) ) continue;
      bomb.AsParallel().ForAll(b0=>LMove(b0, -1000, -1000));
      Thread.Sleep (500);
      life--;
      dspLife.Text = "LIFE: " + life.ToString ();
      if (life < 1) GameOver ();
    }

    foreach(Label m in ms.Where(c=>c.Top != -1000)){
      m.Top -= 15;
      if (m.Top < 0) LMove (m, -1000, -1000);

      Label u = ufo.FirstOrDefault (c => isColl (m, c));
      if (u == null) continue;
      point++;
      btn00.Text = point.ToString ();
      LMove (m, -1000, -1000);
      LMove (u, -50, rnd.Next(200));
    }
  }

  private Boolean isColl(Label p0, Label p1){
    if (p0.Left < p1.Left) return false;
    if (p0.Left > p1.Left + 50) return false;
    if (p0.Top < p1.Top) return false;
    if (p0.Top > p1.Top + 20) return false;
    return true;
  }

  private void LMove(Label o, int left, int top){
    o.Left = left;
    o.Top = top;
  }

  private void GameOver(){
    dspMessage.Left = 150;
    dspMessage.Top = 230;
    dspMessage.Text = "GAME OVER\nPRESS Y REPLAY";
    timer.Stop ();
    canReplay = true;
  }

  private void OnPress(object sender, KeyPressEventArgs e){
    if (e.KeyChar.ToString () == "y" && canReplay) Start();
    if (e.KeyChar.ToString () == "h") btn00.Left -= 20;
    if (e.KeyChar.ToString () == "l") btn00.Left += 20;
    if (e.KeyChar.ToString () == " ") Fire();
    btn00.Left = Math.Max (0, Math.Min(350, btn00.Left));
  }

  private void Fire(){
    Label m = ms.FirstOrDefault (c => c.Top == -1000);
    if (m != null) LMove (m, btn00.Left + 25, 300);
  }
}

public class MainClass
{
  public static void Main(string[] args)
  {
    MainWindow win = new MainWindow ();
    Application.Run (win);
  }
}

ビルドと実行

以上のソースコードをコピペして、「main.cs」というファイルを作成します。

ソースコードと同じデレクトリに入って以下のコマンドを実行します。

$ mcs -r:System.Windows.Forms -r:System.Drawing main.cs

すると「main.exe」というファイルが生成されます。
以下のコマンドでプログラムが実行されます。

$ ./main.exe

遊び方

・キー「y」でゲームを開始します。
・キー「h」で右、キー「l」で左に移動します。
・スペースキーでミサイルを発射します。
・砲台が3回破壊されるとゲームオーバーです。

最後に

以上、c#でしょぼいシューティングゲームを作ってLinux上からビルド&実行してみました。

c#の基本はこの書籍で学びました。

当時、PHPくらいしか触ったことないのに、唐突にc#でアプリを組まなくてはならなくなり、この本に飛びついたもんです。
えらく助かりました。いくら感謝しても足りないくらい。

というわけで、今回はこれにて。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

野村 野村のプロフィール
枕は高いほうがいい。高いほうが本を読みやすいのですよ。なので広めのタオルケットを何重にも折りたたんでその上に枕を載せてその上に頭を載せてたりする。twitterやってます