Unity入门 :场景叠加/预制体资源包/脚本资源/生命周期函数/Inspector页面

场景操作------场景叠加

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

预制体与资源包

预制体概念

定义: 预先设置好的物体(又称预制体),用于保存单个物体的完整信息。

  • 作用:
    • 保存复杂组合对象的信息(如金字塔、坦克等由多个部件组成的物体)
    • 可在不同场景或工程中重复使用
  • 与场景的区别:
    • 场景保存的是多个对象的配置信息
    • 预设体专门保存单个对象的完整信息
  • 本质: 与场景文件类似的配置文件,通过反射机制动态创建对象

用文本打开该文件:

得到如图所示:

这段 YAML 内容 是 Unity 的预制体文件(.prefab):

当你在 Unity 编辑器中引用一个预制体,或者在运行时通过 Resources.Load()AddressablesAssetBundle 等方式加载它时,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):

  1. public 字段或者 带有 [SerializeField] 特性;
  2. 不是 static、const 或 readonly
  3. 类型是可序列化的(如基本类型、Unity 内置类型、自定义的非抽象类/结构体且满足序列化要求等);
  4. 不是自动属性(auto-property),因为属性(property)本身不会被序列化,只有字段(field)才会。
cs 复制代码
public 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

不支持显示的类

cs 复制代码
public 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在实例化脚本时会通过反射获取字段信息
    • 特性信息作为元数据被反射系统读取

一些辅助特性

不细讲了,参照这些进行了

Unity Inspector 面板的某些特性 - Mr.Cat~ - 博客园

相关推荐
在路上看风景2 小时前
20. 资源和脚本的绑定关系
unity
yj爆裂鼓手5 小时前
unity对象池
unity·c#
在路上看风景6 小时前
3.7 SRP Batcher
unity
快乐觉主吖6 小时前
Unity方便修改产品名和包名的小工具
unity·游戏引擎
孟无岐7 小时前
【Laya】HttpRequest 网络请求
网络·typescript·游戏引擎·游戏程序·laya
JIes__18 小时前
Unity(二)——MonoBehavior中的重要内容
unity·游戏引擎
孟无岐1 天前
【Laya】LocalStorage 本地存储
typescript·游戏引擎·游戏程序·laya
妙为1 天前
unreal engine5角色把敌人 “挤飞”
游戏引擎·虚幻·ue·unrealengine5
4Forsee1 天前
【增强现实】快速上手 Vuforia Unity Android AR 应用开发
android·unity·ar