zoukankan      html  css  js  c++  java
  • 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 ="得分:
    "+score;
            lengthText.text = "长度
    " + 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 ="得分:
    "+score;
            lengthText.text = "长度
    " + 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 ="得分:
    "+score;
            lengthText.text = "长度
    " + 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 ="得分:
    "+score;
            lengthText.text = "长度
    " + 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 ="得分:
    "+score;
            lengthText.text = "长度
    " + 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
    (如需转载学习,请标明出处)
  • 相关阅读:
    WordPress怎么禁用古滕堡编辑器(Gutenberg)
    .Net Framework 4.0安装cmd命令
    Windows服务器一键要打开多个软件或一键关闭多个软件
    Photosho 切换英文版教程
    解决宝塔面板无法停止Tomcat方法
    只要系统镜像就能制作可启动安装系统U盘
    [网摘]分享一段流量劫持JS代码
    Script http跳https
    linux系统 标准目录及其内容
    centos7 永久修改主机名
  • 原文地址:https://www.cnblogs.com/1138720556Gary/p/9733959.html
Copyright © 2011-2022 走看看