Unity3D_(游戲)貪吃蛇


 

 

Unity制作貪吃蛇小游戲

 

  玩家通過“WASD”控制小蛇上下左右移動,蛇頭撞倒食物,則食物被吃掉,蛇身體長一節,接着又出現食物,等待蛇來吃,如果蛇在移動中撞到牆或身體交叉蛇頭撞倒自己身體游戲結束

  可通過游戲開始前對小蛇皮膚進行選擇

  自由模式下蛇頭可以穿過四周的牆

  使用本地持久化保存與讀取的類——PlayerPrefs類對玩家游戲數據的存儲

 

  PlayerPrefs類存儲位置  傳送門

  Unity聖典  傳送門

  游戲項目已托管到Github上  傳送門

 

 

游戲展示

 

對玩家的游戲數據記錄

   游戲界面存儲玩家最高分以及上一次游戲的分數

 

 

 

游戲換膚

   為玩家可以選擇藍色小蛇或黃色小蛇

 

 

 

游戲模式

  邊界模式下蛇撞到邊界判定游戲結束

  自由模式下蛇碰到邊界時會從另一個邊界線出來

 

 (文字最下邊有游戲腳本源代碼)

 

  

 

 實現過程

 

制作開始場景UI界面

 

  添加一個Canvas作為游戲開始場景並將Canvas下的Render Mode設置為Screen Space—Camera

    1:Screen Space-Overlay:這種模式層級視圖中不需要任何的攝像機,且UI出現在所有攝像機的最前面。
    2:Screen Space-Camera:這種模式需要綁定一個UICamrea,它支持UI前面顯示3D對象和粒子系統。
    3:World Space:這種模式,UI和3d對象完全一樣。
Canvas 三種渲染模式如下

 

(2D游戲常用Screen Space-Camera模式,3D游戲常用Screen Space-Overlay模式)

  

  Canvas Scaler(Script)個人比較喜歡設置UI Scale Mode設置成Scale With Screen Si   根據屏幕尺寸來調整UI的縮放值 

 

  指定渲染攝像機

 

  添加游戲背景及控制面板

 

  使用UGUI制作游戲場景界面

  

  Bg(Image):制作游戲背景界面

       ControlPanel(Panel):制作游戲選項區域

  Title(Text):制作游戲標題

  Go(Image):制作游戲開始圖標

      添加Button控件,制作成按鈕

      添加Outline外邊框和Shadow陰影組件(逼真圖片按鈕)

  Text:"開始"文本

 

  添加十張Image作為游戲背景圖片

 

  食物作為游戲背景太鮮明時,可以把食物的透明度調為150

 

  制作Text文字背景

 

   Mode下添加一個Toggle提供玩家對模式的選擇

(給文字添加Outline給玩家一種朦朧感)

  

  邊界模式下,蛇撞牆后判斷游戲結束

  復制邊界模式Toggle,修改文字為自由模式(自由模式下蛇撞牆后不會判定結束游戲)

  邊界模式和自由模式玩家只能選擇一個

 

  給Mode添加Toggle Group組件

  

 

  將Toggle Group組件綁定給Border和NoBorder

     

 

 

  is on :當前標簽是否勾選

 

  同理添加小蛇皮膚屬性

 

  將選擇小蛇皮膚也設置成Toggle Group

  "黃色小蛇"和"自由模式" is on 去掉勾選

 

 

 

游戲場景UI界面

 

 

  ControlPanel下的按鈕、文本控件

    Msg(Text):玩家選擇游戲模式

    Score(Text):玩家當前得分

    Length(Text):當前蛇自身長度

    Home(Image):返回主頁面按鈕

    Pause(Image):停止游戲按鈕

 

 

給游戲場景添加邊界

 

  Bg下創建兩個GameObject,設置(錨點)GameObject范圍,添加Box Collider 2D作為游戲碰撞器

 

  給小蛇添加活動范圍,添加一個Box Collider 2D碰撞器

  為了將活動范圍標記出來,可以給碰撞其添加一個Image紅色圖片作為圍牆

 

  修改一下碰撞器范圍

 

 

制作貪吃蛇舌頭並讓其移動

 

  添加Image制作舌頭,設置好舌頭大小

 

  創建SnakeHead.cs腳本並綁定到蛇頭部

 

  控制小蛇頭部移動腳本

 void Move()
    {
        headPos = gameObject.transform.localPosition;
        gameObject.transform.localPosition = new Vector3(headPos.x+x,headPos.y+y,headPos.z);
    }

 

  添加鍵盤按鈕事件

    private void Update()
    {
        if (Input.GetKey(KeyCode.W))
        {
            x = 0;y = step;
        }
        if (Input.GetKey(KeyCode.S))
        {
            x = 0;y = -step;
        }
        if (Input.GetKey(KeyCode.A))
        {
            x = -step;y = 0;
        }
        if (Input.GetKey(KeyCode.D))
        {
            x = step;y = 0;
        }
    }

  

  初始時及改變方向時不斷讓小蛇向着一個方向移動

    private void Start()
    {
        //重復調用
        InvokeRepeating("Move",0,velocity);
        x = step;y = 0;
    }

 

  

Invoke() 方法是 Unity3D 的一種委托機制

如: Invoke("Test", 5);   它的意思是:5 秒之后調用 Test() 方法;

使用 Invoke() 方法需要注意 3點:

1 :它應該在 腳本的生命周期里的(Start、Update、OnGUI、FixedUpdate、LateUpdate)中被調用;

2:Invoke(); 不能接受含有參數的方法;

3:在 Time.ScaleTime = 0; 時, Invoke() 無效,因為它不會被調用到

Invoke() 也支持重復調用:InvokeRepeating("Test", 2 , 3); 

這個方法的意思是指:2 秒后調用 Test() 方法,並且之后每隔 3 秒調用一次 Test() 方法

還有兩個重要的方法:

IsInvoking:用來判斷某方法是否被延時,即將執行
CancelInvoke:取消該腳本上的所有延時方法
Unity中Invoke 和 InvokeRepeating的區別

 

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SnakeHead : MonoBehaviour {

    public float velocity=0.35f;
    public int step;
    private int x;
    private int y;
    private Vector3 headPos;

    private void Start()
    {
        //重復調用
        InvokeRepeating("Move",0,velocity);
        x = step;y = 0;
    }

    private void Update()
    {
        if (Input.GetKey(KeyCode.W))
        {
            x = 0;y = step;
        }
        if (Input.GetKey(KeyCode.S))
        {
            x = 0;y = -step;
        }
        if (Input.GetKey(KeyCode.A))
        {
            x = -step;y = 0;
        }
        if (Input.GetKey(KeyCode.D))
        {
            x = step;y = 0;
        }
    }

    void Move()
    {
        headPos = gameObject.transform.localPosition;
        gameObject.transform.localPosition = new Vector3(headPos.x+x,headPos.y+y,headPos.z);
    }
}
SnakeHead.cs

 

  給小蛇頭部添加轉動時改變頭部方向動畫

 private void Update()
    {
        if (Input.GetKey(KeyCode.W))
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 0);
            x = 0;y = step;
        }
        if (Input.GetKey(KeyCode.S))
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 180);
            x = 0;y = -step;
        }
        if (Input.GetKey(KeyCode.A))
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 90);
            x = -step;y = 0;
        }
        if (Input.GetKey(KeyCode.D))
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, -90);
            x = step;y = 0;
        }
    }

 

 

  發現小球向左走時還能向右走,向下走時還能向上走

  判斷按鍵方法時候可以對方向進行一個判斷

    private void Update()
    {
        if (Input.GetKey(KeyCode.W) &&  y!=-step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 0);
            x = 0;y = step;
        }
        if (Input.GetKey(KeyCode.S) &&  y!=step  )
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 180);
            x = 0;y = -step;
        }
        if (Input.GetKey(KeyCode.A) && x!=step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 90);
            x = -step;y = 0;
        }
        if (Input.GetKey(KeyCode.D) &&  x!=-step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, -90);
            x = step;y = 0;
        }
    }

 

  添加按下空格加快貪吃蛇向前移動速度

        if (Input.GetKeyDown(KeyCode.Space))
        {
            CancelInvoke();
            InvokeRepeating("Move",0,velocity - 0.2f);
        }

        if (Input.GetKeyUp(KeyCode.Space))
        {
            CancelInvoke();
            InvokeRepeating("Move", 0, velocity);
        }

 

  Unity聖典  傳送門

  MonoBehaviour.CancelInvoke 取消調用

     MonoBehaviour.InvokeRepeating 重復調用

 

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SnakeHead : MonoBehaviour {

    public float velocity=0.35f;
    public int step;
    private int x;
    private int y;
    private Vector3 headPos;

    private void Start()
    {
        //重復調用
        InvokeRepeating("Move",0,velocity);
        x = 0;y = step;
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            CancelInvoke();
            InvokeRepeating("Move",0,velocity - 0.2f);
        }

        if (Input.GetKeyUp(KeyCode.Space))
        {
            CancelInvoke();
            InvokeRepeating("Move", 0, velocity);
        }

        if (Input.GetKey(KeyCode.W) &&  y!=-step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 0);
            x = 0;y = step;
        }
        if (Input.GetKey(KeyCode.S) &&  y!=step  )
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 180);
            x = 0;y = -step;
        }
        if (Input.GetKey(KeyCode.A) && x!=step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 90);
            x = -step;y = 0;
        }
        if (Input.GetKey(KeyCode.D) &&  x!=-step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, -90);
            x = step;y = 0;
        }
    }

    void Move()
    {
        headPos = gameObject.transform.localPosition;
        gameObject.transform.localPosition = new Vector3(headPos.x+x,headPos.y+y,headPos.z);
    }
}
SnakeHead.cs

 

 

 

