效果图:

思路:贪吃蛇的玩法核心是玩家控制一个方块 去吃另一个方块,吃掉的方块变成自己的身体跟随上一个方块移动,吃的越多速度越快,游戏结束判断是否撞到墙壁或者撞到自己的身体

一、场景布局

1.相机设置

修改相机参数 :ClearFlags 设置为SolidColor 让我们游戏中的场景纯颜色显示 ,Projection设置为Orthographic 正交相机 , size  设置相机视角的大小

2.场景设置

设置游戏背景图、四面的墙壁、贪吃蛇的蛇头和食物的组件及属性,还有一个游戏失败和显示分数的UI界面

①背景图:新建2D Object-->Sprite 取名GameBG 设置图片精灵 调整scale大小为30*30 作

 围墙Wall :设置Tag标签为Wall(用于判断撞到墙死亡)设置碰撞盒, 复制三个围墙调整大小位置

②贪吃蛇的蛇头 SnakePlayer 添加刚体Rigidbody2D和BoxColider2D组件,这里注意将2D刚体组件的Gravity Scale重力规模设置为0 (平面移动不需要重力) ,调整位置xy为0.5(为啥要调整为0.5 下面会有解释说明)

 创建食物 :FoodPool当作食物存放的对象池,创建食物添加BoxColider2D组件 设置Tag为Food(用于碰撞检测),与蛇头一样调整位置xy为0.5

为什么蛇头和食物要设置position位置为0.5?

因为我们创建的蛇和食物都是scale为1*1的矩形 我们移动的位置想要它跟场景方块对其 需要设置其初始位置为0.5(即:scale/2 大小的一半),其实也可以不用设置 小编有点强迫症对其好看就,嘿嘿......

 ④设置UI界面

创建空物体UIManager当作节点容器 存放组件,左上角Text为分数,RefreshPanel游戏失败背景UI 新建一个Text作为游戏失败文字, 一个Button作为重新开始按钮。

二、功能实现

1.首先制作蛇的移动功能,新建脚本PlayerMovement.cs 贪吃蛇的所有功能都放在这个脚本中

贪吃蛇功能:

①蛇的移动是自动的 我们只需要控制蛇的左右或上下移动的方向即可,

②蛇在往左(或往下)移动时 ,我们不能操作蛇往右(或往左)移动。

③蛇头在触发了食物时吃掉食物,触发了墙或自己的身体时游戏结束

了解了移动方式那我们开始编写功能吧。

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

//方向类型
public enum DirectionType
{
    Horizontal, Vertical
}

public class PlayerMovement : MonoBehaviour
{
    public static Vector3 direction = new Vector3(1, 0, 0);//移动方向
    public float currentTimespeed; //当前移动速度时间(时间越小 速度越快 这里我通过时间来加快速度)
    public float timerSpeedRatio;//每次吃到食物所减去的时间(即:贪吃蛇加速)
    float timer;//用于时间计算

    bool isDie = false;//是否死亡
    int foodnumber = 0;//吃掉的食物数量

    //食物 食物对象池 
    public FoodData foodPrefab;
    public Transform foodPool;
    //贪吃蛇容器 用于存储吃掉的食物变成的身体
    public Transform snakePool;


    //游戏地图
    public Transform GameBG;

    void Start()
    {
        //初始化timer
        timer = currentTimespeed;
        //初始化位置
        transform.position = new Vector3(0.5f, 0.5f, 1);
    }

    void Update()
    {
        //玩家移动
        float h = Input.GetAxis("Horizontal");
        float V = Input.GetAxis("Vertical");

        //判断移动方向
        if (h != 0)
        {
            SetDirection(DirectionType.Horizontal, h);
        }
        if (V != 0)
        {
            SetDirection(DirectionType.Vertical, V);
        }

        //未死亡 执行移动
        if (!isDie)
        {
            Move();
        }
    }

    //修改方向
    private void SetDirection(DirectionType directionType, float _direction)
    {
        //判断水平的左右移动 或 垂直的上下移动
        float value = _direction > 0 ? 1f : -1f;

        //判断方向类型  设置移动方向 
        switch (directionType)
        {
            case DirectionType.Horizontal:
                if (direction.x==0)
                {
                    direction = new Vector2(value, 0);
                }
                break;
            case DirectionType.Vertical:
                if (direction.y==0)
                {
                    direction = new Vector2(0, value);
                }
                break;
            default:
                break;
        }
    }

    //移动
    private void Move()
    {
        timer -= Time.deltaTime;
        if (timer < 0)
        {
            //执行移动
            GetComponent<FoodData>().Move(transform.position + direction);
            timer = currentTimespeed;
        }
    }

