8、生成新的單節蛇身
咱們這裏先說說遊戲小原理好了,遊戲運行後,經過計時器事件不斷生成新的單節蛇身類SnakeNode,添加到List中的0位置,原來的蛇頭變成了第二節。該節新蛇頭的座標經過蛇頭前進方向Direct進行判斷,即若是原蛇頭往左運行,則新蛇頭在原蛇頭位置的左一格生成,其餘方向以此類推。最後將該節添加到SnakeNodes列表中,並將相應圖形添加到遊戲區。node
private void GenNewSnakeNode() { SnakeNode snakeNode = null; switch (Direct) { case Direction.UP: snakeNode = new SnakeNode(new Point(SnakeNodes[SnakeHead]._pos.X, SnakeNodes[SnakeHead]._pos.Y - 1)); break; case Direction.DOWN: snakeNode = new SnakeNode(new Point(SnakeNodes[SnakeHead]._pos.X, SnakeNodes[SnakeHead]._pos.Y + 1)); break; case Direction.LEFT: snakeNode = new SnakeNode(new Point(SnakeNodes[SnakeHead]._pos.X - 1, SnakeNodes[SnakeHead]._pos.Y)); break; case Direction.RIGHT: snakeNode = new SnakeNode(new Point(SnakeNodes[SnakeHead]._pos.X + 1, SnakeNodes[SnakeHead]._pos.Y)); break; } if (snakeNode != null) { SnakeNodes.Insert(0, snakeNode); myCanvas.Children.Add(SnakeNodes[0]._rect); } }
9、隨機水果位置
注意該新位置不得與蛇身任何一節重疊,若是重疊則另外生成新位置,直到成功爲止。dom
private Point SetFruitToRandomPos() { bool flag = true; Point pos = new Point(); while (flag) { flag = false; pos = new Point(rnd.Next(0, CellWidth - 1), rnd.Next(0, CellHeight - 1)); foreach (var node in SnakeNodes) { if (pos.X == node._pos.X && pos.Y == node._pos.Y) { flag = true; break; } } } return pos; }
10、碰撞檢測(蛇頭與水果)
由於只有蛇頭會最早觸碰到水果,因此只需判斷蛇頭座標與水果座標是否相同便可。若是撞到水果,則將水果隨機生成新位置;若是沒有碰到,則刪除蛇尾一節(由於以後會經過計時器會生成新一節蛇頭,這樣就會保存蛇身長度,感受位置前進了一格)。ui
private void CheckCollision() { if (SnakeNodes[SnakeHead]._pos.X == fruit._pos.X && SnakeNodes[SnakeHead]._pos.Y == fruit._pos.Y) { fruit.SetPostion(SetFruitToRandomPos()); } else { if (myCanvas.Children.Contains(SnakeNodes[SnakeNodes.Count - 1]._rect)) myCanvas.Children.Remove(SnakeNodes[SnakeNodes.Count - 1]._rect); SnakeNodes.RemoveAt(SnakeNodes.Count - 1); } }
11、判斷是否遊戲結束
很簡單,看看蛇頭是否觸碰遊戲區四邊或蛇身的任何一節,若是是則返回true。
注意蛇身循環是從1開始的,若是從0開始你知道會出現什麼狀況。spa
private bool IsGameOver() { if (SnakeNodes[SnakeHead]._pos.X == -1 || SnakeNodes[SnakeHead]._pos.X == CellWidth || SnakeNodes[SnakeHead]._pos.Y == -1 || SnakeNodes[SnakeHead]._pos.Y == CellHeight) { return true; } foreach (var node in SnakeNodes) { if (node == SnakeNodes[SnakeHead]) continue; if (node._pos.X == SnakeNodes[SnakeHead]._pos.X && node._pos.Y == SnakeNodes[SnakeHead]._pos.Y) { return true; } } return false; }
十3、刪除遊戲區的全部蛇身節
這個會在從新開始遊戲時使用到:code
private void RemoveSnakeNodeAll() { for (int i = 0; i < SnakeNodes.Count; i++) { if (myCanvas.Children.Contains(SnakeNodes[i]._rect)) { myCanvas.Children.Remove(SnakeNodes[i]._rect); } } }
順便再來一發刪除遊戲區的水果:blog
private void RemoveFruit() { if (fruit == null) { return; } if (myCanvas.Children.Contains(fruit._ellipse)) { myCanvas.Children.Remove(fruit._ellipse); } }
十4、按鍵操做
經過方向鍵,設置Direct值便可。遊戲
private void MyCanvas_PreviewKeyDown(object sender, KeyEventArgs e) { switch (e.Key) { case Key.Left: if (Direct != Direction.RIGHT) { Direct = Direction.LEFT; } break; case Key.Right: if (Direct != Direction.LEFT) { Direct = Direction.RIGHT; } break; case Key.Up: if (Direct != Direction.DOWN) { Direct = Direction.UP; } break; case Key.Down: if (Direct != Direction.UP) { Direct = Direction.DOWN; } break; case Key.Escape: Application.Current.Shutdown(); break; case Key.Space: if (CurrGameState == GameState.NONE) return; if (CurrGameState == GameState.PAUSE) { CurrGameState = GameState.GAMEING; timer.Start(); MenuControl_Pause.Header = "暫停"; } else if (CurrGameState == GameState.GAMEING) { CurrGameState = GameState.PAUSE; timer.Stop(); MenuControl_Pause.Header = "繼續"; } break; } }
十4、定義開始遊戲方法
先刪除界面中的蛇身和水果(保留底部暗格),隨機位置生成水果和三節蛇身。事件
private void StartGame() { RemoveSnakeNodeAll(); RemoveFruit(); int startX = rnd.Next(5, CellWidth - 6); int startY = rnd.Next(5, CellHeight - 6); Direct = Direction.RIGHT; fruit = new Fruit(SetFruitToRandomPos(), myCanvas); SnakeNodes = new List<SnakeNode>(); SnakeNodes.Add(new SnakeNode(new Point(startX, startY))); GenNewSnakeNode(); GenNewSnakeNode(); }
十5、開始遊戲菜單ip
調用StartGame()方法,並設定計時器開始。it
private void MenuFile_NewGame_Click(object sender, RoutedEventArgs e) { StartGame(); timer.Start(); CurrGameState = GameState.GAMEING; MenuControl_Pause.Header = "暫停"; }
十6、暫停與繼續
直接上代碼,沒有要說的了。
private void MenuControl_Pause_Click(object sender, RoutedEventArgs e) { if (CurrGameState == GameState.GAMEING) { CurrGameState = GameState.PAUSE; timer.Stop(); MenuControl_Pause.Header = "繼續"; } else if (CurrGameState == GameState.PAUSE) { CurrGameState = GameState.GAMEING; timer.Start(); MenuControl_Pause.Header = "暫停"; } }
十7、退出遊戲
private void MenuFile_Exit_Click(object sender, RoutedEventArgs e) { Application.Current.Shutdown(); }
十8、其餘菜單功能
本身實現好了
private void MenuHelp_About_Click(object sender, RoutedEventArgs e) { }