東京工芸大学 工学部  電子機械学科 2年 後期 

応用プログラミング 第12回
 2017.12.12
藤木 文彦

http://fujiki.tv/t-kougei/ouyouprog/
fujiki.kougei@gmail.com 
 ■ 1   ■ 2   ■ 3   ■ 4  ■5   ■ 6         ■ 9   ■ 10  ■ 11  ■ 12          ■ 00

インデックスに戻る



 今日は、ゲームを作ります。

 簡単なシューティングゲームですが、やらなければならないことを考えてみると、たくさんあります。
 順を追って考えていきましょう。


キーボードでの砲台の移動
(キー入力のあった時だけ動く方法)
(タイマーで自動的に動く)

 たまの発射(スペース)
  と軌跡(タイマー)

敵の自動発生
(1つだけ)
(複数)

 玉と敵の衝突判定

 相手が球を打ってくる。
 相手の球と自分の衝突判定

 得点表示、終了、再プレイ



 1.ゲームの作成1


 プロジェクト名: Project1201
 csファイル名:  Game1

(今日は同じプロジェクトのまま、途中で、CSファイルの名前だけ変えて保存、メールに添付して提出してもらう形式とします。)

 まずこんな画面を作ってください。




その後、次のようにプログラムします。
なお、このあと使う部分もあらかじめ示しておきますが、コメントアウト( // )してありますから、この部分は入力しなくても動きます。(後で入れます。)





namespace Project1201
{
public partial class Form1 : Form
{
// ここから6行は、ボタンを押すとかと関係なく、直接に入力する。
Point jibun = new Point();
// Point[] tama = new Point[10];
const int tate0 = 50;
const int yoko0 = 50;
Font font1 = new Font("MS UI Gothic", 30);
Brush brush1 = new SolidBrush(Color.Black);

public Form1()
{
InitializeComponent();

// この部分は、単にプログラムとして書く。
pictureBox1.Width = 400;
pictureBox1.Height = 300;
}

private void button1_Click(object sender, EventArgs e)
{
Graphics g = pictureBox1.CreateGraphics();

int yoko = new int();
int tate = new int();
yoko = pictureBox1.Width;
tate = pictureBox1.Height;
jibun.X = yoko / 2;
jibun.Y = tate - tate0;
textBox1.Text = jibun.X.ToString();
textBox2.Text = jibun.Y.ToString();

g.DrawString("凸", font1, brush1, jibun.X, jibun.Y); 
}

private void button2_Click(object sender, EventArgs e)
{
Application.Exit();
}

private void button3_Click(object sender, EventArgs e)
{
//クリアボタンを押したときの処理
Graphics g = pictureBox1.CreateGraphics();
Color bgcolor1 = pictureBox1.BackColor;
g.Clear(bgcolor1);
}

記号の読み方

凸 (とつ)
↑ (うえ)


「スタート」を押すと、こんなふうになるはずです。
なお、青枠の部分(pictureBox1)の大きさが、最初に設定したのと、少し違っていることに気がついたでしょうか。これは、プログラム中で、幅と高さを再設定したためで、そのため、もともとの自分の設定画面の大きさが違うと画面からはみ出したりするかもしれません。あとで、大きさを調整しましょう。


 【演習問題1】 


【メール1】ここで、CSファイルを " Project1201.cs " という名前で保存し、メールに添付し、タイトルを " Project1201 " として送りなさい。
【提出物1】 上記のような画像ファイルを表示した画面のスクリーンショットをプリントして提出物1としなさい。



 2.ゲームの作成2

 キーを押したら、砲台(凸)の位置を変えたいので、次のような部分を追加します。

このとき、あらかじめ2か所の設定が必要です。

まず、ウインドウ全体の枠が選択されている状態(Form1)にしてください。(タイトルバーの名前は Game1 にしても、プロパティの(Name)が Form1 のままなので、 Form1 になります。ここを変更しても構いません。)
ピクチャーやテキストの画面が選択されて「いない」ことを確認の上、

KeyPreview  を True にします。




 次に、プロパティを、「イベント」(雷マーク)に変えて、次のように、"KeyPress" (キーが押されたら)を設定します。ダブルクリックすると、プログラム入力状態になるので、次のように入力します。

 はじめに "KeyPress" を選んだ時には、何も表示されないので、以下のような文字をどうやって選択するのかわからないかもしれませんが、ダブルクリックすると、 "Form1_KeyPress" が表示されて、入力ウインドウに移ると思うので、下のように入力します。






  private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
Graphics g = pictureBox1.CreateGraphics();
// Brush eraseBrush = new SolidBrush(pictureBox1.BackColor);

// g.DrawString("凸", font1,eraseBrush, jibun.X, jibun.Y);

Char c = e.KeyChar;
String s = String.Format("Char={0}", e.KeyChar);
textBox3.Text = s;
if (c == 'z')
{
jibun.X -= 20;
}
else if (c == 'x')
{
jibun.X += 20;
}
textBox1.Text = jibun.X.ToString();
textBox2.Text = jibun.Y.ToString();

g.DrawString("凸", font1, brush1, jibun.X, jibun.Y);
}



 実行して、キーの、 ”z”、”x”を押すと砲台が動きますが、前の砲台が消されずに残っていますので、これを消さないといけませんね。その対応については、次に説明します。





 【演習問題2】 

【メール2】ここで、CSファイルを " Project1202.cs " という名前で保存し、メールに添付し、タイトルを " Project1202 " として送りなさい。
【提出物2】 上記のような画像ファイルを表示した画面のスクリーンショットをプリントして提出物2としなさい。



 3.ゲームの作成3

プロジェクトは、連続したままプログラムを追加していきます。


 砲台が動いた時に、前の表示を消すようにするには、プログラムを次のように変更します。
(前のプログラムで、コメントアウトしていた2行のコメント印( // )を外すだけです。)






 なぜか画面上に残像が残るのですが、これはとりあえず無視します。(後で解決します。)
 それ以外にもこのプログラムには重大な欠陥があります。

 何でしょう?


 
キーを押し続けると、砲台が画面の外に出てしまいます。(座標表示を見るとわかります。下図のように値がマイナスになっていたら変ですよね。)






 画面からはみ出さないようにするには、あらかじめ計算結果が枠からはみ出さないかどうか確認して、範囲内であれば移動するようにします。
 プログラムの一部を次のように変更します。

 左に枠をはみ出す座標になるかどうかを確認してから、はみ出さないならば、実際に座標を移します。
次のようにします。
if (jibun.X - 20 >= 0)
{
jibun.X -= 20;
}

 右にはみ出さないようにするには、次のようにします。

if (jibun.X + 20 < pictureBox1.Width - 50)
{
jibun.X += 20;
}



実行結果は特に掲げる必要はないでしょう。

上記のような簡単な場合はいいのですが、複雑な計算の必要な場合は、一度計算結果を別の変数にいれ、それが、範囲からはみ出さないかどうかを確認してから、代入する方法をとります。


 【演習問題3】 


【メール3】ここで、CSファイルを " Project1203.cs " という名前で保存し、メールに添付し、タイトルを " Project1203 " として送りなさい。
【提出物3】 上記のような画像ファイルを表示した画面のスクリーンショットをプリントして提出物3としなさい。



 4.ゲームの作成4


 スペースを打ったら、弾が出るようにしましょう。
 前のプログラムに、「スペースキーの検出」と「弾の場所の座標設定」「弾の描画」を入れます。
 しかし、これだけだと、弾が一度書かれるとそのままで、さらに、動いて打つと増えてしまいます。
 直すところは、あとで書きますので、まずは、次のプログラムを参照して入力してみましょう。

 なお、将来的に弾が10個まで出せるように、弾の変数は、配列として、 0〜9までを使えるように準備しておきますが、当面1つだけ(配列添え字0だけ)を使います。

 
このプログラムにはそれ以外にも重大な問題があるのですが、考える順番と陥りやすいミスの解説のために、問題のあるバージョンをまず、制作します。

(発射後、砲台の位置が最初の場所に戻ってしまいます。)





 プログラムに次のような部分を付け加えます。これによって、左右移動だけでなく、スペスキーで弾が出ます。(まだ球は動きません。)


// int i = 0;
のコメントを外します。



以下の C == ' '
に関する処理を付け加えます。




  else if (c == ' ')
{
// 弾を発射
i = 0;
tama[i].X = jibun.X;
tama[i].Y = jibun.Y - 20;
}

i = 0;
if (tama[i].Y != 0)
{
g.DrawString("↑", font1, brush1, tama[i].X, tama[i].Y);
}


 【演習問題4】 


【メール4】ここで、CSファイルを " Project1204.cs " という名前で保存し、メールに添付し、タイトルを " Project1204 " として送りなさい。
【提出物4】 上記のような画像ファイルを表示した画面のスクリーンショットをプリントして提出物4としなさい。

 5.ゲームの作成5 スペースキーの副作用の解決



 上のプログラムでは、スペースキーを押すと、何故か砲台の位置が、元の位置に戻ってしまいました。
 これはたまの発射をスペースキーでなく、別のキー(例えば "n" とか) にすると、解決します。しかし、できれば、スペースキーを使いたいですよね。
 なぜ、スペースキーで、砲台が元の位置に移動してしまうのかというと、Windows では、スペースキーには特別な役割があり、Microsoft のサイトに、「Space キー、Enter キー、Esc キー。Space キーは入力フォーカスのあるコントロールをアクティブ化するのに対し、Enter キーは既定のボタンをアクティブ化します。Esc キーを押すと、ウィンドウが取り消されるか、閉じられます。」と記されています。
 要するに、ボタンを押したのと同じ働きをする、ということのようです。このプログラムの場合は、「スタート」ボタンを押したのと同じことになるので、砲台がスタート位置に戻ってしまうのです。

 「スタートボタン」が、「マウスでクリックした場合」だけ動作し、「スペースキーを押したとき」には、反応しないようにしたいですよね。

 そのためには、スタートボタンを押した時の動作の記述を次のように変えます。

 まず、スタートボタンがマウスでクリックされたときの動作を記述するために次のように選択していきます。




 " MouseClick" をダブルクリックすると、次のようなプログラム画面に変わります。




 ここに、スタートボタンを押した時の動作を記述したいのですが、内容は、前に作成したボタンを押した時の動作と同じなので、その部分をコピーして、挿入します。







 このあと、
もともとのプログラム部分は、削除します。
 ただし、次の図のように、
前後の部分は消してはいけません。この部分を消すと、「ボタンをクリックした時の動作が書いてあったはずなのに、無くなっているのはおかしい!」ということで、エラーとなり、デザイン画面に戻れなくなります。
 間違って消してしまったときは、下の記述を参考に、プログラムを復活させてください。



 これを実行してみると、次のように、砲台は元の位置に戻らずに次々と球を発射できますが、まだおかしいことがいくつかありますね。




 【演習問題5】 


【メール5】ここで、CSファイルを " Project1205.cs " という名前で保存し、メールに添付し、タイトルを " Project1205 " として送りなさい。
【提出物5】 上記のような画像ファイルを表示した画面のスクリーンショットをプリントして提出物5としなさい。


 6.ゲームの作成6 画面を毎回書き直す:自分でメソッドを作る


 今、球は1つだけしか打ったことになっていないはずです。
弾が動いていく部分はまだ作っていないから動かないのは仕方ないのですが、それにしてもいくつも残ったままになっているのは変ですね。
 それから、砲台の跡がうっすら残るのも何か嫌です。(本当は完全に消えるはずなのですが、消えない理由がよくわかりません。)

 そこで、次のように考えて、プログラムを作り直します。

 放題を移動させることになったら、画面を一旦消して、移動後に書き直す、という作業をすることにします。

 つまり、

 z、xキーが押された
 −>一旦画面を消去してから、
   新しい位置に砲台を描く
   弾の数が0でなければ、弾を描く

という操作をしますが、これに関しては、独自の処理部分を「メソッド(手続きあるいは関数)」として作成し、何か変化があったら(キーが押されたり、今後予定する、タイマでの更新があったとき)に呼ばれるようにします。

プログラム中に、次のようなメソッドを新しく付け加えます。
これは、今まで、自動生成されていた、

private void button1_click( )

のような部分と同じレベルのところに記述します。




  //自分で作るメソッド(関数)
private void rewrite()
{
Graphics g = pictureBox1.CreateGraphics();

Color bgcolor1 = pictureBox1.BackColor;
g.Clear(bgcolor1);

g.DrawString("凸", font1, brush1, jibun.X, jibun.Y);
if (tamanum > 0)
for (int i = 1; i <= tamanum; i++)
{
if(tama[i].Y>0)
g.DrawString("↑", font1, brush1, tama[i].X, tama[i].Y);
}
}


 これを呼び出して使用するために、今までのプログラムのところどころ変数名を変えたり、記述をコメントアウトして別のプログラムを付け加えたりする必要があります。

以下のプログラムを見て、どこを変えたのか、慎重に変更していってください。
(変数名とかいろいろ変わっています。)


(色付き太字部分が、変更のあった部分、コメントアウトされたり、変数名が変わったり、付け加えられたりしている。)

  public partial class Form1 : Form
{
// ここから6行は、ボタンを押すとかと関係なく、直接に入力する。
Point jibun = new Point();

Point[] tama = new Point[10];
int tamamax = 10;
int tamanum = 0;


const int tate0 = 50;
const int yoko0 = 50;
Font font1 = new Font("MS UI Gothic", 30);
Brush brush1 = new SolidBrush(Color.Black);

public Form1()
{
InitializeComponent();

// この部分は、単にプログラムとして書く。
pictureBox1.Width = 400;
pictureBox1.Height = 300;
}

private void button1_Click(object sender, EventArgs e)
{

}

private void button2_Click(object sender, EventArgs e)
{
Application.Exit();
}

private void button3_Click(object sender, EventArgs e)
{
//クリアボタンを押したときの処理
Graphics g = pictureBox1.CreateGraphics();
Color bgcolor1 = pictureBox1.BackColor;
g.Clear(bgcolor1);
}

private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
Graphics g = pictureBox1.CreateGraphics();
Brush eraseBrush = new SolidBrush(pictureBox1.BackColor);

//g.DrawString("凸", font1,eraseBrush, jibun.X, jibun.Y);

Char c = e.KeyChar;
String s = String.Format("Char={0}", e.KeyChar);
textBox3.Text = s;
if (c == 'z')
{
if (jibun.X - 20 >= 0)
{
jibun.X -= 20;
}
rewrite();
}
else if (c == 'x')
{
if (jibun.X + 20 < pictureBox1.Width - 50)
{
jibun.X += 20;
}
rewrite();
}
else if (c == ' ')
{
// 弾を発射
tamanum=1;
tama[tamanum].X = jibun.X;
tama[tamanum].Y = jibun.Y - 20;
rewrite();

}

textBox1.Text = jibun.X.ToString();
textBox2.Text = jibun.Y.ToString();

//g.DrawString("凸", font1, brush1, jibun.X, jibun.Y);
}


private void button1_MouseClick(object sender, MouseEventArgs e)
{
Graphics g = pictureBox1.CreateGraphics();

int yoko = new int();
int tate = new int();
yoko = pictureBox1.Width;
tate = pictureBox1.Height;
jibun.X = yoko / 2;
jibun.Y = tate - tate0;
textBox1.Text = jibun.X.ToString();
textBox2.Text = jibun.Y.ToString();

//g.DrawString("凸", font1, brush1, jibun.X, jibun.Y); 
rewrite();
}


//自分で作るメソッド(関数)
private void rewrite()
{
Graphics g = pictureBox1.CreateGraphics();

Color bgcolor1 = pictureBox1.BackColor;
g.Clear(bgcolor1);

g.DrawString("凸", font1, brush1, jibun.X, jibun.Y);
if (tamanum > 0)
for (int i = 1; i <= tamanum; i++)
{
if(tama[i].Y>0)
g.DrawString("↑", font1, brush1, tama[i].X, tama[i].Y);
}

}


   


実行すると次のようになります。



砲台が移動しても、撃った弾が残るように見えますが、この弾はこのあと、上方に向かって飛んでいくように移動させますので、とりあえずこのまま置いておきます。新しく撃つと、その位置に表示されます。
移動したあとの残像が消えていますね。

 【演習問題6】 



【メール6】ここで、CSファイルを " Project1206.cs " という名前で保存し、メールに添付し、タイトルを " Project1206 " として送りなさい。
【提出物6】 上記のような画像ファイルを表示した画面のスクリーンショットをプリントして提出物6としなさい。


 7.ゲームの作成7 タイマーの使用

 弾が自動的に動いていくようにするためにタイマーを使います。
 タイマーのセットは、以前にやりましたね。(第10回の 4番の問題です。)

 弾は多数発射できるようにしますが、とりあえず、一発だけ発射します。
 発射前の弾の Y 座標は 0 のはずです。
 また、発射時に弾の座標を 正の値にセットし、時間が経つごとにその座標を減じていきます。座標が0以下(0かマイナス)になったら、上部に到達したとみなして、弾の座標を 0 にセットすることで、移動を止めます。
 なお、弾の値が 0 でなければ、新しい弾は発射できないようにします。

まずタイマーをセットします。




 timer1 をダブルクリックして、タイマーで呼び出された時のプログラムを作成します。
 次のように入力してください。



  private void timer1_Tick(object sender, EventArgs e)
{
int i = tamanum;
if (tama[i].Y != 0)
{
tama[i].Y -= 20;
if (tama[i].Y <= 0) tama[i].Y = 0;
}
rewrite();

}


ここで実行してみます。
しかし、撃った弾は動きません。なぜでしょう?
 タイマーの基本設定をしていないからです。次のように、最初の部分にタイマーを動かすために必要なプログラムを書きます。




  //タイマーに関する初期設定
Timer timer1 = new Timer();
timer1.Interval = 500;
timer1.Start();
timer1.Tick += new EventHandler(timer1_Tick);



 実行すると、次のように弾が飛んでいきます。



 【演習問題7】 

【メール7】ここで、CSファイルを " Project1207.cs " という名前で保存し、メールに添付し、タイトルを " Project1207 " として送りなさい。
(プロジェクト番号のしたの桁は、前回からの連番になっています。)
【提出物7】 上記のような画像ファイルを表示した画面のスクリーンショットをプリントして提出物1としなさい。



 8.複数の弾の発射


 弾が一発しか出ないのでは、ゲームらしくないので、弾を複数出せるようにします。
 あらかじめそうするために、 tama[i] のように配列で宣言してあったわけです。

 下の画面のようになるようにします。









 プログラムの追加変更箇所は、以下の3箇所(発射、移動、描画)です。以前のプログラムと見比べて変更・追加箇所を入力してください。


まず、スペースキーを撃ったら、弾が発射される部分です。
ここでは、10発発射することにしていますが、それは、 tamamax=10 によって決めていますので、この初期設定を変えると、弾の数が変わります。

ここで、発射されていない弾は、 tama[i].Y == 0 となっているはずなので、tama[i] == 0 となっている i を探し、それに、位置を初期設定することで、発射された状態(位置が0でない状態)にします。

この技法は少し難しいので、何をしているのか、自分でよく考えてください。

なお、 0 になっているものを探して、初期値座標を代入したら、それ以上空いている弾を探す必要はないので、
break;
によって、for 文から脱出します。
これがないと、すべての空いている弾を発射してしまいますので、1回スペースを押すと、全ての弾が発射されたことになります。(見かけ上は、重なって表示されるので、1発しか発射されていないように見える。そのため、これを入れ忘れたバグは発見しにくい。先生も最初気がつかづに悩みました。)

  else if (c == ' ')
{
// 弾を発射
for (int i = 0; i < tamamax; i++)
{
//発射されていない弾番号を探す
if (tama[i].Y == 0)
{
tamanum = i;
tama[tamanum].X = jibun.X;
tama[tamanum].Y = jibun.Y - 20;
//この次の break; がないと、全部一度に発射されてしまうので
// 見かけ上弾が一個になってしまう。
break; // for 文から外に出る
}
}
rewrite();
}

textBox1.Text = jibun.X.ToString();
textBox2.Text = jibun.Y.ToString();


 2つめに書き直すのは、弾を移動させる部分です。これは、タイマーによって呼び出される部分でしたね。



  private void timer1_Tick(object sender, EventArgs e)
{
//int i = tamanum;
//全部の弾について、発射されていれば場所を変更
for (int i = 0; i < tamamax; i++)
{
if (tama[i].Y != 0)
{
tama[i].Y -= 20;
if (tama[i].Y <= 0) tama[i].Y = 0;
}
}
rewrite();

}




 3つめに全体を表示しなおす部分でも、弾を全部描きます。 tama[i].Y != 0 のときに、描きます。( != は、イコールではない、という意味でしたね。)


  private void rewrite()
{
Graphics g = pictureBox1.CreateGraphics();

Color bgcolor1 = pictureBox1.BackColor;
g.Clear(bgcolor1);

g.DrawString("凸", font1, brush1, jibun.X, jibun.Y);
//if (tamanum > 0)
//修正 tamanum -> tanmamax
for (int i = 0; i < tamamax; i++)
{
if(tama[i].Y>0)
g.DrawString("↑", font1, brush1, tama[i].X, tama[i].Y);
}
}




 上では、弾は10発にしましたが、設定を変えると、いくらでも出ます。
 最初の部分を次のようにします。(プログラムの行を入れ替えましたから注意)







 【演習問題8】 


【メール8】ここで、CSファイルを " Project1208.cs " という名前で保存し、メールに添付し、タイトルを " Project1208 " として送りなさい。
(プロジェクト番号のしたの桁は、前回からの連番になっています。)
【提出物8】 上記のような画像ファイルを表示した画面のスクリーンショットをプリントして提出しなさい。




 9.敵をランダムに出現させる

 さて、相手も出現させます。
 出現場所は乱数として、手前に迫ってくるようにします。
 5基を出すことにしますが、連続して出すと一斉に出てくるので、すこし時間を空けて発生させるために、間隔をあけます。(タイマー呼び出し3回に1回出現させます。)

 なお、まだ衝突判定を作ってありませんから、下の図のように、弾がすり抜けます。




 まず敵の座標を入れる配列などを初期設定。



  //敵も入れる
Point[] teki = new Point[5];
Random rnd1 = new Random();
const int tekimax = 5;
const int kankakunum = 3;
int kankaku = 0;
//敵設定ここまで



タイマーで呼び出される場所に敵の出現、及び、敵の位置移動、そして、消滅に関する部分を書き加えます。
ここでも、発生させる敵は、空いている番号を選んで発生させるようにしています。




  //敵の発生
for (int j = 0; j < tekimax; j++)
{
if (teki[j].Y == 0 && kankaku == 0)
{
teki[j].X = rnd1.Next(pictureBox1.Width - 100) + 50;
teki[j].Y = 20;

break;
}
}
kankaku++;
if (kankaku == kankakunum) kankaku = 0;
//敵の移動
for (int j = 0; j < tekimax; j++ )
{
if (teki[j].Y != 0)
{
teki[j].Y += 20;
if (teki[j].Y > pictureBox1.Height - 50) { teki[j].Y = 0; }

}
}

//敵の移動終わり


そして、描画部分にも敵を描く部分を付け加えます。



  //敵を描画
for (int j = 0; j < tekimax; j++)
{
if (teki[j].Y != 0)
{

g.DrawString("▼", font1, brush1, teki[j].X, teki[j].Y);
}

}

 【演習問題9】 


【メール9】ここで、CSファイルを " Project1209.cs " という名前で保存し、メールに添付し、タイトルを " Project1209 " として送りなさい。
(プロジェクト番号のしたの桁は、前回からの連番になっています。)
【提出物9】 上記のような画像ファイルを表示した画面のスクリーンショットをプリントして提出しなさい。


 10.弾と敵の衝突判定

 弾が敵に当たったら、敵が消えるようにします。
 2つの物体のあいだの距離がある値以下になった時に衝突したとみなします。
 ここでは、その距離を xhaba,yhaba とし、
 全部の組み合わせについて計算し、当たったモノについては、敵と弾を消して、星印をタイマー1クロック分のあいだだけ描画します。
 表示するのは、印としますが、1つだけではなく、同時に複数当たる場合もあるので、最大出現数を、敵の数までとします。
 衝突したあとの煙をもう少し長いあいだ表示するほうが、実感がわくのですが、その方法は面倒なので、余裕があったら考えてください。(その場合、煙の数は敵の数より多くなる場合がありえます。)





ここまで出来てきた人なら、どこを変更したらよいのか、大体わかると思いますので、以下にプログラムの編集画面だけ掲げます。プログラムの、ほぼ全部を掲げましたので、参考に自分で入れてください。(コピペするテキストは省略しました。)

※画像は一部分重複するように掲げてあります。















 【演習問題10】 


【メール10】ここで、CSファイルを " Project1210.cs " という名前で保存し、メールに添付し、タイトルを " Project1210 " として送りなさい。
(プロジェクト番号のしたの桁は、前回からの連番になっています。)
【提出物10】 上記のような画像ファイルを表示した画面のスクリーンショットをプリントして提出しなさい。

 11.敵に攻め込まれたら終了

 敵を打ち落とすだけではゲームになりませんから、こちらに敵が攻め込んできたら、やられるようにもしないとなりませんね。
 敵が、一番手前まで攻め込んできたら、ライフを減らし、ライフが0になったらゲームオーバーとすることにします。

 そのためには、
・あらかじめ自分のライフを設定する。(ライフが0になったら終了)
・敵の移動後の座標が画面枠の下近くになったら、攻め込まれたとして、ライフを減らす。
・ライフが0になったら、自分の砲台をやられたマーク(例えば※)にして、キー入力を受付け無いようにする。


 ということを行います。

 そのために、今まで使わなかった life という変数を設定し、その数を使用しましょう。







 まず、初期設定部分に、 life=3
をいれます。



キー入力に関する処理は、 life が0より大きくなければ行わないようにするために、次のように、if 文を挿入します。
この if 文の結びの位置に } を入れるのを忘れないようにしてください。




敵に攻め込まれたら、ライフを減らし、ライフが0になったら、タイマー処理を止めます。



描画部分でも、次のように、ライフの値が0になる前は、普通に砲台を描き、0になったら、”※”を描くようにします。




 【演習問題11】 

【メール11】ここで、CSファイルを " Project1211.cs " という名前で保存し、メールに添付し、タイトルを " Project1211 " として送りなさい。
(プロジェクト番号のしたの桁は、前回からの連番になっています。)
【提出物11】 上記のような画像ファイルを表示した画面のスクリーンショットをプリントして提出しなさい。


 12.あと少し改良(応用:時間がなければやらなくて良い)



スコアが表示されるといいですね。上に用意しておいたラベル部分にスコアを表示させましょう。
敵を打ち落とすたびにスコアが入るようにします。
また、自分のライフも表示しましょう。




敵に弾がぶつかった時に、スコアを加算する部分を、衝突判定に加えます。

実はここのプログラムをしている時に、前のプログラムでの衝突判定に重大なミスがあることがわかりました。実は衝突判定時に、「まだ発射されていないたま同士の間の衝突判定」もなされてしまっていました。そのために、最初の状態では、非常にたくさんの弾と敵が衝突している状態となっていたことが分かりました。
 そこで、衝突判定は、「発射されている弾」「現れている敵」の間だけで行うように、この部分を改良します。
 ミスに気がつかなかったのは、ぶつかった座標が、0、0の点であったために、ぶつかり表示が画面に出力されなかったためと思われます。



スコアの初期化は、ライフの初期化のあとに入れましょう。



煙表示部分のあとに、スコア表示を入れておきます。




スタートボタンを押すと、再度全部クリアして始められるような初期化も入れましょう。


スコア表示の文字を大きくするには、次のようにします。





さらに。

マウスクリックで、スタートしたあと、スペースだけではなく、マウスのクリックでも弾が打てるようにします。
pictureBox1 の上で、マウスをクリックして表示される部分に次のようなプログラムをいれます。



この中身は、実は、スペースキーを押した時のプログラムと全く同じです。

このような部分は、自分でメソッド(関数)を作成し、それをスペースキーを押した場合と、マウスクリックした場合の両方から呼び出すようにしたほうが良いですね。
 次の例を見てください。



スペースを押した時のプログラム部分も、次のように簡略化してしまいましょう。

 【演習問題12】 


【メール12】ここで、CSファイルを " Project1212.cs " という名前で保存し、メールに添付し、タイトルを " Project1212 " として送りなさい。
(プロジェクト番号のしたの桁は、前回からの連番になっています。)
【提出物12】 上記のような画像ファイルを表示した画面のスクリーンショットをプリントして提出しなさい。