文章目录
- 前言
- 环境
- 注意事项
- Ioc注入
- 文件夹设置
- Service服务搭建
- Nlog.config
- NlogService配置
- ButtonTest1Service控制反转
- Program主入口
- ButtonTest1从Ioc中获取服务
- 输出
- 生命周期问题
- 总结
前言
Godot.Net中使用IOC之后,Godot的代码将会被极大的解耦。这里不不展开说明IOC的优点。
Godot Engine 4.2 简体中文文档 最佳实践 场景组织
.NET Core 依赖注入 Microsoft.Extensions.DependencyInjection
C# IOC 容器实战:KeyedService和生命周期
.NET 控制台NLog 使用
Godot 添加Nuget 引用
环境
- visual studio 2022
- .net core 8.0
- godot 4.2.1
- window 10
Nuget
注意事项
- 我们每次visual Studio 写完代码后,一定要重新生产解决方案。不然会导致无法更新。
- 我们可以在需要隐藏的文件夹中添加.gdignore,这样我们就能忽略多余的Csharp文件夹
- 在绑定C# 脚本代码后,一定不能再次修改脚本代码的名字,不然会导致加载场景出现问题,整个场景彻底打不开。
Ioc注入
文件夹设置
这里建议手写,因为自动生成的代码是没有命名空间的。
Service服务搭建
Nlog.config
详细的可以参考这个
.NET 控制台NLog 使用
我们在根路径下面添加Nlog.config
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
<targets>
<!--将Debug导出为每小时一个-->
<target name="debug"
xsi:type="File"
fileName="${basedir}/Logs/${date:format=yyyy}/${date:format=MM}/${date:format=dd}/${date:format=HH}.log"
layout="${date:format=yyyy-MM-dd HH\:mm\:ss} [${uppercase:${level}}] : ${message}" />
<!--将Error导出为每天一个,而且存放在一个Error文件夹中-->
<target name="error"
xsi:type="File"
fileName="${basedir}/Logs/${date:format=yyyy}/${date:format=MM}/Error/${date:format=dd}.log"
layout="${date:format=yyyy-MM-dd HH\:mm\:ss} [${uppercase:${level}}] : ${message}" />
</targets>
<rules>
<logger name="*"
minlevel="Debug"
writeTo="debug" />
<logger name="*"
minlevel="Error"
writeTo="error" />
</rules>
</nlog>
NlogService配置
public class NlogServices
{
private Logger logger;
public NlogServices()
{
var url = string.Format("{0}NLog.config", AppDomain.CurrentDomain.BaseDirectory.ToString());
GD.Print($"url地址为{url}");
LogManager.Configuration = new XmlLoggingConfiguration(url);
logger = NLog.LogManager.GetCurrentClassLogger();
}
public void Debug(string msg)
{
GD.Print(msg);
logger.Debug(msg);
}
public void Info(string msg)
{
GD.Print(msg);
logger.Info(msg);
}
public void Error(string msg)
{
GD.Print(msg);
logger.Error(msg);
}
public void Warning(string msg)
{
GD.Print(msg);
logger.Warn(msg);
}
}
ButtonTest1Service控制反转
我们应该在ButtonTest1Service中将ButtonTest1场景脚本对象获取。
public class ButtonTest1Service
{
private NlogServices _nlogService;
private ButtonTest1 _buttonTest1;
public ButtonTest1Service(NlogServices nlogServices) {
_nlogService = nlogServices;
}
public void Start(ButtonTest1 buttonTest1)
{
_buttonTest1 = buttonTest1;
_buttonTest1.ButtonDown += () =>
{
_nlogService.Info("依赖注入成功!");
};
}
}
Program主入口
我们应该有个主入口,我这里的主入口是Program.cs
public static class Program
{
public static IServiceProvider Services = ConfigureServices();
/// <summary>
/// Configures the services for the application.
/// </summary>
private static IServiceProvider ConfigureServices()
{
var services = new ServiceCollection();
services.AddSingleton<NlogServices>();
services.AddTransient<ButtonTest1Service>();
return services.BuildServiceProvider();
}
}
ButtonTest1从Ioc中获取服务
public partial class ButtonTest1 : Button
{
// Called when the node enters the scene tree for the first time.
public ButtonTest1Service SenceSerivce { get; set; }
public override void _Ready()
{
//获取Ioc容器
SenceSerivce = Program.Services.GetService<ButtonTest1Service>();
//Ioc控制反转,将本身添加到Start中
SenceSerivce.Start(this);
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
}
输出
因为我们已经在Service里面注册了按钮事件,所以我们直接使用即可。
生命周期问题
我更建议将Ioc注入放在构造函数而不是Ready里面,因为我们一般会在Ready里面去获取Node子节点。可能会有一个生命周期冲突的问题。
总结
Ioc容器会极大的解决Godot的代码的耦合问题。我们这次是添加了Nlog日志服务。我们后面还可以添加网络服务,数据库服务,文件加载服务等。这个极大的降低了我们代码的耦合。让我们更加专心的解决代码。
SencesScirpt和SenceSerivces的分开,也是功能和职责的分开。SencesScirpt更加注重Godot的生命周期,比如Ready(), Process等生命周期。SenceSerivces更加注重根本的代码逻辑。
我应该基本已经解决了大部分的代码问题。我后面应该就是开始认真的开发游戏了。目前打算从贪吃蛇,推箱子等经典游戏入手。