第一個食物的隨機生成

 

  對游戲邊界范圍的判定

  上邊界與下邊界

 

  經測試

  小蛇走11步碰到上邊界,走10步碰到下邊界

  小蛇走19步碰到右邊界,走11步碰到左邊界

 

  將食物和小蛇設置為預制體

 

  創建一個GameObject空物體對象掛在腳本和預制體

 

  游戲初始時獲得游戲物體,並且生成食物

 private void Start()
    {
        foodHolder = GameObject.Find("FoodHolder").transform;
        MakeFood();
    }

  

  隨機生成食物的位置

 public int xlimit = 18;
 public int ylimit = 10;
 //x軸活動空間不對稱問題,對x軸的偏移值
 public int xoffset = 11;    

 void MakeFood()
 {
   //生成x和y的隨機值
   int x = Random.Range(-xlimit + xoffset,xlimit);
   int y = Random.Range(-ylimit,ylimit);
   //通過小蛇自身的步數長度來計算食物的活動空間
   food.transform.localPosition = new Vector3(x * 20, y * 20, 0);
 }

 

  隨機生成食物的種類和位置

 void MakeFood()
    {
        int index = Random.Range(0,foodSprites.Length);
        GameObject food = Instantiate(foodPrefab);
        food.GetComponent<Image>().sprite = foodSprites[index];
        food.transform.SetParent(foodHolder,false);
        int x = Random.Range(-xlimit + xoffset,xlimit);
        int y = Random.Range(-ylimit,ylimit);
        //通過小蛇自身的步數長度來計算食物的活動空間
        food.transform.localPosition = new Vector3(x * 25, y * 25, 0);
    }

 

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class FoodMaker : MonoBehaviour {

    public int xlimit = 18;
    public int ylimit = 10;
    //x軸活動空間不對稱問題,對x軸的偏移值
    public int xoffset = 11;
    public GameObject foodPrefab;
    public Sprite[] foodSprites;
    private Transform foodHolder;

    private void Start()
    {
        foodHolder = GameObject.Find("FoodHolder").transform;
        MakeFood();
    }

    void MakeFood()
    {
        int index = Random.Range(0,foodSprites.Length);
        GameObject food = Instantiate(foodPrefab);
        food.GetComponent<Image>().sprite = foodSprites[index];
        food.transform.SetParent(foodHolder,false);
        int x = Random.Range(-xlimit + xoffset,xlimit);
        int y = Random.Range(-ylimit,ylimit);
        //通過小蛇自身的步數長度來計算食物的活動空間
        food.transform.localPosition = new Vector3(x * 25, y * 25, 0);
    }
}
FoodMaker.cs

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SnakeHead : MonoBehaviour {

    public float velocity=0.35f;
    public int step;
    private int x;
    private int y;
    private Vector3 headPos;

    private void Start()
    {
        //重復調用
        InvokeRepeating("Move",0,velocity);
        x = 0;y = step;
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            CancelInvoke();
            InvokeRepeating("Move",0,velocity - 0.2f);
        }

        if (Input.GetKeyUp(KeyCode.Space))
        {
            CancelInvoke();
            InvokeRepeating("Move", 0, velocity);
        }

        if (Input.GetKey(KeyCode.W) &&  y!=-step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 0);
            x = 0;y = step;
        }
        if (Input.GetKey(KeyCode.S) &&  y!=step  )
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 180);
            x = 0;y = -step;
        }
        if (Input.GetKey(KeyCode.A) && x!=step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 90);
            x = -step;y = 0;
        }
        if (Input.GetKey(KeyCode.D) &&  x!=-step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, -90);
            x = step;y = 0;
        }
    }

    void Move()
    {
        headPos = gameObject.transform.localPosition;
        gameObject.transform.localPosition = new Vector3(headPos.x+x,headPos.y+y,headPos.z);
    }
}
SnakeHead.cs

 

 

吃掉食物(銷毀)以及食物的隨機生成

 

  給蛇頭添加Box Collider 2D碰撞器,為避免蛇頭未碰撞食物時碰撞器就碰撞到食物,可以設置碰撞器范圍比蛇頭小一圈

  勾選Is Trigger,當物體碰到食物及邊界時,可以進入邊界再判定游戲結束

 

  給蛇頭添加Rigidbody 2D碰撞器,設置重力 Gravity Scale為0  (不然蛇頭在開始游戲時就會不斷往下掉)

 

  同理,給食物預設體Food添加Box Collider 2D碰撞器

 

  新創建一個Food標簽作為標記

 

  將Food預設體標簽設置為Food

 

  SnakeHead.cs中添加食物碰撞生成新食物方法

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("Food"))
        {
            Destroy(collision.gameObject);
            FoodMaker.Instance.MakeFood();
        }
    }

 

  FoodMaker.cs

 

  添加一個單例模式

 

    //單例模式
    private static FoodMaker _instance;
    //可以通過外部去調用方法修改_instance的值
    public static FoodMaker Instance
    {
        get
        {
            return _instance;
        }
    }

    //初始化
    private void Awake()
    {
        _instance = this;
    }

 

 

 

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class FoodMaker : MonoBehaviour {

    //單例模式
    private static FoodMaker _instance;
    public static FoodMaker Instance
    {
        get
        {
            return _instance;
        }
    }
    public int xlimit = 17;
    public int ylimit = 8;
    //x軸活動空間不對稱問題,對x軸的偏移值
    public int xoffset = 11;
    public GameObject foodPrefab;
    public Sprite[] foodSprites;
    private Transform foodHolder;

    private void Awake()
    {
        _instance = this;
    }

    private void Start()
    {
        foodHolder = GameObject.Find("FoodHolder").transform;
        MakeFood();
    }

    public void MakeFood()
    {
        int index = Random.Range(0,foodSprites.Length);
        GameObject food = Instantiate(foodPrefab);
        food.GetComponent<Image>().sprite = foodSprites[index];
        food.transform.SetParent(foodHolder,false);
        int x = Random.Range(-xlimit + xoffset,xlimit);
        int y = Random.Range(-ylimit,ylimit);
        //通過小蛇自身的步數長度來計算食物的活動空間
        food.transform.localPosition = new Vector3(x * 25, y * 25, 0);
    }
}
FoodMaker.cs

 

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SnakeHead : MonoBehaviour {

    public float velocity=0.35f;
    public int step;
    private int x;
    private int y;
    private Vector3 headPos;

    private void Start()
    {
        //重復調用
        InvokeRepeating("Move",0,velocity);
        x = 0;y = step;
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            CancelInvoke();
            InvokeRepeating("Move",0,velocity - 0.2f);
        }

        if (Input.GetKeyUp(KeyCode.Space))
        {
            CancelInvoke();
            InvokeRepeating("Move", 0, velocity);
        }

        if (Input.GetKey(KeyCode.W) &&  y!=-step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 0);
            x = 0;y = step;
        }
        if (Input.GetKey(KeyCode.S) &&  y!=step  )
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 180);
            x = 0;y = -step;
        }
        if (Input.GetKey(KeyCode.A) && x!=step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 90);
            x = -step;y = 0;
        }
        if (Input.GetKey(KeyCode.D) &&  x!=-step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, -90);
            x = step;y = 0;
        }
    }

    void Move()
    {
        headPos = gameObject.transform.localPosition;
        gameObject.transform.localPosition = new Vector3(headPos.x+x,headPos.y+y,headPos.z);
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("Food"))
        {
            Destroy(collision.gameObject);
            FoodMaker.Instance.MakeFood();
        }
    }

}
SnakeHead.cs

 

 

 

蛇身吃掉食物的變長

 

  添加一個Image放置蛇身圖片,添加Box Collider 2D碰撞器(碰撞器的范圍不用太大,以免對食物產生不可描述的誤操作)

 

  SnakeHead.cs腳本中生成蛇身

  創建一個集合,用來保存蛇身部分(兩張圖片不斷輪流交換)

 public List<RectTransform> bodyList = new List<RectTransform>();


 public GameObject bodyPrefab;
 public Sprite[] bodySprites = new Sprite[2];

 

  生成蛇身體方法

    void Grow()
    {
        int index = (bodyList.Count % 2 == 0) ? 0 : 1;
        GameObject body = Instantiate(bodyPrefab);
        body.GetComponent<Image>().sprite = bodySprites[index];
        body.transform.SetParent(canvas,false);
        bodyList.Add(body.transform);
    }

 

 

 

蛇生體移動的方法

 

   創建一個鏈表,當蛇吃了食物后,將蛇身放置到鏈表中

 public List<Transform> bodyList = new List<Transform>();

 

  將圖片放置到bodySprites中(兩張),存放的都是bodyPrefab

    public GameObject bodyPrefab;
    public Sprite[] bodySprites = new Sprite[2];

    private void Awake()
    {
        canvas = GameObject.Find("Canvas").transform;
    }

 

  Unity中將預制體與貪吃蛇頭部綁定一下

 

   蛇碰到食物后開始生成蛇身

    void Grow()
    {
        int index = (bodyList.Count % 2 == 0) ? 0 : 1;
        GameObject body = Instantiate(bodyPrefab,new Vector3(200000,2000000,0),Quaternion.identity);
        body.GetComponent<Image>().sprite = bodySprites[index];
        body.transform.SetParent(canvas, false);
        bodyList.Add(body.transform);
    }

 

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("Food"))
        {
            Destroy(collision.gameObject);
            Grow();
            FoodMaker.Instance.MakeFood();
        }
    }

 

 

  

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class FoodMaker : MonoBehaviour {

    //單例模式
    private static FoodMaker _instance;
    public static FoodMaker Instance
    {
        get
        {
            return _instance;
        }
    }
    public int xlimit = 18;
    public int ylimit = 9;
    //x軸活動空間不對稱問題,對x軸的偏移值
    public int xoffset = 10;
    public GameObject foodPrefab;
    public Sprite[] foodSprites;
    private Transform foodHolder;

    private void Awake()
    {
        _instance = this;
    }

    private void Start()
    {
        foodHolder = GameObject.Find("FoodHolder").transform;
        MakeFood();
    }

    public void MakeFood()
    {
        int index = Random.Range(0,foodSprites.Length);
        GameObject food = Instantiate(foodPrefab);
        food.GetComponent<Image>().sprite = foodSprites[index];
        food.transform.SetParent(foodHolder,false);
        int x = Random.Range(-xlimit + xoffset,xlimit);
        int y = Random.Range(-ylimit,ylimit);
        food.transform.localPosition = new Vector3(x * 20, y * 20, 0);
        //food.transform.localPosition = new Vector3( x,  y, 0);
    }
}
FoodMaker.cs

 

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

public class SnakeHead : MonoBehaviour {

    public List<Transform> bodyList = new List<Transform>();
    public float velocity=0.35f;
    public int step;
    private int x;
    private int y;
    private Vector3 headPos;
    private Transform canvas;

    public GameObject bodyPrefab;
    public Sprite[] bodySprites = new Sprite[2];

