系列文章目录
unity知识点
👉前言
有时候需要做摆放场景物体的时候会重复使用一些物体,这时候把物体做成预制体是最好用的,有时候需要用到很多的预制体,需要手动全部拖到Project面板的Assets文件夹下面(自己创建新的文件夹名称,按自己喜欢的名称就好)
博客将会介绍制作的方法。希望这篇博客对Unity的开发者有所帮助。
大家好,我是心疼你的一切,不定时更新Unity开发技巧,觉得有用记得一键三连哦。
欢迎点赞评论哦.下面就让我们进入正文吧 !
提示:以下是本篇文章正文内容,下面案例可供参考
👉一、效果展示
项目运行时制作预制体
👉二、使用方法
1.如图所示的代码挂载到一个空物体上即可
2.场景如下图所示
3.完整代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 引擎运行可以使用,打包出来不能用切记
/// </summary>
public class GameObjToPrefabs : MonoBehaviour
{
public GameObject prefabHolder;
//制作单个的物体预制体
public void ConvertToPrefab(string name_)
{
#if UNITY_EDITOR
// 将场景物体设为预制体
UnityEditor.PrefabUtility.SaveAsPrefabAsset(prefabHolder, "Assets/Scripts/一键生成预制体/Prefabs/"+ name_ + ".prefab");
#endif
}
//制作物体下面子物体的预制体
public void ConvertToPrefab(List <GameObject> name_s)
{
foreach (var item in name_s)
{
#if UNITY_EDITOR
// 将场景物体设为预制体
UnityEditor.PrefabUtility.SaveAsPrefabAsset(item, "Assets/Scripts/一键生成预制体/Prefabs/" + item.name + ".prefab");
#endif
}
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.P))
{
ConvertToPrefab(prefabHolder.name);
}
if (Input.GetKeyDown(KeyCode.O))
{
List<GameObject> lists = new List<GameObject>();
for (int i = 0; i < prefabHolder.transform.childCount; i++)
{
lists.Add(prefabHolder.transform.GetChild(i).gameObject);
}
ConvertToPrefab(lists);
}
}
}
运行自己测试即可,
最后在加点其他的吧!!
对象池的原理:
Unity对象池的基本原理是通过预先实例化一定数量的对象并将它们放入对象池中,当需要使用对象时,从池中获取一个未使用的对象,使用完毕后,再将对象归还到池中,以便重用。这样可以减少对象的创建与销毁,提高性能,特别是在创建与销毁数量较多的对象时,如子弹、敌人等。
👉三、对象池使用
👉3-1、效果展示
对象池应用
👉3-2、制作prefab
1.先创建一个Resources文件夹,然后制作预制体
预制体如下图所示:
2.预制体上面的组件如下图所示:
3.预制体上面的代码组件如下:
代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DelPush : MonoBehaviour
{
public Rigidbody rigidbody;
private float speed = 50;
private void Start()
{
rigidbody.AddRelativeForce(new Vector3 (0,0,speed), ForceMode.Impulse );
}
void OnEnable()
{
speed =50;
this.transform.position = Vector3.zero;
rigidbody.AddRelativeForce(new Vector3(0, 0, speed), ForceMode.Impulse);
//unity自带的延迟方法 在time秒后,延迟调用方法methodName
Invoke("Push", 2);
}
//放回去
void Push()
{
ObjectTool.instance.PushObj(transform.name, this.gameObject);
speed = 0;
}
}
👉3-3、核心代码
代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectTool : MonoBehaviour
{
public static ObjectTool instance;
void Awake()
{
instance = this;
}
//这里是缓存池模块
//创建字段存储容器
public Dictionary<string, List<GameObject>> pool1Dic = new Dictionary<string, List<GameObject>>();
private GameObject poolObj;
//取得游戏物体
public GameObject GetObj(string name)
{
GameObject obj = null;
//ContainsKey判断是否包含指定的“键名”
//.count 获得符合条件的个数
if (pool1Dic.ContainsKey(name) && pool1Dic[name].Count > 0)
{
//取得List中的第一个
obj = pool1Dic[name][0];
//移除第零个(这样才能允许同时创建多个物体)
//这样才是真正的“拿出来”
pool1Dic[name].RemoveAt(0);
}
else
{
//缓存池中没有该物体,我们去目录中加载
//外面传一个预设体的路径和名字,我内部就去加载它
//Resources类允许你从指定的路径查找或访问资源(api)
obj = GameObject.Instantiate(Resources.Load<GameObject>(name));
//创建对象后,将对象的名字与池中名字相符
obj.name = name;
}
//让物体显示出来
obj.SetActive(true);
obj.transform.parent = null;
return obj;
}
//外界返还游戏物体
public void PushObj(string name, GameObject obj)
{
if (poolObj == null)
{
poolObj = new GameObject("Pool");
}
//将这个物体设置父亲为空物体
obj.transform.parent = poolObj.transform;
//让物体失活也就是让物体隐藏起来不在屏幕上显示了,也就是在缓存池中了
obj.SetActive(false);
//里面有记录这个键(有这个抽屉)就加进去
if (pool1Dic.ContainsKey(name))
{
pool1Dic[name].Add(obj);
}
//未曾记录这个键(没有这个抽屉)就创建一个新的键值对象
else
{
pool1Dic.Add(name, new List<GameObject>() { obj });
}
}
}
👉3-4、对象池使用
新建脚本:CeShiDXC.cs
代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CeShiDXC : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
//向缓存池中拿东西
ObjectTool.instance.GetObj("Cube");
}
if (Input.GetMouseButtonDown(1))
{
ObjectTool.instance.GetObj("Sphere");
}
}
}
最后运行测试即可,如果需要其他功能,请自行扩展
补充:
底层原理分析
-
序列化机制
Unity使用YAML或二进制格式序列化预制体文件。
序列化内容包括:
物体的Transform、组件及其属性。
子物体递归序列化。
对其他资源的引用(通过GUID和Local Identifier管理)。 -
依赖关系处理
若物体引用了材质、贴图等资源,Unity会:
检查资源是否已存在于项目中。
若为运行时生成的新资源(如动态材质),需先保存为独立资源再引用。 -
实例与预制体的链接
预制体实例通过PrefabInstance组件记录源预制体的GUID和文件ID。
修改实例属性时,Unity会标记为覆盖(Override),与源预制体差异通过蓝线显示。
限制与替代方案
-
运行时生成预制体的限制
仅限编辑器模式:无法在构建后的应用中使用。
性能开销:频繁保存预制体会触发资源数据库刷新,导致卡顿。
资源引用风险:动态生成资源需手动管理依赖。 -
替代方案
ScriptableObject
存储配置数据,运行时动态生成物体。
AssetBundle
打包预设资源,支持运行时动态加载。
JSON/二进制序列化
保存物体状态,重启时重新构造。
应用场景
-
快速原型开发:在Play Mode中调试后直接保存为预制体。
-
动态内容生成工具:编辑器扩展工具中批量生成预制体。
-
关卡编辑器:允许用户在运行时设计关卡并保存为预制体模板。
👉壁纸分享
👉总结
本次总结的就是运行生成预制体的代码和对象池代码的使用 有需要会继续增加功能
如能帮助到你,就帮忙点个赞吧,三连更好哦,谢谢
你的点赞就是对博主的支持,有问题记得留言评论哦!
不定时更新Unity开发技巧,觉得有用记得一键三连哦。么么哒!