(到上一篇【程式設計】打磚塊遊戲 – 處理物件及畫面美工)
打磚塊遊戲設計資源 (請按下面圖片):
接下來,在這個教學裏,我們要實現底下遊戲動作: 打磚塊專案檔20180522
- 球的移動及碰到邊界的處理
- 處理球拍的移動 (鍵盤 + 滑鼠)
- 球拍擊中球的判斷及處理
- 球擊中磚塊的判斷及處理
- 遊戲結束條件:1.球掉出下邊界;2.按ESC鍵
- 進入到下一關:擊中全部磚塊,所有磚塊消失。(你會怎麼做?)
首先,我們所有的動作皆透過計時器物件來實現,將計時器物件拖拉至程式主畫面,設定interval,依照人類視覺暫留特性,每秒只要高於16個影像,看起來的東西就會覺得是連貫的,電影的FPS為24,遊戲則要更高,至少30以上,所以,我們的計時器的interval = 1 / 40 * 1000 = 25
程式一開始先宣告:
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);
}
判斷球拍是否擊中球,並且在確認擊中之後,球的垂直移動方向由往下變往上。
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;
}
球擊中磚塊的判斷跟球拍是否擊中球作法類似,擊中確認後,我們只需要將該磚塊的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(); //重新排列所有的磚塊
}
}
遊戲錄影:
音效的處理請參考下一篇:【程式設計】打磚塊遊戲 – 播放背景音樂與音效 (同時)。
問題、意見、遊戲改進提議等歡迎在文章下面的迴響交流。謝謝。