    private void Awake()
    {
        canvas = GameObject.Find("Canvas").transform;
    }

    private void Start()
    {
        //重復調用
        InvokeRepeating("Move",0,velocity);
        x = 0;y = step;
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            CancelInvoke();
            InvokeRepeating("Move",0,velocity - 0.3f);
        }

        if (Input.GetKeyUp(KeyCode.Space))
        {
            CancelInvoke();
            InvokeRepeating("Move", 0, velocity);
        }

        if (Input.GetKey(KeyCode.W) &&  y!=-step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 0);
            x = 0;y = step;
        }
        if (Input.GetKey(KeyCode.S) &&  y!=step  )
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 180);
            x = 0;y = -step;
        }
        if (Input.GetKey(KeyCode.A) && x!=step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 90);
            x = -step;y = 0;
        }
        if (Input.GetKey(KeyCode.D) &&  x!=-step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, -90);
            x = step;y = 0;
        }
    }

    void Move()
    {
        //保存下來蛇頭移動前的位置
        headPos = gameObject.transform.localPosition;
        //蛇頭向期望位置移動
        gameObject.transform.localPosition = new Vector3(headPos.x+x,headPos.y+y,headPos.z);
        if (bodyList.Count > 0)
        {
            //由於是雙色蛇身,此方法棄用
            //將蛇尾移動到蛇頭移動前的位置
           // bodyList.Last().localPosition = headPos;
           //將蛇尾在List中的位置跟新到最前
           // bodyList.Insert(0, bodyList.Last());
           //溢出List最末尾的蛇尾引用
           // bodyList.RemoveAt(bodyList.Count - 1);

            //從后面開始移動蛇身
            for(int i =bodyList.Count-2;i>=0 ;i--)
            {
                //每一個蛇身都移動到它前面一個
                bodyList[i + 1].localPosition = bodyList[i].localPosition;
            }
            //第一個蛇身移動到蛇頭移動前的位置
            bodyList[0].localPosition = headPos;

        }
    }

    void Grow()
    {
        int index = (bodyList.Count % 2 == 0) ? 0 : 1;
        GameObject body = Instantiate(bodyPrefab,new Vector3(200000,2000000,0),Quaternion.identity);
        body.GetComponent<Image>().sprite = bodySprites[index];
        body.transform.SetParent(canvas, false);
        bodyList.Add(body.transform);
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("Food"))
        {
            Destroy(collision.gameObject);
            Grow();
            FoodMaker.Instance.MakeFood();
        }
    }

}
SnakeHead.cs

 

 

游戲的自由模式

 

  當小蛇撞到上邊界時再往下走一步后從下邊界出現

  當小蛇撞到下邊界時再往上走一步后從上邊界出現

  當小蛇撞到上邊界時再往下走一步后從下邊界出現

  當小蛇撞到上邊界時再往下走一步后從下邊界出現

 

     switch(collision.gameObject.name)
            {
                case "Up":
                    transform.localPosition = new Vector3(transform.localPosition.x,-transform.localPosition.y+20,transform.localPosition.z);
                    break;
                case "Down":
                    transform.localPosition = new Vector3(transform.localPosition.x, -transform.localPosition.y-20, transform.localPosition.z);
                    break;
                case "Left":
                    transform.localPosition = new Vector3(-transform.localPosition.x+140,transform.localPosition.y , transform.localPosition.z);
                    break;
                case "Right":
                    transform.localPosition = new Vector3(-transform.localPosition.x+170, transform.localPosition.y, transform.localPosition.z);
                    break;
            }

 

 

 

獎勵目標的生成

 

  添加一個Reward(Image)作為獎勵目標背景圖片

 

  調整獎勵背景圖片和食物大小保持一樣,並添加Box Collider 2D組件

  

  將Resward作為預制體

  FoodMaker.cs上綁定rewardPrefabs預制體

    public GameObject rewardPrefab;

 

  

 

   判斷是否生成道具

  public void MakeFood(bool isReward)
    {
        int index = Random.Range(0,foodSprites.Length);
        GameObject food = Instantiate(foodPrefab);
        food.GetComponent<Image>().sprite = foodSprites[index];
        food.transform.SetParent(foodHolder,false);
        int x = Random.Range(-xlimit + xoffset,xlimit);
        int y = Random.Range(-ylimit,ylimit);
        food.transform.localPosition = new Vector3(x * 20, y * 20, 0);
        //food.transform.localPosition = new Vector3( x,  y, 0);
        if(isReward==true)
        {
            GameObject reward = Instantiate(rewardPrefab);
            reward.transform.SetParent(foodHolder, false);
            x = Random.Range(-xlimit + xoffset, xlimit);
            y = Random.Range(-ylimit, ylimit);
            reward.transform.localPosition = new Vector3(x * 20, y * 20, 0);
        }
    }

 

   當蛇吃到食物后,有百分之20的機率生成道具

 if (collision.gameObject.CompareTag("Food"))
        {
            Destroy(collision.gameObject);
            Grow();
            if (Random.Range(0,100)<20)
            {
                FoodMaker.Instance.MakeFood(true);
            }
            else
            {
                FoodMaker.Instance.MakeFood(false);
            }
        }

 

  當蛇吃到道具時,道具銷毀

 else if(collision.gameObject.CompareTag("Reward"))
        {
            Destroy(collision.gameObject);
            Grow();
        }

 

  

 

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

public class SnakeHead : MonoBehaviour {

    public List<Transform> bodyList = new List<Transform>();
    public float velocity=0.35f;
    public int step;
    private int x;
    private int y;
    private Vector3 headPos;
    private Transform canvas;

    public GameObject bodyPrefab;
    public Sprite[] bodySprites = new Sprite[2];



    private void Awake()
    {
        canvas = GameObject.Find("Canvas").transform;
    }

    private void Start()
    {
        //重復調用
        InvokeRepeating("Move",0,velocity);
        x = 0;y = step;
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            CancelInvoke();
            InvokeRepeating("Move",0,velocity - 0.3f);
        }

        if (Input.GetKeyUp(KeyCode.Space))
        {
            CancelInvoke();
            InvokeRepeating("Move", 0, velocity);
        }

        if (Input.GetKey(KeyCode.W) &&  y!=-step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 0);
            x = 0;y = step;
        }
        if (Input.GetKey(KeyCode.S) &&  y!=step  )
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 180);
            x = 0;y = -step;
        }
        if (Input.GetKey(KeyCode.A) && x!=step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 90);
            x = -step;y = 0;
        }
        if (Input.GetKey(KeyCode.D) &&  x!=-step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, -90);
            x = step;y = 0;
        }
    }

    void Move()
    {
        //保存下來蛇頭移動前的位置
        headPos = gameObject.transform.localPosition;
        //蛇頭向期望位置移動
        gameObject.transform.localPosition = new Vector3(headPos.x+x,headPos.y+y,headPos.z);
        if (bodyList.Count > 0)
        {
            //由於是雙色蛇身,此方法棄用
            //將蛇尾移動到蛇頭移動前的位置
           // bodyList.Last().localPosition = headPos;
           //將蛇尾在List中的位置跟新到最前
           // bodyList.Insert(0, bodyList.Last());
           //溢出List最末尾的蛇尾引用
           // bodyList.RemoveAt(bodyList.Count - 1);

            //從后面開始移動蛇身
            for(int i =bodyList.Count-2;i>=0 ;i--)
            {
                //每一個蛇身都移動到它前面一個
                bodyList[i + 1].localPosition = bodyList[i].localPosition;
            }
            //第一個蛇身移動到蛇頭移動前的位置
            bodyList[0].localPosition = headPos;

        }
    }

    void Grow()
    {
        int index = (bodyList.Count % 2 == 0) ? 0 : 1;
        GameObject body = Instantiate(bodyPrefab,new Vector3(200000,2000000,0),Quaternion.identity);
        body.GetComponent<Image>().sprite = bodySprites[index];
        body.transform.SetParent(canvas, false);
        bodyList.Add(body.transform);
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("Food"))
        {
            Destroy(collision.gameObject);
            Grow();
            if (Random.Range(0,100)<20)
            {
                FoodMaker.Instance.MakeFood(true);
            }
            else
            {
                FoodMaker.Instance.MakeFood(false);
            }
        }
        else if(collision.gameObject.CompareTag("Reward"))
        {
            Destroy(collision.gameObject);
            Grow();
        }
        else if(collision.gameObject.CompareTag("Body"))
        {
            Debug.Log("Die");
        }
        else
        {
            switch(collision.gameObject.name)
            {
                case "Up":
                    transform.localPosition = new Vector3(transform.localPosition.x,-transform.localPosition.y+20,transform.localPosition.z);
                    break;
                case "Down":
                    transform.localPosition = new Vector3(transform.localPosition.x, -transform.localPosition.y-20, transform.localPosition.z);
                    break;
                case "Left":
                    transform.localPosition = new Vector3(-transform.localPosition.x+140,transform.localPosition.y , transform.localPosition.z);
                    break;
                case "Right":
                    transform.localPosition = new Vector3(-transform.localPosition.x+170, transform.localPosition.y, transform.localPosition.z);
                    break;
            }
        }
    }

}
SnakeHead.cs

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class FoodMaker : MonoBehaviour {

    //單例模式
    private static FoodMaker _instance;
    public static FoodMaker Instance
    {
        get
        {
            return _instance;
        }
    }
    public int xlimit = 18;
    public int ylimit = 9;
    //x軸活動空間不對稱問題,對x軸的偏移值
    public int xoffset = 10;
    public GameObject foodPrefab;
    public GameObject rewardPrefab;
    public Sprite[] foodSprites;
    private Transform foodHolder;

    private void Awake()
    {
        _instance = this;
    }

    private void Start()
    {
        foodHolder = GameObject.Find("FoodHolder").transform;
        MakeFood(false);
    }

    public void MakeFood(bool isReward)
    {
        int index = Random.Range(0,foodSprites.Length);
        GameObject food = Instantiate(foodPrefab);
        food.GetComponent<Image>().sprite = foodSprites[index];
        food.transform.SetParent(foodHolder,false);
        int x = Random.Range(-xlimit + xoffset,xlimit);
        int y = Random.Range(-ylimit,ylimit);
        food.transform.localPosition = new Vector3(x * 20, y * 20, 0);
        //food.transform.localPosition = new Vector3( x,  y, 0);
        if(isReward==true)
        {
            GameObject reward = Instantiate(rewardPrefab);
            reward.transform.SetParent(foodHolder, false);
            x = Random.Range(-xlimit + xoffset, xlimit);
            y = Random.Range(-ylimit, ylimit);
            reward.transform.localPosition = new Vector3(x * 20, y * 20, 0);
        }
    }
}
FoodMaker.cs

 

 

