【程式設計-C#】打磚塊遊戲 – 動作

【程式設計-C#】打磚塊遊戲 – 動作

【程式設計-C#】打磚塊遊戲 – 動作

(到上一篇【程式設計】打磚塊遊戲 – 處理物件及畫面美工)

打磚塊遊戲設計資源 (請按下面圖片):

接下來,在這個教學裏,我們要實現底下遊戲動作: 打磚塊專案檔20180522

  1. 球的移動及碰到邊界的處理
  2. 處理球拍的移動 (鍵盤 + 滑鼠)
  3. 球拍擊中球的判斷及處理
  4. 球擊中磚塊的判斷及處理
  5. 遊戲結束條件:1.球掉出下邊界;2.按ESC鍵
  6. 進入到下一關:擊中全部磚塊,所有磚塊消失。(你會怎麼做?)

首先,我們所有的動作皆透過計時器物件來實現,將計時器物件拖拉至程式主畫面,設定interval,依照人類視覺暫留特性,每秒只要高於16個影像,看起來的東西就會覺得是連貫的,電影的FPS為24,遊戲則要更高,至少30以上,所以,我們的計時器的interval  = 1 / 40  * 1000 =  25

一、球的移動及碰到邊界的處理 BrickBreakout – 2 – 1

程式一開始先宣告:

int X_Inc = 5, Y_Inc = 5;
// 水平移動增量 X_Inc (正:往右邊,負:往左邊)
// 垂直移動增量 Y_Inc(正:往下邊,負:往上面)

計時器的Tick事件:

private void timer1_Tick(object sender, EventArgs e)
{
    ball.Left += Y_Inc; //水平
    ball.Top += X_Inc; //垂直

    //邊界碰撞
    if (ball.Left < 0 || ball.Left > this.Bounds.Width) Y_Inc = -Y_Inc; //左右邊界
    if (ball.Top > this.Bounds.Height || ball.Top < 0) X_Inc = -X_Inc; //上下邊界
}

二、處理球拍的移動 (鍵盤 + 滑鼠)

在timer1的Tick事件中加入:

private void timer1_Tick(object sender, EventArgs e)
{
    //球的移動處理
    ball.Left += Y_Inc;
    ball.Top += X_Inc;

    //球的邊界碰撞
    if (ball.Left < 0 || ball.Left > this.Bounds.Width) Y_Inc = -Y_Inc; //左右邊界
    if (ball.Top > this.Bounds.Height || ball.Top < 0) X_Inc = -X_Inc; //上下邊界

    //球拍的移動
    if (Cursor.Position.X >= (this.Bounds.Width - racket.Width))//如果游標在右邊界處 
        racket.Left = this.Bounds.Width - racket.Width;//減去 球拍的水平位置,否則的話,球拍會在視窗 
    else racket.Left = Cursor.Position.X; //球拍的水平位置 = 游標的水平位置

}

除了使用滑鼠移動游標來移動球拍,我們另外抓取按鍵事件來移動球拍,作法是在Form表單中的KeyDown事件抓取左右按鍵:

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Left) Cursor.Position = new Point(Cursor.Position.X  - 20, Cursor.Position.Y);
    if (e.KeyCode == Keys.Right) Cursor.Position = new Point(Cursor.Position.X + 20, Cursor.Position.Y);
}

三、球拍擊中球的判斷及處理 BrickBreakout – 2-2

判斷球拍是否擊中球,並且在確認擊中之後,球的垂直移動方向由往下變往上。

private void timer1_Tick(object sender, EventArgs e)
{
    //球的邊界碰撞
    if (ball.Left <= 0 || ball.Left >= (this.Bounds.Width - ball.Width)) X_Inc = -X_Inc; //左右邊界
    if (ball.Top >= (this.Bounds.Height - ball.Height) || ball.Top <= 0) Y_Inc = -Y_Inc; //上下邊界

    //球拍是否擊中球:
    if (ball.Left >= racket.Left && ball.Left <= (racket.Left + racket.Width) && ball.Top >= (racket.Top - ball.Height)) Y_Inc = -Y_Inc;

    //球拍的移動
    if (Cursor.Position.X >= (this.Bounds.Width - racket.Width))//如果游標在右邊界處 
        racket.Left = this.Bounds.Width - racket.Width;//減去 球拍的水平位置,否則的話,球拍會在視窗 
    else racket.Left = Cursor.Position.X; //球拍的水平位置 = 游標的水平位置

    //球移動
    ball.Left += X_Inc;
    ball.Top += Y_Inc;
}

四、球擊中磚塊的判斷及處理 BrickBreakout – 2-3

球擊中磚塊的判斷跟球拍是否擊中球作法類似,擊中確認後,我們只需要將該磚塊的Visible設為false,使磚塊看不見就好了!(簡單吧?!)

程式在timer1的Tick事件中加了這個部份的處理:

//一一測試每顆磚塊是否被球擊中
for (int i = 0; i < bricks.GetLength(0); i++)
{
    for (int j = 0; j < bricks.GetLength(1); j++)
    {
        if (bricks[i, j].Visible == true) // 若磚塊是可見的話…,表示磚塊尚未被擊中
        {
            if (ball.Left >= bricks[i, j].Left && ball.Left <= (bricks[i, j].Left + bricks[i, j].Width) && ball.Top <= (bricks[i, j].Top + bricks[i, j].Height))
            {
                Y_Inc = -Y_Inc;
                bricks[i, j].Visible = false; //判定擊中後,球的垂直移動方向改變,並將磚塊的Visible屬性設false,使其看不見
                goto HitBrickExit; //一旦擊中,就不用測試其他的磚塊…,跳離這個測試以節省時間
            }
        }
    }
}
HitBrickExit:

另外,再加上球掉出下邊界外的處理:

//球掉到下邊界外,也就是球拍沒擊中球…,遊戲結束
if (ball.Top >= (this.Bounds.Height - ball.Height))
{
    timer1.Enabled = false; //中止計時器1
    lblGameOver.Visible = true; //顯示出遊戲結束訊息
}

再加上幾個按鍵的處理:

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Left) Cursor.Position = new Point(Cursor.Position.X - 20, Cursor.Position.Y);
    if (e.KeyCode == Keys.Right) Cursor.Position = new Point(Cursor.Position.X + 20, Cursor.Position.Y);
    if (e.KeyCode == Keys.Escape) this.Close(); //按Esc離開遊戲
    if (e.KeyCode == Keys.F1) //重新開始遊戲
    {
        ball.Left = (this.Bounds.Width - ball.Width) / 2; //球位置,置於視窗中心
        ball.Top = (this.Bounds.Height - ball.Height) / 2;
        timer1.Enabled = true; //重新啟動計時器1
        lblGameOver.Visible = false; //遊戲訊息隱藏
        place_bricsk(); //重新排列所有的磚塊
    }
}

遊戲錄影:

音效的處理請參考下一篇:【程式設計】打磚塊遊戲 – 播放背景音樂與音效 (同時)

問題、意見、遊戲改進提議等歡迎在文章下面的迴響交流。謝謝。