找回密码
 立即注册
查看: 363|回复: 0

Unity制作贪吃蛇

[复制链接]
发表于 2022-6-21 07:51 | 显示全部楼层 |阅读模式
效果图:


思路:贪吃蛇的玩法核心是玩家控制一个方块 去吃另一个方块,吃掉的方块变成自己的身体跟随上一个方块移动,吃的越多速度越快,游戏结束判断是否撞到墙壁或者撞到自己的身体
一、场景布局
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 贪吃蛇的所有功能都放在这个脚本中
贪吃蛇功能:
①蛇的移动是自动的 我们只需要控制蛇的左右或上下移动的方向即可,
②蛇在往左(或往下)移动时 ,我们不能操作蛇往右(或往左)移动。
③蛇头在触发了食物时吃掉食物,触发了墙或自己的身体时游戏结束
了解了移动方式那我们开始编写功能吧。
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. //方向类型
  5. public enum DirectionType
  6. {
  7.     Horizontal, Vertical
  8. }
  9. public class PlayerMovement : MonoBehaviour
  10. {
  11.     public static Vector3 direction = new Vector3(1, 0, 0);//移动方向
  12.     public float currentTimespeed; //当前移动速度时间(时间越小 速度越快 这里我通过时间来加快速度)
  13.     public float timerSpeedRatio;//每次吃到食物所减去的时间(即:贪吃蛇加速)
  14.     float timer;//用于时间计算
  15.     bool isDie = false;//是否死亡
  16.     int foodnumber = 0;//吃掉的食物数量
  17.     //食物 食物对象池
  18.     public FoodData foodPrefab;
  19.     public Transform foodPool;
  20.     //贪吃蛇容器 用于存储吃掉的食物变成的身体
  21.     public Transform snakePool;
  22.     //游戏地图
  23.     public Transform GameBG;
  24.     void Start()
  25.     {
  26.         //初始化timer
  27.         timer = currentTimespeed;
  28.         //初始化位置
  29.         transform.position = new Vector3(0.5f, 0.5f, 1);
  30.     }
  31.     void Update()
  32.     {
  33.         //玩家移动
  34.         float h = Input.GetAxis("Horizontal");
  35.         float V = Input.GetAxis("Vertical");
  36.         //判断移动方向
  37.         if (h != 0)
  38.         {
  39.             SetDirection(DirectionType.Horizontal, h);
  40.         }
  41.         if (V != 0)
  42.         {
  43.             SetDirection(DirectionType.Vertical, V);
  44.         }
  45.         //未死亡 执行移动
  46.         if (!isDie)
  47.         {
  48.             Move();
  49.         }
  50.     }
  51.     //修改方向
  52.     private void SetDirection(DirectionType directionType, float _direction)
  53.     {
  54.         //判断水平的左右移动 或 垂直的上下移动
  55.         float value = _direction > 0 ? 1f : -1f;
  56.         //判断方向类型  设置移动方向
  57.         switch (directionType)
  58.         {
  59.             case DirectionType.Horizontal:
  60.                 if (direction.x==0)
  61.                 {
  62.                     direction = new Vector2(value, 0);
  63.                 }
  64.                 break;
  65.             case DirectionType.Vertical:
  66.                 if (direction.y==0)
  67.                 {
  68.                     direction = new Vector2(0, value);
  69.                 }
  70.                 break;
  71.             default:
  72.                 break;
  73.         }
  74.     }
  75.     //移动
  76.     private void Move()
  77.     {
  78.         timer -= Time.deltaTime;
  79.         if (timer < 0)
  80.         {
  81.             //执行移动
  82.             GetComponent<FoodData>().Move(transform.position + direction);
  83.             timer = currentTimespeed;
  84.         }
  85.     }
  86.     //检测(需要 FoodData和UIManager脚本)
  87.     void OnTriggerEnter2D(Collider2D col)
  88.     {
  89.         //判断是否触发了墙或者是自己
  90.         if (col.transform.tag.Equals("Wall") || col.transform.tag.Equals("Player"))
  91.         {
  92.             //死亡
  93.             isDie = true;
  94.             UIManager.uiMagr.DieUI();
  95.         }
  96.         //食物
  97.         if (col.transform.tag.Equals("Food"))
  98.         {
  99.             //判断贪吃蛇有没有身体
  100.             if (snakePool.childCount > 0)
  101.             {
  102.                 col.transform.GetComponent<FoodData>().SetDataInt(snakePool.GetChild(snakePool.childCount - 1).GetComponent<FoodData>());
  103.             }
  104.             if (snakePool.childCount <= 0)
  105.             {
  106.                 col.transform.GetComponent<FoodData>().SetDataInt(GetComponent<FoodData>());
  107.             }
  108.             col.transform.SetParent(snakePool);
  109.             if (col.transform== snakePool.GetChild(0))
  110.             {
  111.                 col.transform.tag = "Untagged";
  112.             }
  113.             else
  114.             {
  115.                 col.transform.tag = "Player";
  116.             }
  117.             //创建食物
  118.             CreatFood();
  119.             //加速
  120.             currentTimespeed -= timerSpeedRatio;
  121.             if (currentTimespeed<=0.1f)
  122.             {
  123.                 currentTimespeed = 0.1f;
  124.             }
  125.             //UI
  126.             foodnumber++;
  127.             UIManager.uiMagr.SetNumber(foodnumber);
  128.         }
  129.       
  130.     }
  131.     //创建食物
  132.     public void CreatFood()
  133.     {
  134.         //基础值
  135.         float basePos = 0.5f;
  136.         int h_value = (int)(GameBG.localScale.x / 2);
  137.         int v_value = (int)(GameBG.localScale.y / 2);
  138.         int h = Random.Range(-h_value, h_value + 1);
  139.         int v = Random.Range(-v_value, v_value + 1);
  140.         Vector2 pos = new Vector2(h + 0.5f, v + 0.5f);
  141.         if (pos.x > 15)
  142.         {
  143.             pos = new Vector2(h_value - 0.5f, pos.y);
  144.         }
  145.         if (pos.y > 15)
  146.         {
  147.             pos = new Vector2(pos.x, v_value - 0.5f);
  148.         }
  149.         GetFood(0).position = pos;
  150.     }
  151.     //获取食物
  152.     public Transform GetFood(int index)
  153.     {
  154.         Transform food;
  155.         if (index <= foodPool.childCount)
  156.         {
  157.             food = Instantiate(foodPrefab.transform, foodPool);
  158.         }
  159.         else
  160.         {
  161.             food = foodPool.GetChild(index);
  162.         }
  163.         return food;
  164.     }
  165. }