分數與長度與游戲背景切換

 

  新建一個腳本MainUIController.cs來存儲蛇的分數與長度

 

  分數的單例模式

 //單例模式
    private static MainUIController _instance;
    public static MainUIController Instance
    {
        get
        {
            return _instance;
        }
    }

  

  游戲加分方法  默認吃到一個食物加5分1個長度  獲得道具加分會更高

public void UpdateUI(int s = 5,int l = 1)
    {
        score += s;
        length += l;
        scoreText.text ="得分:\n"+score;
        lengthText.text = "長度\n" + length;
    }

 

  當蛇吃到食物或道具時調用UpdateUI()方法

 if (collision.gameObject.CompareTag("Food"))
        {
            Destroy(collision.gameObject);
            MainUIController.Instance.UpdateUI();
            Grow();
            if (Random.Range(0,100)<20)
            {
                FoodMaker.Instance.MakeFood(true);
            }
            else
            {
                FoodMaker.Instance.MakeFood(false);
            }
        }
        else if(collision.gameObject.CompareTag("Reward"))
        {
            Destroy(collision.gameObject);
            MainUIController.Instance.UpdateUI(Random.Range(5,15)*10);
            Grow();
        }

 

  當分數達到一定數值時能進行游戲背景變色

    private void Update()
    {
        switch (score / 100)
        {
            case 3:
                ColorUtility.TryParseHtmlString("#CCEEFFFF",out tempColor);
                bgImage.color=tempColor;
                msgText.text = "階段" + 2;
                break;
            case 5:
                ColorUtility.TryParseHtmlString("#CCEEFFFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段" + 3;
                break;
            case 7:
                ColorUtility.TryParseHtmlString("#CCFFDBFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段" + 4;
                break;
            case 9:
                ColorUtility.TryParseHtmlString("#EBFFCCFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段" + 5;
                break;
            case 11:
                ColorUtility.TryParseHtmlString("#FFDACCFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段 x";
                break;
        }
    }

 

  將腳本放在Script游戲物體上,並綁定分數版、背景等

 

 

 

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

public class SnakeHead : MonoBehaviour {

    public List<Transform> bodyList = new List<Transform>();
    public float velocity=0.35f;
    public int step;
    private int x;
    private int y;
    private Vector3 headPos;
    private Transform canvas;

    public GameObject bodyPrefab;
    public Sprite[] bodySprites = new Sprite[2];



    private void Awake()
    {
        canvas = GameObject.Find("Canvas").transform;
    }

    private void Start()
    {
        //重復調用
        InvokeRepeating("Move",0,velocity);
        x = 0;y = step;
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            CancelInvoke();
            InvokeRepeating("Move",0,velocity - 0.3f);
        }

        if (Input.GetKeyUp(KeyCode.Space))
        {
            CancelInvoke();
            InvokeRepeating("Move", 0, velocity);
        }

        if (Input.GetKey(KeyCode.W) &&  y!=-step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 0);
            x = 0;y = step;
        }
        if (Input.GetKey(KeyCode.S) &&  y!=step  )
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 180);
            x = 0;y = -step;
        }
        if (Input.GetKey(KeyCode.A) && x!=step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 90);
            x = -step;y = 0;
        }
        if (Input.GetKey(KeyCode.D) &&  x!=-step)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, -90);
            x = step;y = 0;
        }
    }

    void Move()
    {
        //保存下來蛇頭移動前的位置
        headPos = gameObject.transform.localPosition;
        //蛇頭向期望位置移動
        gameObject.transform.localPosition = new Vector3(headPos.x+x,headPos.y+y,headPos.z);
        if (bodyList.Count > 0)
        {
            //由於是雙色蛇身,此方法棄用
            //將蛇尾移動到蛇頭移動前的位置
           // bodyList.Last().localPosition = headPos;
           //將蛇尾在List中的位置跟新到最前
           // bodyList.Insert(0, bodyList.Last());
           //溢出List最末尾的蛇尾引用
           // bodyList.RemoveAt(bodyList.Count - 1);

            //從后面開始移動蛇身
            for(int i =bodyList.Count-2;i>=0 ;i--)
            {
                //每一個蛇身都移動到它前面一個
                bodyList[i + 1].localPosition = bodyList[i].localPosition;
            }
            //第一個蛇身移動到蛇頭移動前的位置
            bodyList[0].localPosition = headPos;

        }
    }

    void Grow()
    {
        int index = (bodyList.Count % 2 == 0) ? 0 : 1;
        GameObject body = Instantiate(bodyPrefab,new Vector3(200000,2000000,0),Quaternion.identity);
        body.GetComponent<Image>().sprite = bodySprites[index];
        body.transform.SetParent(canvas, false);
        bodyList.Add(body.transform);
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("Food"))
        {
            Destroy(collision.gameObject);
            MainUIController.Instance.UpdateUI();
            Grow();
            if (Random.Range(0,100)<20)
            {
                FoodMaker.Instance.MakeFood(true);
            }
            else
            {
                FoodMaker.Instance.MakeFood(false);
            }
        }
        else if(collision.gameObject.CompareTag("Reward"))
        {
            Destroy(collision.gameObject);
            MainUIController.Instance.UpdateUI(Random.Range(5,15)*10);
            Grow();
        }
        else if(collision.gameObject.CompareTag("Body"))
        {
            Debug.Log("Die");
        }
        else
        {
            switch(collision.gameObject.name)
            {
                case "Up":
                    transform.localPosition = new Vector3(transform.localPosition.x,-transform.localPosition.y+20,transform.localPosition.z);
                    break;
                case "Down":
                    transform.localPosition = new Vector3(transform.localPosition.x, -transform.localPosition.y-20, transform.localPosition.z);
                    break;
                case "Left":
                    transform.localPosition = new Vector3(-transform.localPosition.x+140,transform.localPosition.y , transform.localPosition.z);
                    break;
                case "Right":
                    transform.localPosition = new Vector3(-transform.localPosition.x+170, transform.localPosition.y, transform.localPosition.z);
                    break;
            }
        }
    }

}
SnakeHead.cs

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class FoodMaker : MonoBehaviour {

    //單例模式
    private static FoodMaker _instance;
    public static FoodMaker Instance
    {
        get
        {
            return _instance;
        }
    }
    public int xlimit = 18;
    public int ylimit = 9;
    //x軸活動空間不對稱問題,對x軸的偏移值
    public int xoffset = 10;
    public GameObject foodPrefab;
    public GameObject rewardPrefab;
    public Sprite[] foodSprites;
    private Transform foodHolder;

    private void Awake()
    {
        _instance = this;
    }

    private void Start()
    {
        foodHolder = GameObject.Find("FoodHolder").transform;
        MakeFood(false);
    }

    public void MakeFood(bool isReward)
    {
        int index = Random.Range(0,foodSprites.Length);
        GameObject food = Instantiate(foodPrefab);
        food.GetComponent<Image>().sprite = foodSprites[index];
        food.transform.SetParent(foodHolder,false);
        int x = Random.Range(-xlimit + xoffset,xlimit);
        int y = Random.Range(-ylimit,ylimit);
        food.transform.localPosition = new Vector3(x * 20, y * 20, 0);
        //food.transform.localPosition = new Vector3( x,  y, 0);
        if(isReward==true)
        {
            GameObject reward = Instantiate(rewardPrefab);
            reward.transform.SetParent(foodHolder, false);
            x = Random.Range(-xlimit + xoffset, xlimit);
            y = Random.Range(-ylimit, ylimit);
            reward.transform.localPosition = new Vector3(x * 20, y * 20, 0);
        }
    }
}
FoodMaker.cs

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class MainUIController : MonoBehaviour {

    //單例模式
    private static MainUIController _instance;
    public static MainUIController Instance
    {
        get
        {
            return _instance;
        }
    }

    public int score = 0;
    public int length = 0;
    public Text msgText;
    public Text scoreText;
    public Text lengthText;
    public Image bgImage;
    private Color tempColor;

    void Awake()
    {
        _instance = this;    
    }

    private void Update()
    {
        switch (score / 100)
        {
            case 3:
                ColorUtility.TryParseHtmlString("#CCEEFFFF",out tempColor);
                bgImage.color=tempColor;
                msgText.text = "階段" + 2;
                break;
            case 5:
                ColorUtility.TryParseHtmlString("#CCEEFFFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段" + 3;
                break;
            case 7:
                ColorUtility.TryParseHtmlString("#CCFFDBFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段" + 4;
                break;
            case 9:
                ColorUtility.TryParseHtmlString("#EBFFCCFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段" + 5;
                break;
            case 11:
                ColorUtility.TryParseHtmlString("#FFDACCFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段 x";
                break;
        }
    }

    public void UpdateUI(int s = 5,int l = 1)
    {
        score += s;
        length += l;
        scoreText.text ="得分:\n"+score;
        lengthText.text = "長度\n" + length;
    }

}
MainUIController.cs

 

 

暫停與返回按鈕

 

  對按鈕進行引用以及添加一個圖片Sprite[]

    public Button pauseButton;
    public Sprite[] pauseSprites;

 

  設置一個變量記錄游戲狀態

    private bool isPause = false ;

 

  點擊按鈕時候對游戲狀態取反

    public void Pause()
    {
        isPause = !isPause;
        if(isPause)
        {
            Time.timeScale = 0;
            pauseButton.GetComponent<Image>().sprite = pauseSprites[1];
        }
        else
        {
            Time.timeScale = 1;
            pauseButton.GetComponent<Image>().sprite = pauseSprites[0];
        }
    }

 

  Time.timeScale  傳送門

  Script中對圖片、按鈕進行綁定

  

  

  在onclick()

 

 

 

  解決按鍵沖突

  按鍵控制器Edit->Project Settings-> Input 

    

  

 private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space)&&MainUIController.Instance.isPause==false)
        {
            CancelInvoke();
            InvokeRepeating("Move",0,velocity - 0.3f);
        }

        if (Input.GetKeyUp(KeyCode.Space) && MainUIController.Instance.isPause == false)
        {
            CancelInvoke();
            InvokeRepeating("Move", 0, velocity);
        }

        if (Input.GetKey(KeyCode.W) &&  y!=-step && MainUIController.Instance.isPause == false)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 0);
            x = 0;y = step;
        }
        if (Input.GetKey(KeyCode.S) &&  y!=step && MainUIController.Instance.isPause == false)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 180);
            x = 0;y = -step;
        }
        if (Input.GetKey(KeyCode.A) && x!=step && MainUIController.Instance.isPause == false)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 90);
            x = -step;y = 0;
        }
        if (Input.GetKey(KeyCode.D) &&  x!=-step && MainUIController.Instance.isPause == false)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, -90);
            x = step;y = 0;
        }
    }
