C#で(簡単な)ブロック崩しゲームを作ってみました。ただしGame Overは実装されていません。
C# でブロック崩しゲームを作りました。ちなみにGame Overにはならない。 pic.twitter.com/mz5BbvfZ2a
— プログラミング素人 (@s51517765) 2019年5月9日
ここで、簡単に技術的な解説をしたいと思います。
プレイヤーを示す青い四角(パドル)は実は”Buttun”です。マウスカーソルに連動して動きます。
MouseMoveイベントで動かします。
マウスポジションはForm1の位置に対して相対的に適宜されるので、Form1の位置をオフセットします。プレイヤーサイズの中央に合わせたいので、その分もオフセットします。
private void Form1_MouseMove(object sender, MouseEventArgs e) { Form1_x = this.Left; //Form1の位置 Cursol_X = MousePosition.X - Form1_x - playerSize_X / 2; buttonPlayer.Left = Cursol_X; }
崩されるブロックも"Buttun"です。
Y座標がブロックのサイズ(30)に入ったら、その部分にブロックが残っているかBlock_flag[block_no]
判断し、残っていれば、フラグを反転し、Visible=false
にします。
if (ball_y < 30) { if (Block_flag[block_no]) { Block_flag[block_no] = false; switch (block_no) { case 0: button0.Visible = false; break; } //省略 } }
ボールは"Label"に●を書いたものです。
ボールの速度ベクトルはX成分、Y成分に分解して考えることで、
labelBall.Left += (int)(ball_Speed * Math.Sin(ball_Direction));
、
labelBall.Top += (int)(ball_Speed * Math.Cos(ball_Direction));
のようにあらわします。これをtimerイベントで更新します。
ボールの進行速度ベクトルは後で説明する、パドルで角度を変更しますが、その角度は0~2πに正規化しておきます。
ボールの位置は int ball_X = labelBall.Left
のように取得できます。
//ボールの進行角度を 0~2*PIに正規化 if (ball_Direction < 0) ball_Direction += Math.PI * 2; else if (ball_Direction > Math.PI * 2) ball_Direction -= Math.PI * 2; in t ball_X = labelBall.Left; //ボールの位置を取得 int ball_Y = labelBall.Top;
壁にボールが当たったときは、入射角=反射角
となるように速度ベクトルを変更します。
パドルに当たった時も基本は同じですが、端っこに当たったときは反射角度を変化するようにしました。
//横壁との反射 if (ball_X < 0 || this.Width - 30 < ball_X) { ball_Direction = 2 * Math.PI - ball_Direction; } //縦壁との反射 if (ball_Y < 0 || this.Height - 60 < ball_Y) { ball_Direction = Math.PI - ball_Direction; }
パドルの当たり判定が結構難しかったです。
なにも考えずに実装すると、一回の打撃のつもりが、Timerで複数回打撃が発生してしまいます。
ですので、「打ち返し中」というフラグを使います。
パドルから一定の距離をボールが離れるまで、「打ち返し」が発生しないようにします。
//パドル当たり判定 if (Math.Abs(playerPosition_Y - ball_Y) < ball_Speed && hitting == false) //高さ方向を限定&&打ち返し中でない { hitting = true; //打ち返し中フラグ } else if (Math.Abs(playerPosition_Y - ball_Y) > ball_Speed && hitting == true) //打ち返し中を抜けたら { hitting = false; }