Unity3D初級案例-經典貪喫蛇一

引言:小生今日分享的是經典貪喫蛇案例,特別感謝Siki學院的老師們。
這裏附上原視頻鏈接:http://www.sikiedu.com/my/course/89 可以搭配起來學習哦!
小生會根據自己理解,做一些代碼上的修改!大家也可以有自己的主見!
開發版本:unity 2017.1.1f1
適合人羣:初學Unity者
源文件鏈接請見文末!
開啓學習之旅吧!

效果預覽:
主要實現功能:WASD鍵或上下左右鍵控制蛇移動方向,喫到冰淇淋加分,並且增長蛇身。遊戲提供兩種蛇的樣式可選,而且有兩種有無邊界模式可選。記錄當前得分和歷史最高分。

01 場景搭建

新建2D工程,新建StartScene場景,Game場景設置爲1280*720大小,導入資源
我們使用UGUI製作UI及人物,開始界面效果如下:
Canvas要設置爲Screen Sapce Camera模式
需要注意的是,皮膚和模式分別只能二選一,Toggle Group的Allow Switch off不能勾選
新建主場景MainScene,效果如下:
因爲需要開發一個邊界模式,新建四個對象,放入場景四邊,並添加碰撞體,勾選Is Trigger
注意四面牆分別命名爲Up,Down,Left,Right,新建一個父對象統一管理

02 實現思路

有兩種主要方式可以實現蛇的移動
第一種方式,從蛇尾的最後開始一節開始,依次向前一節蛇身的位置移動
第二種,蛇頭每向前移動一個位置,就將蛇尾的最後一節移動到蛇頭剛纔的位置
我們選擇第一種方式,因爲我們的蛇有兩種顏色相間的蛇身,如果第二種方式,會讓蛇身的顏色混亂

03 開發蛇頭

新建一個Image,命名爲SnackHead,Source Image修改爲蛇頭圖片,長寬設置爲45*45,添加Rigidbody2D和BoxCollider2D組件,勾選Is Trigger,爲其添加一個空的父物體Snack,方便管理蛇頭和以後添加的蛇身
在SnakeHead上掛載腳本SnakeHead.cs
首先實現蛇頭的移動,轉頭,空格鍵加速操作
實現主要思想,InvokeRepeating方法持續間隔一定時間調用控制蛇頭移動的Move方法,然後Update方法監聽按鍵,判斷蛇頭移動的XY增量
並實現蛇頭轉向,利用InvokeRepeating的間隔調用時間來控制蛇頭移動的速度
需要注意根據實際情況設計蛇頭移動步長Step的大小,最好能讓蛇頭在有限範圍內移動整數步

 public float velocity = 0.35f;
    //每一步蛇頭移動距離
    public int step;
    //x軸蛇頭移動增量
    private int x;
    //y軸蛇頭移動增量
    private int y;

  private void Start()
    {
        //初始化,讓蛇頭可以向上移動
        x = 0;
        y = step;
        //InvokeRepeating等待0秒,然後每隔velocity時間調用Move方法
        InvokeRepeating("Move", 0, velocity);
    }

  private void Update()
    {
        //虛擬軸控制移動
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        //Input.GetKeyDown鍵按下瞬間
        if (Input.GetKeyDown(KeyCode.Space))
        {
            //CancelInvoke先取消之前的InvokeRepeating命令
            CancelInvoke();
            //將間隔調用“Move”方法的時間減小,則蛇移動變快
            InvokeRepeating("Move", 0, velocity - 0.2f);
        }
        //Input.GetKeyUp鍵擡起瞬間
        if (Input.GetKeyUp(KeyCode.Space))
        {
            CancelInvoke();
            InvokeRepeating("Move", 0, velocity);
        }
        //如果此時y = -step說明蛇正在向下移動,爲了防止蛇目前在向下移動,突然向上移動,加y != -step判斷,以下同理
        {
            //設置當頭上下左右移動的時候,蛇頭的方向和移動方向一致,以下同理
            //Quaternion代表四元數,identity表示初始旋轉角度,可理解爲new Vector(0,0,0)
            gameObject.transform.localRotation = Quaternion.identity;
            //設置蛇的移動方向,x = 0,y = step說明蛇頭在Y軸向上移動,以下同理
            x = 0;
            y = step;
        }
        if (v < 0 && y != step)
        {
            //Quaternion.Euler將歐拉角轉化爲四元數,需要注意歐拉角要與移動方向匹配
            gameObject.transform.localRotation = Quaternion.Euler(new Vector3(0, 0, 180));
            x = 0;
            y = -step;
        }
        if (h < 0 && x != step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(new Vector3(0, 0, 90));
            x = -step;
            y = 0;
        }
        if (h > 0 && x != -step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(new Vector3(0, 0, -90));
            x = step;
            y = 0;
        }
    }

    void Move()
    {
        //獲取當前蛇頭移動的局部座標
        headPos = gameObject.transform.localPosition;
        //將蛇頭當前的移動位置加上x軸和y軸的移動增量,實現蛇頭的移動
        gameObject.transform.localPosition = new Vector3(headPos.x + x, headPos.y + y, 0);
    }



04 食物生成