Update()中對鍵盤按下事件進行處理

 

   接下來實現返回按鈕

    public void Home()
    {
        UnityEngine.SceneManagement.SceneManager.LoadScene(0);
    }

 

  Home按鈕上添加點擊事件

 

 

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

public class SnakeHead : MonoBehaviour {

    public List<Transform> bodyList = new List<Transform>();
    public float velocity=0.35f;
    public int step;
    private int x;
    private int y;
    private Vector3 headPos;
    private Transform canvas;

    public GameObject bodyPrefab;
    public Sprite[] bodySprites = new Sprite[2];



    private void Awake()
    {
        canvas = GameObject.Find("Canvas").transform;
    }

    private void Start()
    {
        //重復調用
        InvokeRepeating("Move",0,velocity);
        x = 0;y = step;
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space)&&MainUIController.Instance.isPause==false)
        {
            CancelInvoke();
            InvokeRepeating("Move",0,velocity - 0.3f);
        }

        if (Input.GetKeyUp(KeyCode.Space) && MainUIController.Instance.isPause == false)
        {
            CancelInvoke();
            InvokeRepeating("Move", 0, velocity);
        }

        if (Input.GetKey(KeyCode.W) &&  y!=-step && MainUIController.Instance.isPause == false)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 0);
            x = 0;y = step;
        }
        if (Input.GetKey(KeyCode.S) &&  y!=step && MainUIController.Instance.isPause == false)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 180);
            x = 0;y = -step;
        }
        if (Input.GetKey(KeyCode.A) && x!=step && MainUIController.Instance.isPause == false)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 90);
            x = -step;y = 0;
        }
        if (Input.GetKey(KeyCode.D) &&  x!=-step && MainUIController.Instance.isPause == false)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, -90);
            x = step;y = 0;
        }
    }

    void Move()
    {
        //保存下來蛇頭移動前的位置
        headPos = gameObject.transform.localPosition;
        //蛇頭向期望位置移動
        gameObject.transform.localPosition = new Vector3(headPos.x+x,headPos.y+y,headPos.z);
        if (bodyList.Count > 0)
        {
            //由於是雙色蛇身,此方法棄用
            //將蛇尾移動到蛇頭移動前的位置
           // bodyList.Last().localPosition = headPos;
           //將蛇尾在List中的位置跟新到最前
           // bodyList.Insert(0, bodyList.Last());
           //溢出List最末尾的蛇尾引用
           // bodyList.RemoveAt(bodyList.Count - 1);

            //從后面開始移動蛇身
            for(int i =bodyList.Count-2;i>=0 ;i--)
            {
                //每一個蛇身都移動到它前面一個
                bodyList[i + 1].localPosition = bodyList[i].localPosition;
            }
            //第一個蛇身移動到蛇頭移動前的位置
            bodyList[0].localPosition = headPos;

        }
    }

    void Grow()
    {
        int index = (bodyList.Count % 2 == 0) ? 0 : 1;
        GameObject body = Instantiate(bodyPrefab,new Vector3(200000,2000000,0),Quaternion.identity);
        body.GetComponent<Image>().sprite = bodySprites[index];
        body.transform.SetParent(canvas, false);
        bodyList.Add(body.transform);
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("Food"))
        {
            Destroy(collision.gameObject);
            MainUIController.Instance.UpdateUI();
            Grow();
            if (Random.Range(0,100)<20)
            {
                FoodMaker.Instance.MakeFood(true);
            }
            else
            {
                FoodMaker.Instance.MakeFood(false);
            }
        }
        else if(collision.gameObject.CompareTag("Reward"))
        {
            Destroy(collision.gameObject);
            MainUIController.Instance.UpdateUI(Random.Range(5,15)*10);
            Grow();
        }
        else if(collision.gameObject.CompareTag("Body"))
        {
            Debug.Log("Die");
        }
        else
        {
            switch(collision.gameObject.name)
            {
                case "Up":
                    transform.localPosition = new Vector3(transform.localPosition.x,-transform.localPosition.y+20,transform.localPosition.z);
                    break;
                case "Down":
                    transform.localPosition = new Vector3(transform.localPosition.x, -transform.localPosition.y-20, transform.localPosition.z);
                    break;
                case "Left":
                    transform.localPosition = new Vector3(-transform.localPosition.x+140,transform.localPosition.y , transform.localPosition.z);
                    break;
                case "Right":
                    transform.localPosition = new Vector3(-transform.localPosition.x+170, transform.localPosition.y, transform.localPosition.z);
                    break;
            }
        }
    }

}
SnakeHead.cs

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class FoodMaker : MonoBehaviour {

    //單例模式
    private static FoodMaker _instance;
    public static FoodMaker Instance
    {
        get
        {
            return _instance;
        }
    }
    public int xlimit = 18;
    public int ylimit = 9;
    //x軸活動空間不對稱問題,對x軸的偏移值
    public int xoffset = 10;
    public GameObject foodPrefab;
    public GameObject rewardPrefab;
    public Sprite[] foodSprites;
    private Transform foodHolder;

    private void Awake()
    {
        _instance = this;
    }

    private void Start()
    {
        foodHolder = GameObject.Find("FoodHolder").transform;
        MakeFood(false);
    }

    public void MakeFood(bool isReward)
    {
        int index = Random.Range(0,foodSprites.Length);
        GameObject food = Instantiate(foodPrefab);
        food.GetComponent<Image>().sprite = foodSprites[index];
        food.transform.SetParent(foodHolder,false);
        int x = Random.Range(-xlimit + xoffset,xlimit);
        int y = Random.Range(-ylimit,ylimit);
        food.transform.localPosition = new Vector3(x * 20, y * 20, 0);
        //food.transform.localPosition = new Vector3( x,  y, 0);
        if(isReward==true)
        {
            GameObject reward = Instantiate(rewardPrefab);
            reward.transform.SetParent(foodHolder, false);
            x = Random.Range(-xlimit + xoffset, xlimit);
            y = Random.Range(-ylimit, ylimit);
            reward.transform.localPosition = new Vector3(x * 20, y * 20, 0);
        }
    }

    public void Home()
    {
        UnityEngine.SceneManagement.SceneManager.LoadScene(0);
    }
}
FoodMaker.cs

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class MainUIController : MonoBehaviour {

    //單例模式
    private static MainUIController _instance;
    public static MainUIController Instance
    {
        get
        {
            return _instance;
        }
    }

    public int score = 0;
    public int length = 0;
    public Text msgText;
    public Text scoreText;
    public Text lengthText;
    public Image bgImage;
    private Color tempColor;

    public Image pauseImage;
    public Sprite[] pauseSprites;
    public bool isPause = false ;

    void Awake()
    {
        _instance = this;    
    }

    private void Update()
    {
        switch (score / 100)
        {
            case 0:
            case 1:
            case 2:
                break;
            case 3:
            case 4:
                ColorUtility.TryParseHtmlString("#CCEEFFFF",out tempColor);
                bgImage.color=tempColor;
                msgText.text = "階段" + 2;
                break;
            case 5:
            case 6:
                ColorUtility.TryParseHtmlString("#CCEEFFFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段" + 3;
                break;
            case 7:
            case 8:
                ColorUtility.TryParseHtmlString("#CCFFDBFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段" + 4;
                break;
            case 9:
            case 10:
                ColorUtility.TryParseHtmlString("#EBFFCCFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段" + 5;
                break;
            case 11:
            case 12:
            case 13:
                ColorUtility.TryParseHtmlString("#FFDACCFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段 x";
                break;
        }
    }

    public void UpdateUI(int s = 5,int l = 1)
    {
        score += s;
        length += l;
        scoreText.text ="得分:\n"+score;
        lengthText.text = "長度\n" + length;
    }

    public void Pause()
    {
        isPause = !isPause;
        if(isPause)
        {
            Time.timeScale = 0;
            pauseImage.sprite = pauseSprites[1];
        }
        else
        {
            Time.timeScale = 1;
            pauseImage.sprite = pauseSprites[0];
        }
    }
}
MainUIController.cs

 

 

游戲貪吃蛇死亡處理

 

  添加游戲死亡標記

    private bool isDie = false;

 

  判斷游戲死亡時觸發的粒子特效

    void Die()
    {
        CancelInvoke();
        isDie = true;
        Instantiate(dieEffect);
        StartCoroutine(GameOver(1.0f));
    }

 

  通過Unity協成進行游戲的重新開始

    IEnumerator GameOver(float t)
    {
        yield return new WaitForSeconds(t);
        UnityEngine.SceneManagement.SceneManager.LoadScene(1);
    }

 

  

 

  游戲結束時候記錄最高得分

    void Die()
    {
        CancelInvoke();
        isDie = true;
        Instantiate(dieEffect);
        //記錄游戲的最后長度
        PlayerPrefs.SetInt("last1",MainUIController.Instance.length);
        PlayerPrefs.SetInt("lasts", MainUIController.Instance.score);
        //當游戲長度大於最高得分時
        if (PlayerPrefs.GetInt("bests", 0)<MainUIController.Instance.score)
        {
            //將當前游戲長度和分數記錄到best1和bests當中
            PlayerPrefs.SetInt("best1", MainUIController.Instance.length);
            PlayerPrefs.SetInt("bests", MainUIController.Instance.score);
        }
        StartCoroutine(GameOver(1.0f));
    }

 

1、存儲值://本地化存儲方式,一般用在保存玩家的偏好設置中,常見於玩家設置,游戲分數存取…………

  PlayerPrefs.SetFloat(string key,float value); //通過key 與value 存儲,就像鍵值對一樣。

  PlayerPrefs.SetInt(string key,Int value);

  PlayerPrefs.SetString(string key,string value);

2、讀取值:

  PlayerPrefs.GetFloat(string key);  //通過key得到存儲的value值

  PlayerPrefs.GetInt(string key);

  PlayerPrefs.GetString(string key);
Unity 中PlayerPrefs類實現數據本地化存儲

 

 

用戶設置的存儲

 

  添加StartUIController.cs腳本控制Gary開始場景界面

  獲得Gary開始場景界面Text文本控件

    public Text lastText;
    public Text bestText;

 

  對文本控件的值進行讀取刷新

    private void Awake()
    {
        lastText.text = "上次:長度" + PlayerPrefs.GetInt("last1",0)  + ",分數" + PlayerPrefs.GetInt("lasts",0);
        lastText.text = "最好:長度" + PlayerPrefs.GetInt("best1", 0) + ",分數" + PlayerPrefs.GetInt("bests", 0);
    }

 

  Gary場景中創建一個空物體游戲對象ScriptHolder掛在游戲腳本

  

 

  實現點擊開始進入場景功能

  切換場景方法

    public void StartGame()
    {
        UnityEngine.SceneManagement.SceneManager.LoadScene(1);
    }

 

  Gary場景中Start添加onClick()點擊事件

 

(可以看到此時已經實現上次分數以及最高分數的存儲)

 

  動態綁定選擇游戲皮膚、模式

  存儲玩家的選擇

 private void Start()
    {
        if (PlayerPrefs.GetString("sh", "sh01") == "sh01")
        {
            blue.isOn = true;
            PlayerPrefs.SetString("sh", "sh01");
            PlayerPrefs.SetString("sb01", "sb0101");
            PlayerPrefs.SetString("sb02", "sb0102");
        }
        else
        {
            yellow.isOn = true;
            PlayerPrefs.SetString("sh", "sh02");
            PlayerPrefs.SetString("sb01", "sb0201");
            PlayerPrefs.SetString("sb02", "sb0202");
        }
        if (PlayerPrefs.GetInt("border", 1) == 1)
        {
            border.isOn = true;
            PlayerPrefs.SetInt("border",1);
        }
        else
        {
            noborder.isOn = true;
            PlayerPrefs.SetInt("border", 0);
        }
    }

    public void BlueSelected(bool isOn)
    {
        if (isOn)
        {
            PlayerPrefs.SetString("sh", "sh01");
            PlayerPrefs.SetString("sb01", "sb0101");
            PlayerPrefs.SetString("sb02", "sb0102");
        }
    }
       
    public void YellowSelected(bool isOn)
    {
        if (isOn)
        {
            PlayerPrefs.SetString("sh", "sh02");
            PlayerPrefs.SetString("sb01", "sb0201");
            PlayerPrefs.SetString("sb02", "sb0202");
        }
    }

    public void BorderSelected(bool isOn)
    {
        if (isOn)
        {
            PlayerPrefs.SetInt("border",1);
        }
    }

    public void NoBorderSelected(bool isOn)
    {
        if (isOn)
        {
            //自由模式
            PlayerPrefs.SetInt("border", 0);
        }
    }

 

 

 

 

完成換膚與數據讀取

 

  使用泛型加載游戲換膚方法

    private void Awake()
    {
        canvas = GameObject.Find("Canvas").transform;
        //通過Resources.Load(string path)方法加載資源;
        gameObject.GetComponent<Image>().sprite = Resources.Load<Sprite>(PlayerPrefs.GetString("sh", "sh02"));
        bodySprites[0]  = Resources.Load<Sprite>(PlayerPrefs.GetString("sh01", "sh0201"));
        bodySprites[1]  = Resources.Load<Sprite>(PlayerPrefs.GetString("sh02", "sh0202"));
    }

 

 

  判斷游戲模式

  添加一個模式表示位

    public bool hasBorder = true;

 

  游戲初始時默認無邊界

 void Start()
    {
        if (PlayerPrefs.GetInt("border", 1)==0)
        {
            hasBorder = false;
            //取消邊界上的顏色
            foreach(Transform t in bgImage.gameObject.transform)
            {
                t.gameObject.GetComponent<Image>().enabled = false;
            }
        }
    }

 

  SnakeHead.cs腳本中對游戲碰到邊界死亡進行判定

if (MainUIController.Instance.hasBorder)
            {
                Die();
            }
            else
            {
                switch (collision.gameObject.name)
                {
                    case "Up":
                        transform.localPosition = new Vector3(transform.localPosition.x, -transform.localPosition.y + 20, transform.localPosition.z);
                        break;
                    case "Down":
                        transform.localPosition = new Vector3(transform.localPosition.x, -transform.localPosition.y - 20, transform.localPosition.z);
                        break;
                    case "Left":
                        transform.localPosition = new Vector3(-transform.localPosition.x + 140, transform.localPosition.y, transform.localPosition.z);
                        break;
                    case "Right":
                        transform.localPosition = new Vector3(-transform.localPosition.x + 170, transform.localPosition.y, transform.localPosition.z);
                        break;
                }
            }

 

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class StartUIController : MonoBehaviour {

    public Text lastText;
    public Text bestText;
    public Toggle blue;
    public Toggle yellow;
    public Toggle border;
    public Toggle noborder;

    private void Awake()
    {
        lastText.text = "上次:長度" + PlayerPrefs.GetInt("last1",0)  + ",分數" + PlayerPrefs.GetInt("lasts",0);
        bestText.text = "最好:長度" + PlayerPrefs.GetInt("best1", 0) + ",分數" + PlayerPrefs.GetInt("bests",0);
    }

    private void Start()
    {
        if (PlayerPrefs.GetString("sh", "sh01") == "sh01")
        {
            blue.isOn = true;
            PlayerPrefs.SetString("sh", "sh01");
            PlayerPrefs.SetString("sb01", "sb0101");
            PlayerPrefs.SetString("sb02", "sb0102");
        }
        else
        {
            yellow.isOn = true;
            PlayerPrefs.SetString("sh", "sh02");
            PlayerPrefs.SetString("sb01", "sb0201");
            PlayerPrefs.SetString("sb02", "sb0202");
        }
        if (PlayerPrefs.GetInt("border", 1) == 1)
        {
            border.isOn = true;
            PlayerPrefs.SetInt("border",1);
        }
        else
        {
            noborder.isOn = true;
            PlayerPrefs.SetInt("border", 0);
        }
    }

    public void BlueSelected(bool isOn)
    {
        if (isOn)
        {
            PlayerPrefs.SetString("sh", "sh01");
            PlayerPrefs.SetString("sb01", "sb0101");
            PlayerPrefs.SetString("sb02", "sb0102");
        }
    }
       
    public void YellowSelected(bool isOn)
    {
        if (isOn)
        {
            PlayerPrefs.SetString("sh", "sh02");
            PlayerPrefs.SetString("sb01", "sb0201");
            PlayerPrefs.SetString("sb02", "sb0202");
        }
    }

    public void BorderSelected(bool isOn)
    {
        if (isOn)
        {
            PlayerPrefs.SetInt("border",1);
        }
    }

    public void NoBorderSelected(bool isOn)
    {
        if (isOn)
        {
            //自由模式
            PlayerPrefs.SetInt("border", 0);
        }
    }

    public void StartGame()
    {
        UnityEngine.SceneManagement.SceneManager.LoadScene(1);
    }
}
StartUIController.cs

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class MainUIController : MonoBehaviour {

    //單例模式
    private static MainUIController _instance;
    public static MainUIController Instance
    {
        get
        {
            return _instance;
        }
    }

    public int score = 0;
    public int length = 0;
    public Text msgText;
    public Text scoreText;
    public Text lengthText;
    public Image bgImage;
    private Color tempColor;

    public Image pauseImage;
    public Sprite[] pauseSprites;
    public bool isPause = false ;
    public bool hasBorder = true;

    void Awake()
    {
        _instance = this;    
    }

    void Start()
    {
        if (PlayerPrefs.GetInt("border", 1)==0)
        {
            hasBorder = false;
            //取消邊界上的顏色
            foreach(Transform t in bgImage.gameObject.transform)
            {
                t.gameObject.GetComponent<Image>().enabled = false;
            }
        }
    }

    private void Update()
    {
        switch (score / 100)
        {
            case 0:
            case 1:
            case 2:
                break;
            case 3:
            case 4:
                ColorUtility.TryParseHtmlString("#CCEEFFFF",out tempColor);
                bgImage.color=tempColor;
                msgText.text = "階段" + 2;
                break;
            case 5:
            case 6:
                ColorUtility.TryParseHtmlString("#CCEEFFFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段" + 3;
                break;
            case 7:
            case 8:
                ColorUtility.TryParseHtmlString("#CCFFDBFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段" + 4;
                break;
            case 9:
            case 10:
                ColorUtility.TryParseHtmlString("#EBFFCCFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段" + 5;
                break;
            case 11:
            case 12:
            case 13:
                ColorUtility.TryParseHtmlString("#FFDACCFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段 x";
                break;
        }
    }

    public void UpdateUI(int s = 5,int l = 1)
    {
        score += s;
        length += l;
        scoreText.text ="得分:\n"+score;
        lengthText.text = "長度\n" + length;
    }

    public void Pause()
    {
        isPause = !isPause;
        if(isPause)
        {
            Time.timeScale = 0;
            pauseImage.sprite = pauseSprites[1];
        }
        else
        {
            Time.timeScale = 1;
            pauseImage.sprite = pauseSprites[0];
        }
    }
}
MainUIController.cs

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class FoodMaker : MonoBehaviour {

    //單例模式
    private static FoodMaker _instance;
    public static FoodMaker Instance
    {
        get
        {
            return _instance;
        }
    }
    public int xlimit = 18;
    public int ylimit = 9;
    //x軸活動空間不對稱問題,對x軸的偏移值
    public int xoffset = 10;
    public GameObject foodPrefab;
    public GameObject rewardPrefab;
    public Sprite[] foodSprites;
    private Transform foodHolder;

    private void Awake()
    {
        _instance = this;
    }

    private void Start()
    {
        foodHolder = GameObject.Find("FoodHolder").transform;
        MakeFood(false);
    }

    public void MakeFood(bool isReward)
    {
        int index = Random.Range(0,foodSprites.Length);
        GameObject food = Instantiate(foodPrefab);
        food.GetComponent<Image>().sprite = foodSprites[index];
        food.transform.SetParent(foodHolder,false);
        int x = Random.Range(-xlimit + xoffset,xlimit);
        int y = Random.Range(-ylimit,ylimit);
        food.transform.localPosition = new Vector3(x * 20, y * 20, 0);
        //food.transform.localPosition = new Vector3( x,  y, 0);
        if(isReward==true)
        {
            GameObject reward = Instantiate(rewardPrefab);
            reward.transform.SetParent(foodHolder, false);
            x = Random.Range(-xlimit + xoffset, xlimit);
            y = Random.Range(-ylimit, ylimit);
            reward.transform.localPosition = new Vector3(x * 20, y * 20, 0);
        }
    }

    public void Home()
    {
        UnityEngine.SceneManagement.SceneManager.LoadScene(0);
    }
}
FoodMaker.cs

 

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

public class SnakeHead : MonoBehaviour {

    public List<Transform> bodyList = new List<Transform>();
    public float velocity=0.35f;
    public int step;
    private int x;
    private int y;
    private Vector3 headPos;
    private Transform canvas;
    private bool isDie = false;

    public GameObject dieEffect;
    public GameObject bodyPrefab;
    public Sprite[] bodySprites = new Sprite[2];



    private void Awake()
    {
        canvas = GameObject.Find("Canvas").transform;
        //通過Resources.Load(string path)方法加載資源;
        gameObject.GetComponent<Image>().sprite = Resources.Load<Sprite>(PlayerPrefs.GetString("sh", "sh02"));
        bodySprites[0]  = Resources.Load<Sprite>(PlayerPrefs.GetString("sb01", "sb0201"));
        bodySprites[1]  = Resources.Load<Sprite>(PlayerPrefs.GetString("sb02", "sb0202"));
    }

    private void Start()
    {
        //重復調用
        InvokeRepeating("Move",0,velocity);
        x = 0;y = step;
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space)&&MainUIController.Instance.isPause==false&&isDie==false)
        {
            CancelInvoke();
            InvokeRepeating("Move",0,velocity - 0.3f);
        }

        if (Input.GetKeyUp(KeyCode.Space) && MainUIController.Instance.isPause == false && isDie == false)
        {
            CancelInvoke();
            InvokeRepeating("Move", 0, velocity);
        }

        if (Input.GetKey(KeyCode.W) &&  y!=-step && MainUIController.Instance.isPause == false && isDie == false)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 0);
            x = 0;y = step;
        }
        if (Input.GetKey(KeyCode.S) &&  y!=step && MainUIController.Instance.isPause == false && isDie == false)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 180);
            x = 0;y = -step;
        }
        if (Input.GetKey(KeyCode.A) && x!=step && MainUIController.Instance.isPause == false && isDie == false)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 90);
            x = -step;y = 0;
        }
        if (Input.GetKey(KeyCode.D) &&  x!=-step && MainUIController.Instance.isPause == false && isDie == false)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, -90);
            x = step;y = 0;
        }
    }

    void Move()
    {
        //保存下來蛇頭移動前的位置
        headPos = gameObject.transform.localPosition;
        //蛇頭向期望位置移動
        gameObject.transform.localPosition = new Vector3(headPos.x+x,headPos.y+y,headPos.z);
        if (bodyList.Count > 0)
        {
            //由於是雙色蛇身,此方法棄用
            //將蛇尾移動到蛇頭移動前的位置
           // bodyList.Last().localPosition = headPos;
           //將蛇尾在List中的位置跟新到最前
           // bodyList.Insert(0, bodyList.Last());
           //溢出List最末尾的蛇尾引用
           // bodyList.RemoveAt(bodyList.Count - 1);

            //從后面開始移動蛇身
            for(int i =bodyList.Count-2;i>=0 ;i--)
            {
                //每一個蛇身都移動到它前面一個
                bodyList[i + 1].localPosition = bodyList[i].localPosition;
            }
            //第一個蛇身移動到蛇頭移動前的位置
            bodyList[0].localPosition = headPos;

        }
    }

    void Grow()
    {
        int index = (bodyList.Count % 2 == 0) ? 0 : 1;
        GameObject body = Instantiate(bodyPrefab,new Vector3(200000,2000000,0),Quaternion.identity);
        body.GetComponent<Image>().sprite = bodySprites[index];
        body.transform.SetParent(canvas, false);
        bodyList.Add(body.transform);
    }

    void Die()
    {
        CancelInvoke();
        isDie = true;
        Instantiate(dieEffect);
        //記錄游戲的最后長度
        PlayerPrefs.SetInt("last1",MainUIController.Instance.length);
        PlayerPrefs.SetInt("lasts", MainUIController.Instance.score);
        //當游戲長度大於最高得分時
        if (PlayerPrefs.GetInt("bests", 0)<MainUIController.Instance.score)
        {
            //將當前游戲長度和分數記錄到best1和bests當中
            PlayerPrefs.SetInt("best1", MainUIController.Instance.length);
            PlayerPrefs.SetInt("bests", MainUIController.Instance.score);
        }
        StartCoroutine(GameOver(1.0f));
    }

    IEnumerator GameOver(float t)
    {
        yield return new WaitForSeconds(t);
        UnityEngine.SceneManagement.SceneManager.LoadScene(1);
    }


    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("Food"))
        {
            Destroy(collision.gameObject);
            MainUIController.Instance.UpdateUI();
            Grow();
            if (Random.Range(0,100)<20)
            {
                FoodMaker.Instance.MakeFood(true);
            }
            else
            {
                FoodMaker.Instance.MakeFood(false);
            }
        }
        else if(collision.gameObject.CompareTag("Reward"))
        {
            Destroy(collision.gameObject);
            MainUIController.Instance.UpdateUI(Random.Range(5,15)*10);
            Grow();
        }
        else if(collision.gameObject.CompareTag("Body"))
        {
            Die();
        }
        else
        {
            if (MainUIController.Instance.hasBorder)
            {
                Die();
            }
            else
            {
                switch (collision.gameObject.name)
                {
                    case "Up":
                        transform.localPosition = new Vector3(transform.localPosition.x, -transform.localPosition.y + 20, transform.localPosition.z);
                        break;
                    case "Down":
                        transform.localPosition = new Vector3(transform.localPosition.x, -transform.localPosition.y - 20, transform.localPosition.z);
                        break;
                    case "Left":
                        transform.localPosition = new Vector3(-transform.localPosition.x + 140, transform.localPosition.y, transform.localPosition.z);
                        break;
                    case "Right":
                        transform.localPosition = new Vector3(-transform.localPosition.x + 170, transform.localPosition.y, transform.localPosition.z);
                        break;
                }
            }
        }
    }

}
SnakeHead.cs

 

 