复制代码
代码中有详细的解释,直接复制代码会出现问题,原因是需要FoodData.cs和UIManager.cs脚本中的方法.
设置贪吃蛇的初始属性


2.创建食物(和身体)属性脚本FoodData   将脚本拖给给SnakePlayer和food
这个食物脚本,在被蛇吃掉之后变成蛇的身体。
功能介绍:
①基础属性 移动前的位置信息,上一级物体,下一级物体。
②当食物被吃掉时,要获取蛇的最后一个身体,当作自己的上一级,上一级移动后,下一级移动到上一级移动前的位置
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class FoodData : MonoBehaviour
  5. {
  6.     public Vector3 oldPos;//记录上一次移动
  7.     public FoodData parentObj;//获取身体部位的上一个身体部位属性(用于贪吃蛇移动时,下一个方块移动到上一个方块的位置)
  8.     public FoodData newObj;//记录下一个身体部位属性(用于当前身体移动后 调用下一个物体的移动方法)
  9.     void Start()
  10.     {
  11.         
  12.     }
  13.     // Update is called once per frame
  14.     void Update()
  15.     {
  16.         
  17.     }
  18.     //获取上一个物体(食物被吃掉时调用)
  19.     public void SetDataInt(FoodData obj)
  20.     {
  21.         parentObj = obj;
  22.         //设置上一个物体的newobj为自己
  23.         parentObj.newObj = this;
  24.         //食物被吃掉变成白色
  25.         transform.GetComponent<SpriteRenderer>().color = Color.white;
  26.         //位置初始化
  27.         transform.position = parentObj.oldPos;
  28.     }
  29.     //移动 (用于当前物体移动完后执行下一个物体的移动)
  30.     public void Move()
  31.     {
  32.         //记录上一次移动位置(这个值 下一个物体移动时所需)
  33.         oldPos=transform.position;
  34.         //修改位置
  35.         transform.position = parentObj.oldPos;
  36.         //执行下一个物体的移动命令
  37.         if (newObj!=null)
  38.         {
  39.             newObj.Move();
  40.         }
  41.     }
  42.     //移动(蛇的头部移动 需要传参)
  43.     public void Move(Vector3 pos)
  44.     {
  45.         oldPos = transform.position;
  46.         //修改位置
  47.         transform.position = pos;
  48.         if (newObj != null)
  49.         {
  50.             newObj.Move();
  51.         }
  52.     }
  53. }
复制代码
3.脚本UIManager.cs 拖给空物体UIManager
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine.UI;
  4. using UnityEngine;
  5. using UnityEngine.SceneManagement;//加载场景时需引用
  6. public class UIManager : MonoBehaviour
  7. {
  8.     public static UIManager uiMagr;
  9.     public Text number_txt;//分数
  10.     public Button refreshBtn;//重新开始按钮
  11.     public Transform dieUI;//游戏失败面板
  12.     void Start()
  13.     {
  14.         //初始化
  15.         uiMagr = this;
  16.         dieUI.gameObject.SetActive(false);
  17.         refreshBtn.onClick.AddListener(Refresh);
  18.     }
  19.     // Update is called once per frame
  20.     void Update()
  21.     {
  22.         //按下esc 退出程序
  23.         if (Input.GetKeyDown(KeyCode.Escape))
  24.         {
  25.             Application.Quit();
  26.         }
  27.     }
  28.     //修改分数值
  29.     public void SetNumber(int value)
  30.     {
  31.         number_txt.text = value.ToString();
  32.     }
  33.     //显示死亡UI
  34.     public void DieUI()
  35.     {
  36.         dieUI.gameObject.SetActive(true);
  37.     }
  38.     //刷新
  39.     void Refresh()
  40.     {
  41.         //重新加载场景
  42.         SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
  43.     }
  44. }
复制代码
链接:https://pan.baidu.com/s/1bGXUal8RIJBSb6oFq4zHPA
提取码:syq1

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


开发者涨薪指南


48位大咖的思考法则、工作方式、逻辑体系

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-26 09:38 , Processed in 0.089835 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表