1. 为什么你的Unity项目需要依赖注入?
如果你和我一样,在Unity里摸爬滚打了好几年,肯定经历过这样的场景:一个脚本需要另一个脚本的数据,于是你写了个 FindObjectOfType,或者更“暴力”一点,直接 GetComponent 或者拖拽一个 public 字段到Inspector面板。项目小的时候,这招挺好使,简单直接。但随着功能越加越多,脚本之间的引用关系就像一团乱麻,改一个地方,可能十个地方报错。更头疼的是,想写个单元测试?对不起,这些紧耦合的代码几乎没法测。
这就是我们常说的“代码耦合度太高”。而依赖注入(Dependency Injection, DI),就是解开这团乱麻的一把利器。它不是什么高深莫测的黑科技,你可以把它理解为一个“超级智能的中间人”或者“对象管家”。
想象一下,你是一个游戏导演,要拍一场戏(实现一个功能)。以前的做法是,演员A(ClassA)需要道具B(ClassB),他得自己满场跑去找道具组,甚至自己动手做一个。这导致演员A非常依赖具体的道具组流程,一旦道具组搬家了或者换人了,演员A就懵了。
而依赖注入的做法是:你,作为导演,在开拍前就把剧本(依赖关系)告诉了一位专业的制片主任(DI容器)。你只需要说:“这场戏需要演员A,他手里要拿着道具B。” 开拍时,制片主任会自动把道具B递到演员A手里。演员A根本不需要关心道具B是从哪来的、怎么做的,他只需要专注演戏(业务逻辑)就行了。
VContainer 就是Unity生态里这位非常称职的“制片主任”。它轻量、高效,而且和Unity的生命周期结合得非常好。我当初从手动管理依赖,到尝试一些其他IoC框架,最后切换到VContainer,最大的感受就是:代码变干净了,架构变清晰了,写测试也终于不再是噩梦了。它让你能更专注于游戏玩法本身,而不是在对象创建的泥潭里挣扎。
所以,无论你是想重构一个老项目,还是为一个新项目打下坚实的地基,花点时间掌握VContainer,绝对是笔划算的投资。接下来,我就带你从零开始,用最直白的方式,把它用起来。
2. 快速上手:5分钟创建你的第一个VContainer项目
光说不练假把式,咱们直接动手。别担心,步骤非常简单,我会带你一步步走通。
2.1 安装VContainer
首先,你需要一个Unity项目(建议使用2020.3 LTS或更新版本)。打开Unity,我们通过Package Manager来安装VContainer,这是最推荐的方式。
- 在Unity编辑器中,点击顶部菜单栏的 Window > Package Manager。
- 在Package Manager窗口左上角,点击“+”号按钮,选择 “Add package from git URL...”。
- 在弹出的输入框中,粘贴VContainer的Git仓库地址:
https://github.com/hadashiA/VContainer.git?path=VContainer/Assets/VContainer - 点击“Add”按钮,Unity就会开始下载并安装VContainer。
等待安装完成后,你就能在Package Manager的“My Registries”或“In Project”列表里看到VContainer了。这种方式能确保你总是使用最新的稳定版本,并且便于后续更新。
2.2 理解核心概念:LifetimeScope
安装好后,你可能会问,从哪开始?VContainer的核心是一个叫做 LifetimeScope 的组件。你可以把它看作是一个“依赖关系配置中心”,或者一个“对象作用域”。我们所有的类型注册和依赖关系定义,都在这里进行。
在Unity中,一个典型的游戏会有不同的作用域。比如:
- 整个游戏进程级:一些全局的、唯一的服务,比如存档管理器、音频管理器、网络客户端。
- 单个场景级:这个场景特有的管理器、UI控制器、关卡数据。
- 更小的局部级:比如一个战斗小队、一个UI面板内部。
LifetimeScope 完美支持这种层次结构。父Scope中注册的服务,子Scope可以拿来就用;而子Scope注册的服务,则只在自己的范围内有效。这为管理复杂项目的依赖提供了极大的灵活性。我们先从最简单的单Scope开始。
2.3 第一个实战案例:让一个类“动”起来
我们来复现并丰富一下原始文章里的第一个例子,目标是让一个不继承自 MonoBehaviour 的普通C#类,能像MonoBehaviour一样拥有 Start() 和 Update() 生命周期。
第一步:创建我们的“演员”
在Scripts文件夹下,创建一个C#脚本,命名为 ActorPresenter。注意,它不继承 MonoBehaviour,而是实现VContainer提供的 IStartable 和 ITickable 接口。
using VContainer.Unity; // 注意这个命名空间
using UnityEngine;
public class ActorPresenter : IStartable, ITickable
{
public void Start()
{
Debug.Log($"[ActorPresenter] Start方法被调用!时间:{Time.time}");
// 这里可以放初始化逻辑,比如加载资源、订阅事件
}
pu

301

被折叠的 条评论
为什么被折叠?