    //检测(需要 FoodData和UIManager脚本)
    void OnTriggerEnter2D(Collider2D col)
    {
        //判断是否触发了墙或者是自己
        if (col.transform.tag.Equals("Wall") || col.transform.tag.Equals("Player"))
        {
            //死亡
            isDie = true;
            UIManager.uiMagr.DieUI();
        }

        //食物
        if (col.transform.tag.Equals("Food"))
        {
            //判断贪吃蛇有没有身体
            if (snakePool.childCount > 0)
            {
                col.transform.GetComponent<FoodData>().SetDataInt(snakePool.GetChild(snakePool.childCount - 1).GetComponent<FoodData>());
            }

            if (snakePool.childCount <= 0)
            {
                col.transform.GetComponent<FoodData>().SetDataInt(GetComponent<FoodData>());
            }
            col.transform.SetParent(snakePool);
            if (col.transform== snakePool.GetChild(0))
            {
                col.transform.tag = "Untagged";
            }
            else
            {
                col.transform.tag = "Player";
            }

            //创建食物
            CreatFood();
            //加速
            currentTimespeed -= timerSpeedRatio;
            if (currentTimespeed<=0.1f)
            {
                currentTimespeed = 0.1f;
            }
            //UI
            foodnumber++;
            UIManager.uiMagr.SetNumber(foodnumber);
        }

       
    }

    //创建食物
    public void CreatFood()
    {
        //基础值
        float basePos = 0.5f;
        int h_value = (int)(GameBG.localScale.x / 2);
        int v_value = (int)(GameBG.localScale.y / 2);
        int h = Random.Range(-h_value, h_value + 1);
        int v = Random.Range(-v_value, v_value + 1);

        Vector2 pos = new Vector2(h + 0.5f, v + 0.5f);
        if (pos.x > 15)
        {
            pos = new Vector2(h_value - 0.5f, pos.y);
        }
        if (pos.y > 15)
        {
            pos = new Vector2(pos.x, v_value - 0.5f);
        }

        GetFood(0).position = pos;
    }

    //获取食物
    public Transform GetFood(int index)
    {
        Transform food;
        if (index <= foodPool.childCount)
        {
            food = Instantiate(foodPrefab.transform, foodPool);
        }
        else
        {
            food = foodPool.GetChild(index);
        }
        return food;
    }

}

 代码中有详细的解释,直接复制代码会出现问题,原因是需要FoodData.cs和UIManager.cs脚本中的方法.

 设置贪吃蛇的初始属性

2.创建食物(和身体)属性脚本FoodData   将脚本拖给给SnakePlayer和food

这个食物脚本,在被蛇吃掉之后变成蛇的身体。

功能介绍:

①基础属性 移动前的位置信息,上一级物体,下一级物体。

②当食物被吃掉时,要获取蛇的最后一个身体,当作自己的上一级,上一级移动后,下一级移动到上一级移动前的位置

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

public class FoodData : MonoBehaviour
{
    public Vector3 oldPos;//记录上一次移动
    public FoodData parentObj;//获取身体部位的上一个身体部位属性(用于贪吃蛇移动时,下一个方块移动到上一个方块的位置)
    public FoodData newObj;//记录下一个身体部位属性(用于当前身体移动后 调用下一个物体的移动方法)
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    //获取上一个物体(食物被吃掉时调用)
    public void SetDataInt(FoodData obj) 
    {
        parentObj = obj;
        //设置上一个物体的newobj为自己
        parentObj.newObj = this;
        //食物被吃掉变成白色
        transform.GetComponent<SpriteRenderer>().color = Color.white;
        //位置初始化
        transform.position = parentObj.oldPos;
    }

    //移动 (用于当前物体移动完后执行下一个物体的移动)
    public void Move() 
    {
        //记录上一次移动位置(这个值 下一个物体移动时所需)
        oldPos=transform.position;

        //修改位置
        transform.position = parentObj.oldPos;

        //执行下一个物体的移动命令
        if (newObj!=null)
        {
            newObj.Move();
        }
    }

    //移动(蛇的头部移动 需要传参)
    public void Move(Vector3 pos) 
    {
        oldPos = transform.position;
        //修改位置
        transform.position = pos;

        if (newObj != null)
        {
            newObj.Move();
        }
    }
}

3.脚本UIManager.cs 拖给空物体UIManager

using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
using UnityEngine.SceneManagement;//加载场景时需引用

public class UIManager : MonoBehaviour
{
    public static UIManager uiMagr;
    public Text number_txt;//分数
    public Button refreshBtn;//重新开始按钮
    public Transform dieUI;//游戏失败面板

    void Start()
    {
        //初始化
        uiMagr = this;
        dieUI.gameObject.SetActive(false);
        refreshBtn.onClick.AddListener(Refresh);
    }

    // Update is called once per frame
    void Update()
    {
        //按下esc 退出程序
        if (Input.GetKeyDown(KeyCode.Escape))
        {
            Application.Quit();
        }
    }

    //修改分数值
    public void SetNumber(int value) 
    {
        number_txt.text = value.ToString();
    }

    //显示死亡UI
    public void DieUI() 
    {
        dieUI.gameObject.SetActive(true);
    }

    //刷新
    void Refresh() 
    {
        //重新加载场景
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
    }
}

链接:https://pan.baidu.com/s/1bGXUal8RIJBSb6oFq4zHPA 
提取码:syq1

Logo

苏州本地的技术开发者社区,在这里可以交流本地的好吃好玩的,可以交流技术,可以交流招聘等等,没啥限制。

更多推荐