深圳seo网站优化公司360公司官网首页
news/
2025/9/26 9:30:20/
文章来源:
深圳seo网站优化公司,360公司官网首页,装饰公司网站php源码,徐州做网站的公司Unity3D 小案例 像素贪吃蛇 第二期 蛇的觅食
像素贪吃蛇
食物生成
在场景中创建一个 2D 正方形#xff0c;调整颜色#xff0c;添加 Tag 并修改为 Food。 然后拖拽到 Assets 文件夹中变成预制体。 创建食物管理器 FoodManager.cs#xff0c;添加单例#xff0c;可以设置…Unity3D 小案例 像素贪吃蛇 第二期 蛇的觅食
像素贪吃蛇
食物生成
在场景中创建一个 2D 正方形调整颜色添加 Tag 并修改为 Food。 然后拖拽到 Assets 文件夹中变成预制体。 创建食物管理器 FoodManager.cs添加单例可以设置食物生成的坐标范围提供生成一个食物的方法。
因为 Random.Range 的取值范围是 [min, max)为了取到 max 的值需要给右边界加一。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class FoodManager : MonoBehaviour
{public static FoodManager instance;public GameObject food;public int borderLeft -8;public int borderRight 8;public int borderTop 4;public int borderBottom -4;void Awake(){if (instance null){instance this;}else{Destroy(gameObject);}}void Start(){// 初始生成一个食物GenerateFood();}/// summary/// 生成食物/// /summarypublic void GenerateFood(){GameObject obj Instantiate(food, transform);int x Random.Range(borderLeft, borderRight 1);int y Random.Range(borderBottom, borderTop 1);obj.transform.position new Vector3(x, y, 0);}
}在场景中创建节点挂上脚本拖拽引用。 运行游戏可以看到场景中生成了一个食物。 吃掉食物
给食物的预制体添加碰撞体勾选 Is Trigger。 同样蛇头也要添加碰撞体还要再添加一个刚体Body Type 设置为 Kinematic不需要受到重力影响。 在 Snake.cs 中添加碰撞函数判断碰撞物体的标签是 Food就销毁食物生成新的蛇身并生成下一个食物。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Snake : MonoBehaviour
{// ...void OnTriggerEnter2D(Collider2D other){if (other.CompareTag(Food)){Destroy(other.gameObject);GenerateBody();FoodManager.instance.GenerateFood();}}
}此时运行游戏蛇头可以吃掉食物了。
但是有时候蛇头还未到达食物的位置食物就被吃掉了甚至蛇头只是经过食物的附近食物也消失了。这是因为碰撞体的范围问题默认的 Size 是 (1, 1)可以稍微调小一些例如 (0.5, 0.5)。 调整后的效果 食物位置
目前场景范围适中生成的食物都在空地但是当蛇越来越长的时候会发现食物生成的位置有可能在蛇的身上。
我们应该让食物始终都在空地生成。
那么对于一个坐标是否为空地就需要做一些标记。
网格
目前食物生成的坐标取值范围在 X 轴是 [-8, 8]在 Y 轴是 [-4, 4]。
如果把这些坐标点看成是一个网格可以按照行列来看。
左上角是 (-8, 4)是第 0 行第 0 列索引为 0。
右上角是 (8, 4)是第 0 行第 16 列索引为 16。
左下角是 (-8, -4)是第 8 行第 0 列索引为 136。
右下角是 (8, -4)是第 8 行第 16 列索引为 152。 注意这里的索引是从第 0 行开始从左到右递增。行数增加时索引继续计数。 网格列表
在 FoodManager.cs 中添加一个 Vector3 列表X 和 Y 记录坐标Z 记录是否空地0 表示空地1 表示有物体占用。
这里总行数是上边界减去下边界还要加上一个端点总共 9 行。
总列数是右边界减去左边界还要加上一个端点总共 17 列。
根据行列数依次添加 Vector3 到列表中Z 默认是 0。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class FoodManager : MonoBehaviour
{// ...public ListVector3 gridList;public int rowMax 0;public int colMax 0;void Start(){rowMax borderTop - borderBottom 1;colMax borderRight - borderLeft 1;for (int i 0; i rowMax; i){for (int j 0; j colMax; j){gridList.Add(new Vector3(borderLeft j, borderTop - i, 0));}}}
}然后提供一个标记网格列表的方法把传入的坐标转成 int判断边界换算行列计算索引根据索引从网格列表中取出一个网格点更新标记。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class FoodManager : MonoBehaviour
{// .../// summary/// 标记网格列表/// /summary/// param namepos坐标位置/param/// param nameflag标记/parampublic void MarkGridList(Vector3 pos, bool flag){int x (int)pos.x;int y (int)pos.y;// 坐标超出边界if (x borderLeft || x borderRight) return;if (y borderBottom || y borderTop) return;// 换算行列int row borderTop - y;int col x - borderLeft;// 计算索引int index col row * colMax;// 索引超出边界if (index 0 || index gridList.Count - 1) return;// 取出网格点标记是否空地Vector3 grid gridList[index];grid.z flag ? 1 : 0;// 更新网格点gridList[index] grid;}
}标记网格
在游戏开始时蛇头会占用一个网格生成的身体也需要标记网格。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Snake : MonoBehaviour
{void Start(){// 初始生成身体for (int i 0; i initBodyCount; i){GenerateBody();}FoodManager.instance.MarkGridList(transform.position, true);// ...}void GenerateBody(){GameObject obj Instantiate(body);// ...FoodManager.instance.MarkGridList(obj.transform.position, true);}
}在蛇的移动过程中也要动态地标记网格。
蛇头和身体移动后都要标记网格已经被占用只有在最后一个身体移动前标记当前网格位置为空地。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Snake : MonoBehaviour
{void Move(){// ...// 移动前先标记旧的位置posMarkFirst transform.position;transform.Translate(direction);// 标记蛇头移动后的网格位置FoodManager.instance.MarkGridList(transform.position, true);// ...for (int i 0; i bodyList.Count; i){// 最后一个身体移动前标记当前网格位置为空地if (i bodyList.Count - 1){FoodManager.instance.MarkGridList(bodyList[i].transform.position, false);}// ...// 每个身体移动后标记当前网格位置FoodManager.instance.MarkGridList(bodyList[i].transform.position, true);}}
}食物也会占用网格每次生成食物时也要标记网格。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class FoodManager : MonoBehaviour
{public void GenerateFood(){GameObject obj Instantiate(food, transform);int x Random.Range(borderLeft, borderRight 1);int y Random.Range(borderBottom, borderTop 1);obj.transform.position new Vector3(x, y, 0);// 标记食物占用的网格位置MarkGridList(obj.transform.position, true);}
}筛选空地
在食物生成时不能单纯用随机数来确定坐标位置而是要从网格列表中筛选未被占用的网格点然后从这些网格点中随机取出一个位置。
定义一个 filterList用来存储筛选后的网格点。
每次生成食物时需要先清理 filterList然后从网格列表中筛选 Z 为 0表示未被占用的网格点添加到筛选列表中。
然后再生成随机数从筛选列表中取出网格点赋值位置给生成的食物。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class FoodManager : MonoBehaviour
{// ...public ListVector3 filterList;// ...public void GenerateFood(){// 清理筛选列表filterList.Clear();for (int i 0; i gridList.Count; i){// 筛选未被占用的网格点if (gridList[i].z 0){filterList.Add(gridList[i]);}}// 没有空地了if (filterList.Count 0) return;// 随机取出一个空地int index Random.Range(0, filterList.Count);Vector3 pos filterList[index];GameObject obj Instantiate(food, transform);// int x Random.Range(borderLeft, borderRight 1);// int y Random.Range(borderBottom, borderTop 1);// obj.transform.position new Vector3(x, y, 0);obj.transform.position pos;// 标记食物占用的网格位置MarkGridList(obj.transform.position, true);}
}至此当蛇身越来越长时也不会出现食物生成在蛇身上的情况了。
运行效果
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/918047.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!