场景操作------场景叠加
在编辑模式下,把对应场景拖拽进来,方便我们复制对应预制体进入场景

预制体与资源包
预制体概念
定义: 预先设置好的物体(又称预制体),用于保存单个物体的完整信息。
- 作用:
- 保存复杂组合对象的信息(如金字塔、坦克等由多个部件组成的物体)
- 可在不同场景或工程中重复使用
- 与场景的区别:
- 场景保存的是多个对象的配置信息
- 预设体专门保存单个对象的完整信息
- 本质: 与场景文件类似的配置文件,通过反射机制动态创建对象
用文本打开该文件:
得到如图所示:
这段 YAML 内容 是 Unity 的预制体文件(.prefab):
当你在 Unity 编辑器中引用一个预制体,或者在运行时通过
Resources.Load()、Addressables、AssetBundle等方式加载它时,Unity 就会解析这个 YAML 格式的.prefab文件,并根据其中的数据重建完整的 GameObject 及其所有组件。
预设体相关操作
1、**存储:**可以专门在Asset页面中新建一个文件"Prefab"管理这些预制体
2、**修改预制体:**在场景中修改后,override
3、**修改单个预制体,其他预制体不变:**unpack场景中的预制体,再修改
4、快速找到文件夹中的对应预制体:选中场景中的预制体,右键"Select Prefab Asset"
资源包
这个工程中的预制体不仅能给自己用,还可以给别人用。
这就是我们资源包的用法------将当前项目中的部分资源,导出成资源包,加载到其他项目中
导出资源包
在Project页面中导出资源包

弹出窗口后点击导出

得到文件如下:

脚本资源

脚本挂载原理
- 反射机制: Unity通过文件名找到对应类并实例化
- 挂载失败表现: 当类名与文件名不一致时会出现警告提示
图中Test脚本 中的类名已改为Test2,所以这里加载失败了
尤其是新建脚本是默认取名,然后里面类名改了,外面文件名没改!
MonoBehavior基类

- 继承必要性:Unity新建的脚本默认继承MonoBehaviour,只有继承后才能挂载到GameObject上
- **挂载原理:**Unity通过反射机制获取脚本类名,检查是否继承MonoBehaviour来决定能否挂载
继承MonoBehavior可以再次被继承
cs
public class Test : MonoBehavior
{
}
public class Test3 : Test
{
}
Test3并未继承MonoBehavior,但因为继承了Test的特性,所以也能挂载到物体上
不继承MonoBehavior的类
**挂载机制:**只有继承MonoBehavior的类才能出现在Inspector面板的AddComponent菜单中
**关联方式:**需要通过脚本代码手动建立与其他对象的关联关系

使用场景
- **管理类:**常实现为单例模式,如怪物管理器、场景管理器等全局控制模块
- **数据类:**用于存储结构化数据,如示例中的玩家信息类包含age/name/sex等字段
- **工具类:**提供通用功能方法,不与具体游戏对象绑定
cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test4//Test4是玩家数据类
{
public int age;
public string name;
public bool sex;
}
public class Test : MonoBehavior
{
public Test4 player1;
}
不继承MonoBehavior的类中的生命周期相关函数可以删去,因为没有意义。
脚本执行顺序
- **默认情况:**当场景中多个脚本(如Test、Test2、Test3)同时挂载时,Unity引擎无法自动控制它们的执行顺序
- **问题表现:**脚本间的执行顺序具有不确定性,可能导致依赖关系出错
可以手动调整脚本执行顺序:
1、选中任意脚本,通过"Script Execution Order"选项进入设置界面
- 数值规则:
- 数值越小执行越早
- Default Time为系统默认分界线
- 系统核心脚本(如物理引擎)通常设置为负值
- 示例说明:
- 当Test设置为100,Test2设置为200时
- Test脚本会先于Test2执行
- 差值越大优先级差异越明显
典型场景:
- 管理系统初始化(如GameManager应最先执行)
- 物理计算与渲染的顺序控制
- 网络同步与本地预测的时序处理
修改默认脚本模版
**模板结构:**新建脚本默认包含继承MonoBehavior的类定义,如Start()和Update()两个基本函数
1、在Unity版本资源管理器中点击这个
2、根据路径找到对应路径
生命周期函数
帧的相关概念

