プログラミング素人のはてなブログ

プログラミングも電気回路も専門外の技術屋の末端が勉強したことや作品をアウトプットするブログ。コードに間違いなど見つけられたら、気軽にコメントください。 C#、python3、ラズパイ始めました。

C#でブロック崩しを作った

C#で(簡単な)ブロック崩しゲームを作ってみました。ただしGame Overは実装されていません。

ここで、簡単に技術的な解説をしたいと思います。

f:id:s51517765:20190511173408p:plain
ゲーム画面


プレイヤーを示す青い四角(パドル)は実は”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;
}

github.com