開發食物,新建一個Image,命名爲SnackBody,source image設置爲任意的食物圖片,長寬設置爲35*35,添加Box Collider2D,勾選is trigger, 需要注意碰撞器大小設置稍微小一點,防止蛇頭擦肩而過的時候,發生碰撞,標籤設置爲Food,最後設爲預製體。
設置步長step爲30px,計算後得到世界座標中心點到四周的步數,但爲了防止出現食物"卡"在邊緣,如下圖,將步數各減一步
在Canvas下設置一個子物體FoodRoot,掛載腳本FoodCreator.cs
將FoodCreator設置爲單例模式,只需實例化一次,方便調用
我們規定遊戲開始,就生成一個食物,蛇每喫掉一個食物就隨機生成其他食物,並有一定機率生成特殊獎勵
特殊獎勵的預製體和食物製作差不多。

public class FoodCreator : MonoBehaviour
{
    private static FoodCreator instance;
    public static FoodCreator Instance
    {
        get
        {
            return instance;
        }
    }
    public int xMinLimit = 11;
    public int xMaxLimit = 20;
    public int yMinLimit = 11;
    public int yMaxLimit = 11;
    //要和蛇頭移動步長一致
    public int step = 30;
    public GameObject foodPrefabs;
    //設置
    public GameObject rewardPrefabs;
    //保存食物的Sprites
    public Sprite[] foodSprites;
    private Transform foodHolder;

    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
        }
    }

    private void Start()
    {
        foodHolder = GameObject.FindGameObjectWithTag("FoodRoot").transform;
        //遊戲開始時,就生成一個食物
        CreateFood(false);
    }

    public void CreateFood(bool isReward)
    {
        //隨機取得一個食物的下標
        int index = Random.Range(0, foodSprites.Length);
        //實例化food預製體
        GameObject food = Instantiate(foodPrefabs);
        //將食物的image source改爲選中下標的食物
        food.GetComponent<Image>().sprite = foodSprites[index];
        //將food設置爲foodHolder的子物體,false會使得food保持局部座標不變
        food.transform.SetParent(foodHolder, false);
        //隨機取得食物生成位置
        int x = Random.Range(-xMinLimit, xMaxLimit + 1);
        int y = Random.Range(-yMinLimit, yMaxLimit + 1);
        food.transform.localPosition = new Vector3(x * step, y * step, 0);
        //判斷是否生成獎勵
        if (isReward)
        {
            //同理
            GameObject reward = Instantiate(rewardPrefabs);
            reward.transform.SetParent(foodHolder, false);
            x = Random.Range(-xMinLimit, xMaxLimit);
            y = Random.Range(-yMinLimit, yMaxLimit);
            reward.transform.localPosition = new Vector3(x * step, y * step, 0);
        }
    }
}



05 處理蛇身的生成

蛇身SnakeBody的製作和前面類似,tag設置爲Body,設爲預製體
我們使用List<Transform>來存儲蛇身,需要注意引用命名空間using System.Collections.Generic;
在SnakeHead.cs中新增AddBody()方法,然後添加OnTriggerEnter2D()用於觸發檢測,當碰到食物或者獎勵的時候,調用AddBody()方法,實現蛇喫食物增加蛇身的功能
  void AddBody()
    {
        //三元運算符,如果bodyList.Count被2模除則返回0,否則返回1,控制身體奇偶數輪換顏色
        int index = (bodyList.Count % 2 == 0) ? 0 : 1;
        //new Vector3(2000, 2000, 0)先將身體實例化在屏幕外
        GameObject newBody = Instantiate(bodyPrefab, new Vector3(2000, 2000, 0), Quaternion.identity);
        newBody.GetComponent<Image>().sprite = bodySprites[index];
        newBody.transform.SetParent(snackRoot, false);
        //將新生成的蛇身加入到bodyList中
        bodyList.Add(newBody.transform);
    }

 private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("Food"))
        {
            Destroy(collision.gameObject);
            AddBody();
            //(Random.Range(0, 100) < 20) ? true : false 三元運算符 隨機值小於20則返回true,否則false
            FoodCreator.Instance.CreateFood((Random.Range(0, 100) < 20) ? true : false);
        }
        else if (collision.gameObject.CompareTag("Reward"))
        {
            Destroy(collision.gameObject);
            AddBody();
        }
}



06 實現蛇移動

實現方法如圖所示
在SnakeHead類中添加Move方法,使用 List<Transform>記錄蛇尾的位置信息
public List<Transform> bodyList = new List<Transform>();
 void Move()
    {
        //獲取當前蛇頭移動的局部座標
        headPos = gameObject.transform.localPosition;
        //將蛇頭當前的移動位置加上x軸和y軸的移動增量,實現蛇頭的移動
        gameObject.transform.localPosition = new Vector3(headPos.x + x, headPos.y + y, 0);
        
        //剛開始bodyList爲空,防止報空指針
        if (bodyList.Count > 0)
        {
            for (int i = bodyList.Count - 2; i >= 0; i--)
            {
                //將前一節蛇尾的位置賦予後一節
                bodyList[i + 1].localPosition = bodyList[i].localPosition;
            }
            //將原來蛇頭的位置賦予給下標爲0的蛇尾,也就是蛇頭後一節的蛇尾
            bodyList[0].localPosition = headPos;
        }

        //方法二:將蛇尾最後一節移至蛇頭的位置
        //if (bodyList.Count > 0)
        //{
        //bodyList.Last()獲取list最後的元素
        //    bodyList.Last().localPosition = headPos;
        //Insert將元素插入到指定位置
        //    bodyList.Insert(0, bodyList.Last());
        //RemoveAt移除指定下標的元素
        //    bodyList.RemoveAt(bodyList.Count - 1);
        //}
    }




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章