【程式設計-C#】打磚塊遊戲 – 動作
(到上一篇【程式設計】打磚塊遊戲 – 處理物件及畫面美工)
打磚塊遊戲設計資源 (請按下面圖片):
接下來,在這個教學裏,我們要實現底下遊戲動作: 打磚塊專案檔20180522
- 球的移動及碰到邊界的處理
- 處理球拍的移動 (鍵盤 + 滑鼠)
- 球拍擊中球的判斷及處理
- 球擊中磚塊的判斷及處理
- 遊戲結束條件:1.球掉出下邊界;2.按ESC鍵
- 進入到下一關:擊中全部磚塊,所有磚塊消失。(你會怎麼做?)
首先,我們所有的動作皆透過計時器物件來實現,將計時器物件拖拉至程式主畫面,設定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(); //重新排列所有的磚塊 } }
遊戲錄影:
音效的處理請參考下一篇:【程式設計】打磚塊遊戲 – 播放背景音樂與音效 (同時)。
問題、意見、遊戲改進提議等歡迎在文章下面的迴響交流。謝謝。