Unity已内置死循环机制,开发者无需手动编写
**开发方式:**通过生命周期函数在固定时机处理游戏逻辑
生命周期函数概念
执行主体 :所有继承MonoBehavior的脚本类
触发机制 :Unity通过反射自动调用特定名称的函数
**完整周期:**从GameObject出生到消亡的全过程
还需要注意的是:生命周期函数的访问修饰符通常为private/protected,因无需手动调用
生命周期具体函数

Awake函数
基本概念: Awake是Unity中的生命周期函数,在对象创建时自动调用
类比说明: 类似构造函数的存在,用于对象创建时的初始化操作
**调用特点:**一个对象在其生命周期内只会被调用一次
需要说明的是:这里的对象创建指的是脚本类对象,不是依附的GameObject对象
可以通过动态挂载脚本可验证:拖拽瞬间触发Awake
修饰符特点相关:
默认修饰符: 不写时默认为private私有
- 可选修饰符:
- protected:当子类需要重写时使用
- public:公共访问(不推荐)
使用建议:
- 无继承需求时使用private或不写
- 需要子类重写时使用protected
OnEnable函数
**调用时机:**当脚本依附的GameObject对象每次激活时自动调用
**初始调用:**对象实例化时若处于激活状态,会立即触发第一次OnEnable调用
**核心用途:**如果对象需要在重新激活时处理一些逻辑,就可以使用该函数
Start函数
执行时机:
- 从对象被创建出来后,在第一次真更新之前调用
- 一个对象只会调用一次
- 执行顺序在Awake之后,但在第一次Update之前
与Awake的区别:
- 执行顺序:Awake最早执行(对象出生时立即调用),Start稍晚(第一次更新前调用)
- **动态创建场景:**在Update中动态创建的对象会立即执行Awake,但Start要等到当前帧结束后才会执行
- 初始化时机:Awake类似构造函数,Start更适合需要等待其他对象初始化的场景
FixedUpdate函数
主要用于进行物理相关的处理,如碰撞检测等物理系统相关操作
**固定间隔执行:**在Unity内部死循环中以固定时间间隔执行,默认间隔为0.02秒
**特殊执行机制:**虽然每帧执行,但其执行间隔时间可单独控制,不同于常规游戏帧更新
FixedUpdate 的执行频率独立于帧率(Frame Rate)
即使游戏卡到 10 FPS,FixedUpdate 仍会按 0.02 秒的节奏被调用(可能一帧内调用多次,或跳过以追赶时间)。
如何控制间隔时间
1、ProjectSetting------Time
Update生命周期函数
**核心作用:**主要用于处理游戏核心逻辑更新的函数,是Unity提供给开发者编写游戏逻辑的主要接口
- 执行时机:
- 晚于FixedUpdate执行
- 每帧都会调用,帧率概念与游戏帧率相关
典型应用:
- 处理位移等游戏对象状态变化
- 实现游戏核心机制
LateUpdate生命周期函数
- 执行顺序:
- 与Update具有相同的帧率
- 在Update之后执行
- 核心用途:
- 解决渲染顺序问题
- 主要用于处理摄像机位置更新相关内容
- 底层机制:
- 在Update和LateUpdate之间Unity会进行动画更新等处理
- 若在Update中更新摄像机可能导致渲染错误(如黑屏)
**执行日志顺序:**FixedUpdate→Update→LateUpdate的固定执行顺序
Ondisable生命周期函数
- 调用时机:当依附的GameObject对象每次失活时调用
- **对应关系:**与OnEnable形成对应关系,分别处理激活和失活状态
- 关键区别:
- 对象删除操作会触发完整的销毁流程(失活→销毁)
- OnDisable在每次失活时都调用,OnDestroy只在最终销毁时调用一次
- 典型应用:适合进行最终资源释放、数据持久化等收尾工作
生命周期函数继承多态的实现
虚函数声明:
可以将生命周期函数声明为虚函数,如protected virtual void Awake(),支持子类重写。
子类重写
cs
public class Test : MonoBehaviour
{
protected virtual void Awake()
{
print("Awake");
}
}
public class Lesson1Son : Test
{
protected override void Awake()
{
base.Awake(); // 确保父类初始化完成------如果不想保留父类的效果就不保留
Debug.Log("子类的Awake");
}
}
输出结果可以体现出这种重写:我这里是不保留父类方法的输出:
生命周期函数默认继承
cs
public class Test : MonoBehaviour
{
protected virtual void Awake()
{
print("Awake");
}
void Update()
{
print("Update");
}
void LateUpdate()
{
print("LateUpdate");
}
void OnDisable()
{
print("OnDisable");
}
}
public class Lesson1Son : Test
{
}
会直接输出父类打印结果!
打印方法相关
- Debug类方法:
- Debug.Log():普通信息打印
- Debug.LogError():错误信息打印(红色)
- Debug.LogWarning():警告信息打印(黄色)
- MonoBehaviour专用:
- print()方法:继承MonoBehaviour时简化写法
Inspector页面
基本原理: 继承MonoBehaviour的脚本挂载到GameObject上后,其成员变量可以在Inspector窗口显示并编辑
工作流程: 运行时Unity会通过反射获取Inspector中设置的值,为成员变量赋值
私有/保护字段如何序列化
- 默认行为:
- private和protected等私有/保护变量默认不会显示在Inspector窗口
- 示例中声明了测试变量但Inspector窗口无变化
**原因:**Unity默认只序列化公共字段,私有和保护字段需要特殊处理才能显示
**解决方法:**使用[SerializeField]特性强制序列化字段
cs
[SerializeField]
private int privateInt;
[SerializeField]
protected string protectedStr;
序列化概念: 将对象保存到文件或数据库字段中的过程
public字段默认显示
**默认行为:**在Unity中,public修饰的成员变量默认会在Inspector面板中显示并可编辑
public修饰的成员变量默认会在 Inspector 面板中显示并可编辑 ,但这 并不完全等同于"默认可以序列化"。Unity 的序列化系统会自动序列化满足以下条件的字段(field):
- 是
public字段 ,或者 带有[SerializeField]特性;- 不是 static、const 或 readonly;
- 类型是可序列化的(如基本类型、Unity 内置类型、自定义的非抽象类/结构体且满足序列化要求等);
- 不是自动属性(auto-property),因为属性(property)本身不会被序列化,只有字段(field)才会。
cspublic class Example : MonoBehaviour { public int score; // ✅ 显示在 Inspector,会被序列化 [SerializeField] private float speed; // ✅ 显示(因 SerializeField),会被序列化 private string name; // ❌ 不显示,不序列化 public static int count; // ❌ static,不序列化,不显示 public int Health { get; set; } // ❌ 属性,不序列化,不显示(即使 public) }
public字段如何不显示
同理,如果不想让public字段在Inspector显示,也要添加字段
cs
#region 知识点四 公共的也不让其显示编辑
//在变量前加上特性
[HideInInspector]
public int publicInt2 = 50;
#endregion
部分类不支持显示
支持显示的类
cs#region 知识点五 大部分类型都能显示编辑 public int[] array; public List<int> list; public E_TestEnum type; public GameObject gameObj; #endregion
不支持显示的类
cspublic struct MyStruct { public int age; public bool sex; } public class MyClass { public int age; public bool sex; } //字典不能被Inspector窗口显示 public Dictionary<int, string> dic; //自定义类型变量 public MyStruct myStruct; public MyClass myClass;
但是也可以使用方法使其显示------通过添加[System.Serializable]特性使自定义结构体和类在Inspector窗口显示
cs[System.Serializable] public struct MyStruct { public int age; public bool sex; } [System.Serializable] public class MyClass { public int age; public bool sex; }题话外:Dictionary不能使用这种方法------但却可以通过Odin进行编辑
特性原理
cs
[SerializeField] private float speed;
[HideInInspector]
public int publicInt2 = 50;
#endregion
这些序列化字段都属于反射与特性相关内容,这里就不详细展开了
- 反射机制应用 :
- Unity在实例化脚本时会通过反射获取字段信息
- 特性信息作为元数据被反射系统读取
一些辅助特性
不细讲了,参照这些进行了










