Arzie100 发表于 2022-6-21 07:51

Unity制作贪吃蛇

效果图:


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

<div id="marketingBox" class="marketing-box"><div class="marketing-content">


开发者涨薪指南


48位大咖的思考法则、工作方式、逻辑体系
页: [1]
查看完整版本: Unity制作贪吃蛇