添加游戲音樂

 

  Main場景攝像機上綁定一個Audio Source音樂播放器

 

  吃到東西和游戲結束時分別播放兩個不同的音樂

    public AudioClip eatClip;
    public AudioClip dieClip;

 

  

void Grow()
    {
        //播放貪吃蛇變長音樂
        AudioSource.PlayClipAtPoint(eatClip,Vector3.zero);
        int index = (bodyList.Count % 2 == 0) ? 0 : 1;
        GameObject body = Instantiate(bodyPrefab,new Vector3(200000,2000000,0),Quaternion.identity);
        body.GetComponent<Image>().sprite = bodySprites[index];
        body.transform.SetParent(canvas, false);
        bodyList.Add(body.transform);
    }

    void Die()
    {
        //播放死亡音樂
        AudioSource.PlayClipAtPoint(dieClip, Vector3.zero);
        CancelInvoke();
        isDie = true;
        Instantiate(dieEffect);
        //記錄游戲的最后長度
        PlayerPrefs.SetInt("last1",MainUIController.Instance.length);
        PlayerPrefs.SetInt("lasts", MainUIController.Instance.score);
        //當游戲長度大於最高得分時
        if (PlayerPrefs.GetInt("bests", 0)<MainUIController.Instance.score)
        {
            //將當前游戲長度和分數記錄到best1和bests當中
            PlayerPrefs.SetInt("best1", MainUIController.Instance.length);
            PlayerPrefs.SetInt("bests", MainUIController.Instance.score);
        }
        StartCoroutine(GameOver(1.0f));
    }

 

  

 

 

 

