VContainer-getting-started/hello-world | 入门——Hello World
VContainer 基础集成步骤如下:
- 在场景中创建一个继承自
LifetimeScope
的组件:管理容器(container)和作用域(scope)。 - 在 LifetimeScope 子类中使用 C# 代码注册依赖项。这是组合根(composition root)。
- 运行场景时将自动构建容器并与Unity生命周期对接,LifetimeScope 会自动构建容器并将其分发到自己的 PlayerLoopSystem 中。
:::note
作用域(Scope)在游戏运行时会频繁创建/销毁。LifetimeScope
通过父子关系管理这一过程。
:::
1. 创建依赖其他类的组件
“Hello world”,示例服务类:
namespace MyGame
{
public class HelloWorldService
{
public void Hello()
{
UnityEngine.Debug.Log("Hello world");
}
}
}
2. 定义组合根
接着编写一个配置类用来自动管理注册的依赖项。
- 在项目选项卡中的文件夹中右键单击,选择创建 -> C#脚本。
- 将其命名为
GameLifetimeScope.cs
。
:::note
VContainer 会自动为以 *LifetimeScope 结尾的 C# 脚本生成模板。
:::
使用 builder
注册上面的服务类。
using VContainer;
using VContainer.Unity;
namespace MyGame
{
public class GameLifetimeScope : LifetimeScope
{
protected override void Configure(IContainerBuilder builder)
{
+ builder.Register<HelloWorldService>(Lifetime.Singleton);
}
}
}
:::note
VContainer 始终需要显式地传递 Lifetime
参数,为开发提供透明性和一致性。
:::
3. 创建绑定 LifetimeScope 的 GameObject
在 Hierarchy 面板中右键单击并选择创建空对象。并将其命名为 GameLifetimeScope
。
然后将之前创建的脚本(GameLifetimeScope.cs)附加到空对象上。
4. 如何使用新的 HelloWorldService?
注册的对象将自动执行依赖注入。
如下所示:
using VContainer;
using VContainer.Unity;
namespace MyGame
{
public class GamePresenter
{
readonly HelloWorldService helloWorldService;
public GamePresenter(HelloWorldService helloWorldService)
{
this.helloWorldService = helloWorldService;
}
}
}
同时需要注册该类(GamePresenter)。
builder.Register<HelloWorldService>(Lifetime.Singleton);
+ builder.Register<GamePresenter>(Lifetime.Singleton);
5. 对接 Unity 生命周期
要在 Unity 中编写应用程序,我们必须中断Unity的生命周期事件。
(通常是 MonoBehaviour的 Start / Update / OnDestroy / 等)
使用 VContainer 注册的对象可以独立于 MonoBehaviour 执行此操作。
通过实现和注册一些标记接口可以自动完成。
using VContainer;
using VContainer.Unity;
namespace MyGame
{
- public class GamePresenter
+ public class GamePresenter : ITickable
{
readonly HelloWorldService helloWorldService;
public GamePresenter(HelloWorldService helloWorldService)
{
this.helloWorldService = helloWorldService;
}
+ void ITickable.Tick()
+ {
+ helloWorldService.Hello();
+ }
}
}
现在,Tick()
将在 Unity 的 Update 时机执行。
因此,最好的习惯是通过使用标记接口来管理和隔离副作用入口点。
(从设计上来说,对于 MonoBehaviour,使用 Start / Update 等就足够了。VContainer 的标记接口可以将领域逻辑和表现逻辑的入口点分离。)
如下注册,让它运行在 Unity 的生命周期事件上:
- builder.Register<GamePresenter>(Lifetime.Singleton);
+ builder.RegisterEntryPoint<GamePresenter>();
:::note
- RegisterEntryPoint<GamePresenter>() 是一个别名,注册在与 Unity 的 PlayerLoop 事件相关的接口。
- 类似于 Register<GamePresenter>(Lifetime.Singleton).As<ITickable>()
- 注册生命周期事件而不依赖于 MonoBehaviour 有助于解耦领域逻辑和表现逻辑!
:::
如果有多个EntryPoints,可以使用以下声明进行分组。
builder.UseEntryPoints(Lifetime.Singleton, entryPoints =>
{
entryPoints.Add<GamePresenter>();
// entryPoints.Add<OtherSingletonEntryPointA>();
// entryPoints.Add<OtherSingletonEntryPointB>();
// entryPoints.Add<OtherSingletonEntryPointC>();
})
这可以更清楚地表明,入口点(EntryPoints)在设计上被赋予了特殊待遇。
6. 控制反转(IoC)
它通常响应用户输入等事件调用逻辑。
视图组件解耦示例:
using UnityEngine.UI;
public class HelloScreen : MonoBehaviour
{
public Button HelloButton;
}
使用 Unity 编程中,通常会将逻辑调用嵌入到 HelloScreen 中,但如果使用了 DI,就可以将 HelloScreen 与任何控制流分离。
namespace MyGame
{
- public class GamePresenter : ITickable
+ public class GamePresenter : IStartable
{
readonly HelloWorldService helloWorldService;
+ readonly HelloScreen helloScreen;
public GamePresenter(
HelloWorldService helloWorldService,
+ HelloScreen helloScreen)
{
this.helloWorldService = helloWorldService;
+ this.helloScreen = helloScreen;
}
+ void IStartable.Start()
+ {
+ helloScreen.HelloButton.onClick.AddListener(() => helloWorldService.Hello());
+ }
}
}
这样,领域逻辑 / 控制流 / 视图组件就成功分离开来了。
- GamePresenter: 仅负责控制流。
- HelloWorldService: 仅负责可以随时调用的功能
- HelloScreen: 仅负责视图。
最后,在 VContainer 中,需要注册依赖的 MonoBehaviour。以及注册 HelloScreen。
public class GameLifetimeScope : LifetimeScope
{
+ [SerializeField]
+ HelloScreen helloScreen;
protected override void Configure(IContainerBuilder builder)
{
builder.RegisterEntryPoint<GamePresenter>();
builder.Register<HelloWorldService>(Lifetime.Singleton);
+ builder.RegisterComponent(helloScreen);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!