今天實現一款經典小游戲的實例,貪吃蛇想必大家都有接觸過,當然今天實現的細節沒有那么全面,只能算是簡易版本的小游戲,使用的是Unity中的UGUI,Bug可能有點多,不過大體算是完成了。
大概的原理
整體小游戲的核心其實還蠻簡單的,通俗一點講就是:鍵盤控制2D網格圖片的上下左右移動。我使用的是UGUI中GridLayoutGroup組件添加多個Image實現整體貪吃蛇移動的地圖,其實也就是一個個的網格,網格單元就是圖片,平時的網格圖片都是透明的,貪吃蛇的身體則是其他圖片。
我需要控制的就是貪吃蛇的頭部和身體,使用鍵盤WASD鍵位進行貪吃蛇頭部網格移動,后續身體只需要移動到上一節身體的位置就好了,當然理論可行,實際操作還需要考慮其他的問題。
小游戲的效果圖
效果圖中的小問題咱們先不討論,旨在整體的實現效果,基于此可以進行游戲的完善
關鍵代碼演示
設置地圖中具體坐標的圖片,也就是實時更新屏幕畫面
public void SetSpriteImage(List<SnakeCell> snakeBody)
{
//設置其他格子
SetDefaultSpriteImage();
//設置food
if (gameController.food.foodCoord != Vector2.zero)
imgArray[(int)(gameController.food.foodCoord.x), (int)(gameController.food.foodCoord.y)].sprite = Resources.Load<Sprite>("002/Textures/Food");
try
{
foreach (var item in snakeBody)
{
imgArray[(int)item.Coord.x, (int)item.Coord.y].sprite = Resources.Load<Sprite>("002/Textures/" + item.SpriteName);
}
}
catch (System.Exception)
{
gameController.isLife = false;
Debug.Log("游戲結束");
}
//判斷貪吃蛇 吃食物
if (gameController.snake.head != Vector2.zero && gameController.snake.head == gameController.food.foodCoord)
{
Vector2 direc = (gameController.snake.tail - gameController.snake.head).normalized;
direc = new Vector2(direc.y, direc.x);
if (Vector2.Dot(Vector2.up, direc) == 0)
{
if (gameController.snake.direction == Snake.Direction.Left)
{
gameController.snake.AddSnakeBody(new Vector2(gameController.snake.tail.x, gameController.snake.tail.y + 1));
}
else if(gameController.snake.direction == Snake.Direction.Right)
{
gameController.snake.AddSnakeBody(new Vector2(gameController.snake.tail.x, gameController.snake.tail.y - 1));
}
}else if(Vector2.Dot(Vector2.up, direc) == 1)
{
gameController.snake.AddSnakeBody(new Vector2(gameController.snake.tail.x + 1, gameController.snake.tail.y));
}
else if(Vector2.Dot(Vector2.up, direc) == -1)
{
gameController.snake.AddSnakeBody(new Vector2(gameController.snake.tail.x - 1, gameController.snake.tail.y));
}
else if (Vector2.Dot(Vector2.up, direc) < 0)
{
if(gameController.snake.tail.y < gameController.snake.head.y)
{
gameController.snake.AddSnakeBody(new Vector2(gameController.snake.tail.x, gameController.snake.tail.y - 1));
}
else
{
gameController.snake.AddSnakeBody(new Vector2(gameController.snake.tail.x, gameController.snake.tail.y + 1));
}
}
else if (Vector2.Dot(Vector2.up, direc) > 0)
{
if (gameController.snake.tail.y < gameController.snake.head.y)
{
gameController.snake.AddSnakeBody(new Vector2(gameController.snake.tail.x, gameController.snake.tail.y - 1));
}
else
{
gameController.snake.AddSnakeBody(new Vector2(gameController.snake.tail.x, gameController.snake.tail.y + 1));
}
}
gameController.food.CreateFood(gameController);
}
}
代碼解析
這段代碼里面涉及到三種圖片的刷新,也就是不同標記的屬性圖片對網格的賦值。
首先需要進行的是普通網格圖片的賦值,這里呢沒有給出具體的方法實現,但其實內部就是將整體網格遍歷一遍進行透明圖片的賦值。
然后刷新的圖片就是我們貪吃蛇的食物,這里呢就是紅色方塊,食物的生成位置其實不是完全隨機的,生成的位置必須是處于地圖網格中且必須不能在貪吃蛇身體進行食物的生成,每次食物一旦被貪吃蛇吃掉就會觸發食物的再次生成
最后我們需要考慮的是貪吃蛇吃掉食物之后身體的延長問題,其實有人會覺得身體延長就直接在貪吃蛇尾部進行網格圖片的替換就成了,但是這里就存在一個問題,就是尾部身體延長的方向位置怎么擺放。由效果圖可知,在貪吃蛇進行身體移動的時候尾部的延伸方向其實是存在多種情況的。
在代碼中的體現就是八個方向的判斷來決定尾部身體如何生成,具體的判斷依據就是貪吃蛇頭部和尾部形成的向量與Y軸坐標的點積的值,再根據當前貪吃蛇移動的方向來生成貪吃蛇的身體。(具體以代碼為主)
由于編碼秉承面向對象的原則,所以當前代碼中可能存在多個對象并未給出說明,具體可以查看源碼。
代碼地址
具體代碼我已經上傳Github,看這里
目前代碼上可能存在蠻多的問題,游戲性上也是不夠,但畢竟只是個小游戲,我沒打算做得有多好,簡簡單單實現功能就成。
總結
以前動手寫代碼還是缺點腦子,寫到哪里算哪里,完全沒考慮對象封裝、游戲框架這種東西,代碼不一定有多么實用的功能,但至少能看的明白又舒服,減耦合才是王道!