游戲源代碼

 

  控制蛇和食物腳本

 

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

public class SnakeHead : MonoBehaviour {

    public List<Transform> bodyList = new List<Transform>();
    public float velocity=0.35f;
    public int step;
    private int x;
    private int y;
    private Vector3 headPos;
    private Transform canvas;
    private bool isDie = false;

    public AudioClip eatClip;
    public AudioClip dieClip;
    public GameObject dieEffect;
    public GameObject bodyPrefab;
    public Sprite[] bodySprites = new Sprite[2];



    private void Awake()
    {
        canvas = GameObject.Find("Canvas").transform;
        //通過Resources.Load(string path)方法加載資源;
        gameObject.GetComponent<Image>().sprite = Resources.Load<Sprite>(PlayerPrefs.GetString("sh", "sh02"));
        bodySprites[0]  = Resources.Load<Sprite>(PlayerPrefs.GetString("sb01", "sb0201"));
        bodySprites[1]  = Resources.Load<Sprite>(PlayerPrefs.GetString("sb02", "sb0202"));
    }

    private void Start()
    {
        //重復調用
        InvokeRepeating("Move",0,velocity);
        x = 0;y = step;
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space)&&MainUIController.Instance.isPause==false&&isDie==false)
        {
            CancelInvoke();
            InvokeRepeating("Move",0,velocity - 0.3f);
        }

        if (Input.GetKeyUp(KeyCode.Space) && MainUIController.Instance.isPause == false && isDie == false)
        {
            CancelInvoke();
            InvokeRepeating("Move", 0, velocity);
        }

        if (Input.GetKey(KeyCode.W) &&  y!=-step && MainUIController.Instance.isPause == false && isDie == false)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 0);
            x = 0;y = step;
        }
        if (Input.GetKey(KeyCode.S) &&  y!=step && MainUIController.Instance.isPause == false && isDie == false)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 180);
            x = 0;y = -step;
        }
        if (Input.GetKey(KeyCode.A) && x!=step && MainUIController.Instance.isPause == false && isDie == false)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, 90);
            x = -step;y = 0;
        }
        if (Input.GetKey(KeyCode.D) &&  x!=-step && MainUIController.Instance.isPause == false && isDie == false)
        {
            gameObject.transform.localRotation = Quaternion.Euler(0, 0, -90);
            x = step;y = 0;
        }
    }

    void Move()
    {
        //保存下來蛇頭移動前的位置
        headPos = gameObject.transform.localPosition;
        //蛇頭向期望位置移動
        gameObject.transform.localPosition = new Vector3(headPos.x+x,headPos.y+y,headPos.z);
        if (bodyList.Count > 0)
        {
            //由於是雙色蛇身,此方法棄用
            //將蛇尾移動到蛇頭移動前的位置
           // bodyList.Last().localPosition = headPos;
           //將蛇尾在List中的位置跟新到最前
           // bodyList.Insert(0, bodyList.Last());
           //溢出List最末尾的蛇尾引用
           // bodyList.RemoveAt(bodyList.Count - 1);

            //從后面開始移動蛇身
            for(int i =bodyList.Count-2;i>=0 ;i--)
            {
                //每一個蛇身都移動到它前面一個
                bodyList[i + 1].localPosition = bodyList[i].localPosition;
            }
            //第一個蛇身移動到蛇頭移動前的位置
            bodyList[0].localPosition = headPos;

        }
    }

    void Grow()
    {
        //播放貪吃蛇變長音樂
        AudioSource.PlayClipAtPoint(eatClip,Vector3.zero);
        int index = (bodyList.Count % 2 == 0) ? 0 : 1;
        GameObject body = Instantiate(bodyPrefab,new Vector3(200000,2000000,0),Quaternion.identity);
        body.GetComponent<Image>().sprite = bodySprites[index];
        body.transform.SetParent(canvas, false);
        bodyList.Add(body.transform);
    }

    void Die()
    {
        //播放死亡音樂
        AudioSource.PlayClipAtPoint(dieClip, Vector3.zero);
        CancelInvoke();
        isDie = true;
        Instantiate(dieEffect);
        //記錄游戲的最后長度
        PlayerPrefs.SetInt("last1",MainUIController.Instance.length);
        PlayerPrefs.SetInt("lasts", MainUIController.Instance.score);
        //當游戲長度大於最高得分時
        if (PlayerPrefs.GetInt("bests", 0)<MainUIController.Instance.score)
        {
            //將當前游戲長度和分數記錄到best1和bests當中
            PlayerPrefs.SetInt("best1", MainUIController.Instance.length);
            PlayerPrefs.SetInt("bests", MainUIController.Instance.score);
        }
        StartCoroutine(GameOver(1.0f));
    }

    IEnumerator GameOver(float t)
    {
        yield return new WaitForSeconds(t);
        UnityEngine.SceneManagement.SceneManager.LoadScene(1);
    }


    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("Food"))
        {
            Destroy(collision.gameObject);
            MainUIController.Instance.UpdateUI();
            Grow();
            if (Random.Range(0,100)<20)
            {
                FoodMaker.Instance.MakeFood(true);
            }
            else
            {
                FoodMaker.Instance.MakeFood(false);
            }
        }
        else if(collision.gameObject.CompareTag("Reward"))
        {
            Destroy(collision.gameObject);
            MainUIController.Instance.UpdateUI(Random.Range(5,15)*10);
            Grow();
        }
        else if(collision.gameObject.CompareTag("Body"))
        {
            Die();
        }
        else
        {
            if (MainUIController.Instance.hasBorder)
            {
                Die();
            }
            else
            {
                switch (collision.gameObject.name)
                {
                    case "Up":
                        transform.localPosition = new Vector3(transform.localPosition.x, -transform.localPosition.y + 20, transform.localPosition.z);
                        break;
                    case "Down":
                        transform.localPosition = new Vector3(transform.localPosition.x, -transform.localPosition.y - 20, transform.localPosition.z);
                        break;
                    case "Left":
                        transform.localPosition = new Vector3(-transform.localPosition.x + 140, transform.localPosition.y, transform.localPosition.z);
                        break;
                    case "Right":
                        transform.localPosition = new Vector3(-transform.localPosition.x + 170, transform.localPosition.y, transform.localPosition.z);
                        break;
                }
            }
        }
    }

}
SnakeHead.cs

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class FoodMaker : MonoBehaviour {

    //單例模式
    private static FoodMaker _instance;
    public static FoodMaker Instance
    {
        get
        {
            return _instance;
        }
    }
    public int xlimit = 18;
    public int ylimit = 9;
    //x軸活動空間不對稱問題,對x軸的偏移值
    public int xoffset = 10;
    public GameObject foodPrefab;
    public GameObject rewardPrefab;
    public Sprite[] foodSprites;
    private Transform foodHolder;

    private void Awake()
    {
        _instance = this;
    }

    private void Start()
    {
        foodHolder = GameObject.Find("FoodHolder").transform;
        MakeFood(false);
    }

    public void MakeFood(bool isReward)
    {
        int index = Random.Range(0,foodSprites.Length);
        GameObject food = Instantiate(foodPrefab);
        food.GetComponent<Image>().sprite = foodSprites[index];
        food.transform.SetParent(foodHolder,false);
        int x = Random.Range(-xlimit + xoffset,xlimit);
        int y = Random.Range(-ylimit,ylimit);
        food.transform.localPosition = new Vector3(x * 20, y * 20, 0);
        //food.transform.localPosition = new Vector3( x,  y, 0);
        if(isReward==true)
        {
            GameObject reward = Instantiate(rewardPrefab);
            reward.transform.SetParent(foodHolder, false);
            x = Random.Range(-xlimit + xoffset, xlimit);
            y = Random.Range(-ylimit, ylimit);
            reward.transform.localPosition = new Vector3(x * 20, y * 20, 0);
        }
    }

    public void Home()
    {
        UnityEngine.SceneManagement.SceneManager.LoadScene(0);
    }
}
FoodMaker.cs

 

 

  場景UI控制腳本 

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class MainUIController : MonoBehaviour {

    //單例模式
    private static MainUIController _instance;
    public static MainUIController Instance
    {
        get
        {
            return _instance;
        }
    }

    public int score = 0;
    public int length = 0;
    public Text msgText;
    public Text scoreText;
    public Text lengthText;
    public Image bgImage;
    private Color tempColor;

    public Image pauseImage;
    public Sprite[] pauseSprites;
    public bool isPause = false ;
    public bool hasBorder = true;

    void Awake()
    {
        _instance = this;    
    }

    void Start()
    {
        if (PlayerPrefs.GetInt("border", 1)==0)
        {
            hasBorder = false;
            //取消邊界上的顏色
            foreach(Transform t in bgImage.gameObject.transform)
            {
                t.gameObject.GetComponent<Image>().enabled = false;
            }
        }
    }

    private void Update()
    {
        switch (score / 100)
        {
            case 0:
            case 1:
            case 2:
                break;
            case 3:
            case 4:
                ColorUtility.TryParseHtmlString("#CCEEFFFF",out tempColor);
                bgImage.color=tempColor;
                msgText.text = "階段" + 2;
                break;
            case 5:
            case 6:
                ColorUtility.TryParseHtmlString("#CCEEFFFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段" + 3;
                break;
            case 7:
            case 8:
                ColorUtility.TryParseHtmlString("#CCFFDBFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段" + 4;
                break;
            case 9:
            case 10:
                ColorUtility.TryParseHtmlString("#EBFFCCFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段" + 5;
                break;
            case 11:
            case 12:
            case 13:
                ColorUtility.TryParseHtmlString("#FFDACCFF", out tempColor);
                bgImage.color = tempColor;
                msgText.text = "階段 x";
                break;
        }
    }

    public void UpdateUI(int s = 5,int l = 1)
    {
        score += s;
        length += l;
        scoreText.text ="得分:\n"+score;
        lengthText.text = "長度\n" + length;
    }

    public void Pause()
    {
        isPause = !isPause;
        if(isPause)
        {
            Time.timeScale = 0;
            pauseImage.sprite = pauseSprites[1];
        }
        else
        {
            Time.timeScale = 1;
            pauseImage.sprite = pauseSprites[0];
        }
    }
}
MainUIController.cs

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class StartUIController : MonoBehaviour {

    public Text lastText;
    public Text bestText;
    public Toggle blue;
    public Toggle yellow;
    public Toggle border;
    public Toggle noborder;

    private void Awake()
    {
        lastText.text = "上次:長度" + PlayerPrefs.GetInt("last1",0)  + ",分數" + PlayerPrefs.GetInt("lasts",0);
        bestText.text = "最好:長度" + PlayerPrefs.GetInt("best1", 0) + ",分數" + PlayerPrefs.GetInt("bests",0);
    }

    private void Start()
    {
        if (PlayerPrefs.GetString("sh", "sh01") == "sh01")
        {
            blue.isOn = true;
            PlayerPrefs.SetString("sh", "sh01");
            PlayerPrefs.SetString("sb01", "sb0101");
            PlayerPrefs.SetString("sb02", "sb0102");
        }
        else
        {
            yellow.isOn = true;
            PlayerPrefs.SetString("sh", "sh02");
            PlayerPrefs.SetString("sb01", "sb0201");
            PlayerPrefs.SetString("sb02", "sb0202");
        }
        if (PlayerPrefs.GetInt("border", 1) == 1)
        {
            border.isOn = true;
            PlayerPrefs.SetInt("border",1);
        }
        else
        {
            noborder.isOn = true;
            PlayerPrefs.SetInt("border", 0);
        }
    }

    public void BlueSelected(bool isOn)
    {
        if (isOn)
        {
            PlayerPrefs.SetString("sh", "sh01");
            PlayerPrefs.SetString("sb01", "sb0101");
            PlayerPrefs.SetString("sb02", "sb0102");
        }
    }
       
    public void YellowSelected(bool isOn)
    {
        if (isOn)
        {
            PlayerPrefs.SetString("sh", "sh02");
            PlayerPrefs.SetString("sb01", "sb0201");
            PlayerPrefs.SetString("sb02", "sb0202");
        }
    }

    public void BorderSelected(bool isOn)
    {
        if (isOn)
        {
            PlayerPrefs.SetInt("border",1);
        }
    }

    public void NoBorderSelected(bool isOn)
    {
        if (isOn)
        {
            //自由模式
            PlayerPrefs.SetInt("border", 0);
        }
    }

    public void StartGame()
    {
        UnityEngine.SceneManagement.SceneManager.LoadScene(1);
    }
}
StartUIController.cs

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM