Unity3D_(遊戲)貪吃蛇

 

 

Unity製做貪吃蛇小遊戲html

 

  玩家經過「WASD」控制小蛇上下左右移動,蛇頭撞倒食物,則食物被吃掉,蛇身體長一節,接着又出現食物,等待蛇來吃,若是蛇在移動中撞到牆或身體交叉蛇頭撞倒本身身體遊戲結束git

  可經過遊戲開始前對小蛇皮膚進行選擇github

  自由模式下蛇頭能夠穿過四周的牆canvas

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

 

  PlayerPrefs類存儲位置  傳送門ide

  Unity聖典  傳送門測試

  遊戲項目已託管到Github上  傳送門
動畫

 

 

遊戲展現this

 

對玩家的遊戲數據記錄spa

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

 

 

 

遊戲換膚

   爲玩家能夠選擇藍色小蛇或黃色小蛇

 

 

 

遊戲模式

  邊界模式下蛇撞到邊界斷定遊戲結束

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

 

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

 

  

 

 實現過程

 

製做開始場景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));
    }

 

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

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

  PlayerPrefs.SetInt(string key,Int value);

  PlayerPrefs.SetString(string key,string value);

二、讀取值:

  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
相關文章
相關標籤/搜索