Godot 学习笔记(3):IOC容器注入,以NlogServices为例

本文介绍了如何在Godot.Net项目中使用IoC容器进行解耦,包括Service的搭建、NLog配置用于日志记录,并讨论了控制反转的最佳实践,以及避免输出生命周期问题的建议。
摘要由CSDN通过智能技术生成

前言

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更加注重根本的代码逻辑。

我应该基本已经解决了大部分的代码问题。我后面应该就是开始认真的开发游戏了。目前打算从贪吃蛇,推箱子等经典游戏入手。

  • 25
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值