Godot.NET C# 工程化开发(1):通用Nuget 导入+ 模板文件导出,包含随机数生成,日志管理,数据库连接等功能
文章目录
- 前言
- Github项目地址,包含模板文件
- 后期思考补充
- 项目设置
- 编写失误
- 环境
- visual studio 配置
- 详细的配置看我这篇文章
- Nuget 推荐
- NewtonSoft 成功
- Bogus 成功
- Github文档地址
- 随机生成
- 构造器生成
- 构造器+接口(推荐)
- 文件夹设置
- Nlog 成功!
- Nlog.config
- NlogHelper.cs
- Nloghelper使用
- 测试
- FreeSql 以Sqlite为例
- FreeSql官方文档
- sqlite3 安装,CodeFrist则不需要安装。我这里用CodeFrist
- 生成Sqlite数据库文件,这里我取名为sqliteDb.db
- Nuget引入,FreeSql核心和FreeSql的Sqlite支持
- FreeSqlHelper CodeFrist模式
- T_ModelBase 数据库基类+Bogus随机生成
- T_Person,数据库插入类,我习惯用T开头带表数据库实体
- 连接,插入,查询测试使用
- GD_Extension项目打包,用于复用
- Icon封面准备
- visual studio 导出
- Github项目地址,包含模板文件
- 总结
前言
我们学编程,不要重复造工具。我之所以使用C# 开发Godot ,而不是Unity。很大的原因就是Godot.NET 支持Nuget的导入,因为Nuget是.NET Core 的第三方库。我也将Godot 的Visual Studio 项目的.NET 版本强制升级到的.NET Core 8.0版本,目前还没有任何问题。
Github项目地址,包含模板文件
Gclove2000/GodotNet_Csharp_IOC_SimpleTemplate
后期思考补充
我将项目分成3层,从上到下是
- Godot:只是单纯挂载脚本
- GD_Program:负责游戏逻辑
- GD_Extension:通用的工具类
但是我后面想了一下,游戏逻辑也有部分是可以通用的,所以我感觉我的三层构造应该是存在过度封装了。两层封装说不定好一些。我后面打算先用两层封装好一点。等后面项目复杂度上来之后,再细分好了。
项目设置
编写失误
我写到后面的时候发现,Interfaces应当放在GD_Extension中。读者记得修改

环境
- window 10
- .net core 8.0
- godot 4.2.1
- visual studio 2022
visual studio 配置
- GD_Extesion:Godot工具类,后面用于导出
- Assests:资源文件夹
- Utils:工具类
- Interfaces:接口类
- GD_Program:Godot运行逻辑
- SceneModels:场景脚本实际运行类,IOC装配生成
- Services:服务类
- Program.cs:IOC容器位置
- Godot:Godot引擎生成解决方案
- Scene:挂载脚本,只用于建立脚本连接关系

详细的配置看我这篇文章
Godot 学习笔记(5):彻底的项目工程化,解决GodotProjectDir is null+工程化范例
Nuget 推荐
| Nuget | 介绍 |
|---|---|
| Newtonsoft.Json | 高性能Json序列化库 |
| Bogus | 随机测试数据生成,比如随机数据,随机人民,地名,手机号,账号,密码 |
| Microsoft.Extensions.DependencyInjection | 微软IOC框架,个人推荐 |
| Autofac | 第三方IOC 框架,性能也不错 |
| Nlog | 日志管理 |
| FreeSql | 数据库ORM框架,个人推荐 |
| SqlSugar | 数据库ORM框架,一般来说够用了,游戏开发也不是高频并发操作 |
| MiniExcel | Excel ORM框架,简易操作。建议使用CSV |
| Microsoft.AspNetCore.SignalR.Common | 微软开发即时通讯框架,用于解决多人联网 |
| Grpc | 谷歌开发的即使通讯框架,用于解决多人联网 |
NewtonSoft 成功

//以匿名对象为例
GD.Print(JsonConvert.SerializeObject(new
{Name = "小王",Age = "24"
}));

Bogus 成功

Github文档地址
Bugous Github文档地址

随机生成
//以随机数为例
var faker = new Faker();
for(var i = 0; i < 10; i++)
{GD.Print($"Bogus,int 0-10:[{faker.Random.Int(0, 10)}]");
}

构造器生成
public class MyStudent
{public int Id { get; set; }public string? Name { get; set; }public int Age { get; set; }/// <summary>/// 构建faker构造器/// </summary>public static Faker<MyStudent> Faker = new Faker<MyStudent>().RuleFor(t=>t.Id,f=>f.IndexFaker).RuleFor(t=>t.Name,f=>f.Name.FindName()).RuleFor(t=>t.Age,f=>f.Random.Int(10,30));}
//以构造器为例
for (var i = 0; i < 10; i++)
{var stu = MyStudent.Faker.Generate();GD.Print($"Bogus:[{JsonConvert.SerializeObject(stu)}]");
}

构造器+接口(推荐)
个人建议,上个接口,更规范一点
public interface IModelFaker<T> where T : class
{public T FakerOne();public IEnumerable<T> FakeMany(int num);
}
public class MyStudent : IModelFaker<MyStudent>
{public int Id { get; set; }public string? Name { get; set; }public int Age { get; set; }/// <summary>/// 构建faker构造器/// </summary>private Faker<MyStudent> faker = new Faker<MyStudent>().RuleFor(t => t.Id, f => f.IndexFaker).RuleFor(t => t.Name, f => f.Name.FindName()).RuleFor(t => t.Age, f => f.Random.Int(10, 30));public MyStudent FakerOne(){return faker.Generate();}public IEnumerable<MyStudent> FakeMany(int num){return faker.Generate(num);}
}
文件夹设置
因为后面会涉及到文件夹的设置问题,我这里简单说明一下

添加配置

Visual Studio C# 项目生成时复制项目资源目录到生成目录
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>
NlogHelper.cs
Godot的输出比较特别,需要特别处理一下
public class NlogHelper
{private Logger logger;public NlogHelper(){var url = string.Format("{0}Assests/NLog.config", AppDomain.CurrentDomain.BaseDirectory.ToString());GD.Print($"Nlog加载完毕,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($"[info]:{msg}");logger.Info(msg);}public void Error(string msg){GD.PrintErr(msg);GD.PushError(msg);logger.Error(msg);}public void Warning(string msg){GD.Print($"[warning]:{msg}");GD.PushWarning(msg);logger.Warn(msg);}
}
Nloghelper使用


测试
nlogHelper.Debug("Debug");
nlogHelper.Info("Info");
nlogHelper.Warning("Warning");
nlogHelper.Error("Error");




FreeSql 以Sqlite为例
FreeSql官方文档
FreeSql官方文档

sqlite3 安装,CodeFrist则不需要安装。我这里用CodeFrist
SQLite 安装
生成Sqlite数据库文件,这里我取名为sqliteDb.db
sqlite3 sqliteDb.db
.open sqliteDb.db

Nuget引入,FreeSql核心和FreeSql的Sqlite支持


FreeSqlHelper CodeFrist模式
C# FreeSql使用,基于Sqlite的DB Frist和Code First测试
T_ModelBase 数据库基类+Bogus随机生成
/// <summary>
/// 基类
/// </summary>
public abstract class T_ModelBase
{/// <summary>/// 主键自增/// </summary>[Column(IsPrimary =true,IsIdentity =true)]public long Id { get; set; }/// <summary>/// 创建时间/// </summary>public DateTime CreateTime { get; set; } = DateTime.Now;/// <summary>/// 更新时间/// </summary>public DateTime UpdateTime { get; set; } = DateTime.Now;/// <summary>/// 假删除/// </summary>public bool IsDelete { get; set; } = false;public DateTime DeleteTime { get; set; }
}
T_Person,数据库插入类,我习惯用T开头带表数据库实体
public class T_Person : T_ModelBase, IModelFaker<T_Person>
{public int Age { get; set; }public string Name { get; set; }private Faker<T_Person> faker = new Faker<T_Person>().RuleFor(t => t.Id, f => f.IndexFaker).RuleFor(t => t.CreateTime, f => f.Date.Between(new DateTime(2024, 1, 1), DateTime.Now)).RuleFor(t => t.Name, f => f.Name.FindName()).RuleFor(t => t.Age, f => f.Random.Int(10, 30));public IEnumerable<T_Person> FakeMany(int num){return faker.Generate(num);}public T_Person FakerOne(){return faker.Generate();}
}
连接,插入,查询测试使用
var isConnect = freeSqlHelper.SqliteDb.Ado.ExecuteConnectTest(10);
GD.Print($"数据库连接状态:[{isConnect}]");var insertLists = new T_Person().FakeMany(10);var insertName = freeSqlHelper.SqliteDb.Insert(insertLists).ExecuteAffrows();
GD.Print($"数据库插入[{insertName}]行数据");var selectLists = freeSqlHelper.SqliteDb.Queryable<T_Person>().OrderByDescending(t=>t.Id).Take(10).ToList();foreach (var item in selectLists)
{GD.Print(JsonConvert.SerializeObject(item));
}


GD_Extension项目打包,用于复用
我写到后面的时候发现,Interfaces应当放在GD_Extension中。读者记得修改

Icon封面准备
【VisualStudio 】VisualStudio2022 项目模板
准备一个Godot Icon的图片,用于封面展示

visual studio 导出







Github项目地址,包含模板文件
Gclove2000/GodotNet_Csharp_IOC_SimpleTemplate
总结
我这里就是简单引入了几个通用的Nuget,这个我后期是会日常去维护的。这个就是我们的脚手架了。而且我在GD_Extension中尽量少的使用Godot的Api。基本只使用了Godot Api 的输出语句。所以这个随着Godot 版本的更新,基本不需要大改。这个以后就是我们宝贵的Godot资源库了。
相关文章:
Godot.NET C# 工程化开发(1):通用Nuget 导入+ 模板文件导出,包含随机数生成,日志管理,数据库连接等功能
文章目录 前言Github项目地址,包含模板文件后期思考补充项目设置编写失误环境visual studio 配置详细的配置看我这篇文章 Nuget 推荐NewtonSoft 成功Bogus 成功Github文档地址随机生成构造器生成构造器接口(推荐) 文件夹设置Nlog 成功!Nlog.configNlogHe…...
数据仓库——雪花模式以及层次递归
层次结构 钻取 向下钻取:对某些代表事实的报表中添加维度细节 向上钻取:从某些代表事实的报表中去除维度细节 属性层次 提供了一种自然方法,用于顺序地在不断深入的层次上组织事实。许多维度可以被理解为包含连续主从关系的属性层次。此类…...
Transformer的前世今生 day09(Transformer的框架概述)
前情提要 编码器-解码器结构 如果将一个模型分为两块:编码器和解码器那么编码器-解码器结构为:编码器负责处理输入,解码器负责生成输出流程:我们先将输入送入编码器层,得到一个中间状态state,并送入解码器…...
Qt 压缩/解压文件
前面讲了很多Qt的文件操作,文件操作自然就包括压缩与解压缩文件了,正好最近项目里要用到压缩以及解压缩文件,所以就研究了一下Qt如何压缩与解压缩文件。 QZipReader/QZipWriter QZipReader 和 QZipWriter 类提供了用于读取和写入 ZIP 格式文…...
【leetcode刷题之路】面试经典150题(8)——位运算+数学+一维动态规划+多维动态规划
文章目录 20 位运算20.1 【位运算】二进制求和20.2 【位运算】颠倒二进制位20.3 【位运算】位1的个数20.4 【位运算】只出现一次的数字20.5 【哈希表】【位运算】只出现一次的数字 II20.6 【位运算】数字范围按位与 21 数学21.1 【双指针】回文数21.2 【数学】加一21.3 【数学】…...
JetBrains全家桶激活,分享 WebStorm 2024 激活的方案
大家好,欢迎来到金榜探云手! WebStorm公司简介 JetBrains 是一家专注于开发工具的软件公司,总部位于捷克。他们以提供强大的集成开发环境(IDE)而闻名,如 IntelliJ IDEA、PyCharm、和 WebStorm等。这些工具…...
Sublime 彻底解决中文乱码
1. 按ctrl,打开Console,输入如下代码: import urllib.request,os; pf Package Control.sublime-package; ipp sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHand…...
复旦大学EMBA校友出席两会建言献策助力中国发展
阳春三月,备受瞩目的全国两会如期召开。期间,复旦大学EMBA多位校友作为第十四届全国人民代表大会代表、第十四届全国政协委员与全国各地代表共商国是。 无论是作为大型央企负责人,还是作为科创企业的中坚力量,复旦大学EM…...
virtualbox导入vdi
新建虚拟机 点击新建 输入新建属性 配置cpu和内存 虚拟硬盘 这里选择已有的vdi文件 摘要 这里点击完成 虚拟机添加成功 点击启动,启动虚拟机 注意 这个时候的ip,还是以前镜像的ip,如果两个镜像一起启动,则需要修 改ip地…...
【信号处理】基于DGGAN的单通道脑电信号增强和情绪检测(tensorflow)
关于 情绪检测,是脑科学研究中的一个常见和热门的方向。在进行情绪检测的分类中,真实数据不足,经常导致情绪检测模型的性能不佳。因此,对数据进行增强,成为了一个提升下游任务的重要的手段。本项目通过DCGAN模型实现脑…...
使用 Docker Compose 部署 Spring Boot 应用
使用 Docker Compose 部署 Spring Boot 应用 第一步:创建 Spring Boot 应用的 Dockerfile 在您的 Spring Boot 项目根目录中创建一个 Dockerfile。 编辑 Dockerfile,添加以下内容: # 基础镜像使用 OpenJDK FROM openjdk:11-jdk-slim# 维护者…...
nginx 正向代理 https
问题背景 因为网络环境受限,应用服务器无法直接访问外网,需要前置机上中转一下,这种情况可在应用服务器修改/etc/hosts文件指向前置机,在前置机上的nginx设置四层代理,从而出站。 方案 根据How to Use NGINX as an …...
vue3从其他页面跳转页面头部组件菜单el-menu菜单高亮
主要代码 import { ref, onMounted, watch } from vue; const activeIndex ref("/"); const route useRoute();onMounted(() > {updateActiveMenu(); });watch(() > route.path, updateActiveMenu);function updateActiveMenu() {// 根据路由更新activeMenu…...
python 条件循环语句
python 条件循环语句 一、条件控制语句1. Python3 条件控制2. if 语句3. if 嵌套4. match...case5. 注意: 二、循环控制语句1. Python3 循环语句2. while 循环3. 无限循环4. while 循环使用 else 语句5. 简单语句组6. for 语句7. for...else8. break 和 continue 语…...
CIM搭建实现发送消息的效果
目录 背景过程1、下载代码2、进行配置3、直接启动项目4、打开管理界面5、启动web客户端实例项目6、发送消息 项目使用总结 背景 公司项目有许多需要发送即时消息的场景,之前一直采用的是传统的websocket连接,它会存在掉线严重,不可重连&…...
C++第十三弹---内存管理(下)
✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】 目录 1、operator new与operator delete函数 1.1、operator new与operator delete函数 2、new和delete的实现原理 2.1、内置类型 2.2、自定义类型 …...
Python爬虫学习完整版
一、什么是爬虫 网络爬虫,是一种按照一定规则,自动抓取互联网信息的程序或者脚本。由于互联网数据的多样性和资源的有限性,根据用户需求定向抓取相关网页并分析也成为如今主流的爬取策略。 1 爬虫可以做什么 你可以爬取网络上的的图片&#…...
JavaScript中的继承方式详解
Question JavaScript实现继承的方式? 包含原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承、寄生组合式继承和ES6 类继承 JavaScript实现继承的方式 在JavaScript中,实现继承的方式多种多样,每种方式都有其优势和适用场景。以下…...
Git基础(23):Git分支合并实战保姆式流程
文章目录 前言准备正常分支合并1. 创建两个不冲突分支2. 将dev合并到test 冲突分支合并1. 制造分支冲突2. 冲突合并 前言 Git分支合并操作 准备 这里先在Gitee创建了一个空仓库,方便远程查看内容。 正常分支合并 1. 创建两个不冲突分支 (1…...
为什么有些前端一直用 div 当按钮,而不是用 button?
1. HTML 中的 <div> 和 <button> 在了解为什么有些前端开发者更喜欢使用 <div> 作为按钮之前,让我们先来了解一下 <div> 和 <button> 标签在 HTML 中的作用和区别。 <div>:是 HTML 中的一个通用容器元素࿰…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...
