godot+c#使用godot-sqlite连接数据库
前言
查阅了很多资料都没有关于godot使用c#连接godot-sqlite的,因此研究出了方法,注意该方法可适用4.5及以上,其他版本未验证
采用如下方法,你可以使用c#操作sqlite实现
存档和读档
功能
步骤
导入和联通
首先需要下载导入
- 创建一个游戏项目
- 点击[AssetLib]搜索sqlite,等待出现【Godot-SQlite】,并且点击下载
- 然后直接导入到项目,这个时候可以在文件夹看到【addons】文件夹
- 点击【项目】-【项目设置】-【插件】,进行勾选启用,注意这里需要addons文件夹在res的根目录下,否则识别不到
- 接下来尝试联通数据库,在查阅了很多资料,都说需要通过这个路径加载sqlite插件联通数据库
res://addons/godot-sqlite/bin/gdsqlite.gdns
- 不知道是不是版本原因实际是没有这个文件的,经过测试最终使用如下实现联通了sqlite数据库
- 新建一个node2d节点,然后挂载gd脚本,因为它是适配gd语言的,所以对gd语言的适配性是最好的
- gd脚本代码看如下
- 编写完毕之后,编译并启动游戏
- 观察控制台
- 建立的脚本名称是SqliteBridge.gd,内容如下
extends Nodefunc _ready():if ClassDB.class_exists("SQLite"):var db = ClassDB.instantiate("SQLite")db.path = "user://test.db"if db.open_db():print("数据库打开成功!")db.query("CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, name TEXT);")print("表已经创建或已存在")db.close_db()else:print("打开sqlite数据库失败")else:print("SQLite类未找到,请确保插件可用并且存在可执行文件.")
启动游戏之后控制台如下
控制台提示如下
Opened database successfully (C:/Users/xxx/AppData/Roaming/Godot/app_userdata/sqlTest/test.db)
数据库打开成功!
表已经创建或已存在
Closed database (C:/Users/xxx/AppData/Roaming/Godot/app_userdata/sqlTest/test.db)
- 并且提示你打开的数据库文件的路径是什么,如果顺着路径打开文件夹会看到如下
- 通过如上的脚本代码,我们设置访问的数据库路径是user://test.db,设置user://的目的是因为这个路径是可读写的
使用c#操作godot-sqlite
-
正如前面所说,godot-sqlite是适配gd语言的,如果要通过c#操作这个,必须使用一个桥接代码,中转访问
-
为了演示方便我这里计划操作一个学生信息表
CREATE TABLE IF NOT EXISTS students (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT NOT NULL,age INTEGER NOT NULL,grade TEXT
)
- 那么如上只是一个示例,到正式的开发游戏,你可以把表替换为玩家信息表,物品表,怪物信息表等
- 同时,为了方便操作,我这里采用了和JAVA的JDBC的模式来操作表,以及进行增删改查
- 为了可以实现这个,首先我们需要打开游戏项目路径,找到有csproj命名的那层文件夹
- 在该文件夹的地址栏输入cmd打开命令行,输入如下
dotnet add package System.Data.SQLite.Core
注意:该操作必须你已经配置好了DOTNET
- 该操作的目的是为了可以引入
System.Data.SQLite
,否则项目是否无法引用数据库连接,会报错
那么执行修改之后,以我的项目为例,会从
<Project Sdk="Godot.NET.Sdk/4.4.1"><PropertyGroup><TargetFramework>net8.0</TargetFramework><EnableDynamicLoading>true</EnableDynamicLoading></PropertyGroup>
</Project>
变成
<Project Sdk="Godot.NET.Sdk/4.4.1"><PropertyGroup><TargetFramework>net8.0</TargetFramework><EnableDynamicLoading>true</EnableDynamicLoading></PropertyGroup><ItemGroup><PackageReference Include="System.Data.SQLite.Core" Version="1.0.119" /></ItemGroup>
</Project>
- 首先创建一个数据库连接代码
DBConnection.cs
using System;
using System.Data.SQLite;
using Godot;
using System.IO;public static class DBConnection
{private static SQLiteConnection _connection;private static string _dbPath = "user://test.db";// 获取数据库连接:cite[7]public static SQLiteConnection GetConnection(){if (_connection == null){// 确保用户数据目录存在string userDir = OS.GetUserDataDir();string fullPath = Path.Combine(userDir, "test.db");// 如果数据库文件不存在,则创建它if (!File.Exists(fullPath)){SQLiteConnection.CreateFile(fullPath);}string connectionString = $"Data Source={fullPath};Version=3;";_connection = new SQLiteConnection(connectionString);_connection.Open();// 初始化数据库表InitializeTables();}return _connection;}// 初始化数据库表:cite[1]private static void InitializeTables(){string createTableSQL = @"CREATE TABLE IF NOT EXISTS students (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT NOT NULL,age INTEGER NOT NULL,grade TEXT)";using (var command = new SQLiteCommand(createTableSQL, _connection)){command.ExecuteNonQuery();}GD.Print("数据库表初始化成功");}// 关闭数据库连接public static void CloseConnection(){if (_connection != null){_connection.Close();_connection = null;GD.Print("数据库连接已经关闭");}}
}
- 创建对应的学生信息类实体
Student.cs
using Godot;
using System;public class Student
{public int Id { get; set; }public string Name { get; set; }public int Age { get; set; }public string Grade { get; set; }public Student() { }public Student(string name, int age, string grade){Name = name;Age = age;Grade = grade;}// 重写ToString方法便于输出public override string ToString(){return $"Student [ID: {Id}, Name: {Name}, Age: {Age}, Grade: {Grade}]";}
}
- 创建学生信息表的操作DAO层
StudentDAO.cs
using System;
using System.Data.SQLite;
using System.Collections.Generic;
using Godot;
using System.IO;public class StudentDAO
{private static string GetDbPath(){string userDir = OS.GetUserDataDir();return Path.Combine(userDir, "test.db");}// 添加学生:cite[1]public static bool AddStudent(Student student){string dbPath = GetDbPath();string connectionString = $"Data Source={dbPath};Version=3;";// 使用 using 语句确保连接在使用后会被正确关闭和释放:cite[10]using (var connection = new SQLiteConnection(connectionString)){try{connection.Open();string sql = @"INSERT INTO students (name, age, grade) VALUES (@name, @age, @grade)";using (var command = new SQLiteCommand(sql, connection)){command.Parameters.AddWithValue("@name", student.Name);command.Parameters.AddWithValue("@age", student.Age);command.Parameters.AddWithValue("@grade", student.Grade);int rowsAffected = command.ExecuteNonQuery();GD.Print($"新增学生: {student.Name}, 操作结果: {rowsAffected}");return rowsAffected > 0;}}catch (Exception e){GD.PrintErr($"添加学生失败: {e.Message}");return false;}} // using 结束处,connection 会被自动 Dispose}// 根据ID删除学生:cite[5]public static bool DeleteStudent(int id){string dbPath = GetDbPath();string connectionString = $"Data Source={dbPath};Version=3;";try{using (var connection = new SQLiteConnection(connectionString)){connection.Open();string sql = "DELETE FROM students WHERE id = @id";using (var command = new SQLiteCommand(sql, connection)){command.Parameters.AddWithValue("@id", id);int rowsAffected = command.ExecuteNonQuery();GD.Print($"使用ID删除学生: {id}, 操作结果: {rowsAffected}");return rowsAffected > 0;}}}catch (Exception e){GD.PrintErr($"删除学生失败: {e.Message}");return false;}}// 更新学生信息:cite[5]public static bool UpdateStudent(Student student){string dbPath = GetDbPath();string connectionString = $"Data Source={dbPath};Version=3;";try{using (var connection = new SQLiteConnection(connectionString)){connection.Open();string sql = @"UPDATE students SET name = @name, age = @age, grade = @grade WHERE id = @id";using (var command = new SQLiteCommand(sql, connection)){command.Parameters.AddWithValue("@name", student.Name);command.Parameters.AddWithValue("@age", student.Age);command.Parameters.AddWithValue("@grade", student.Grade);command.Parameters.AddWithValue("@id", student.Id);int rowsAffected = command.ExecuteNonQuery();GD.Print($"更新学生信息: {student.Name}, 操作结果: {rowsAffected}");return rowsAffected > 0;}}}catch (Exception e){GD.PrintErr($"更新学生信息失败: {e.Message}");return false;}}// 获取所有学生:cite[1]public static List<Student> GetAllStudents(){string dbPath = GetDbPath();string connectionString = $"Data Source={dbPath};Version=3;";var students = new List<Student>();try{using (var connection = new SQLiteConnection(connectionString)){connection.Open();string sql = "SELECT * FROM students";using (var command = new SQLiteCommand(sql, connection))using (var reader = command.ExecuteReader()){while (reader.Read()){students.Add(new Student{Id = Convert.ToInt32(reader["id"]),Name = reader["name"].ToString(),Age = Convert.ToInt32(reader["age"]),Grade = reader["grade"].ToString()});}}}GD.Print($"已获取 {students.Count} 数量学生信息");}catch (Exception e){GD.PrintErr($"获取学生信息失败: {e.Message}");}return students;}// 根据ID查询学生:cite[7]public static Student GetStudentById(int id){string dbPath = GetDbPath();string connectionString = $"Data Source={dbPath};Version=3;";try{using (var connection = new SQLiteConnection(connectionString)){connection.Open();string sql = "SELECT * FROM students WHERE id = @id";using (var command = new SQLiteCommand(sql, connection)){command.Parameters.AddWithValue("@id", id);using (var reader = command.ExecuteReader()){if (reader.Read()){GD.Print($"使用ID获取学生信息: {id}");return new Student{Id = Convert.ToInt32(reader["id"]),Name = reader["name"].ToString(),Age = Convert.ToInt32(reader["age"]),Grade = reader["grade"].ToString()};}}}}}catch (Exception e){GD.PrintErr($"获取学生信息失败: {e.Message}");}GD.Print($"未找到学生信息: {id}");return null;}// 根据姓名查询学生(模糊查询):cite[7]public static List<Student> GetStudentsByName(string name){string dbPath = GetDbPath();string connectionString = $"Data Source={dbPath};Version=3;";var students = new List<Student>();try{using (var connection = new SQLiteConnection(connectionString)){connection.Open();string sql = "SELECT * FROM students WHERE name LIKE @name";using (var command = new SQLiteCommand(sql, connection)){command.Parameters.AddWithValue("@name", $"%{name}%");using (var reader = command.ExecuteReader()){while (reader.Read()){students.Add(new Student{Id = Convert.ToInt32(reader["id"]),Name = reader["name"].ToString(),Age = Convert.ToInt32(reader["age"]),Grade = reader["grade"].ToString()});}}}}GD.Print($"已获取 {students.Count} 行数据包含该名称的学生: {name}");}catch (Exception e){GD.PrintErr($"根据名称获取学生失败: {e.Message}");}return students;}
}
- 新建桥接代码,并且将该脚本绑定到node2d节点上
SQLiteBridge.cs
using Godot;
using System;
using System.Collections.Generic;public partial class SQLiteBridge : Node2D
{public override void _Ready(){GD.Print("Starting SQLite database operations...");// 测试数据库操作TestDatabaseOperations();GD.Print("All database operations completed");}private void TestDatabaseOperations(){// 1. 添加学生GD.Print("\n=== 添加学生 ===");var student1 = new Student("张三", 20, "大三");var student2 = new Student("李四", 19, "大二");var student3 = new Student("王五", 21, "大三");StudentDAO.AddStudent(student1);StudentDAO.AddStudent(student2);StudentDAO.AddStudent(student3);// 2. 查询所有学生GD.Print("\n=== 查询所有学生 ===");List<Student> allStudents = StudentDAO.GetAllStudents();foreach (var student in allStudents){GD.Print(student.ToString());}// 3. 根据ID查询学生GD.Print("\n=== 根据ID查询学生 ===");Student retrievedStudent = StudentDAO.GetStudentById(1);if (retrievedStudent != null){GD.Print($"找到学生: {retrievedStudent}");}// 4. 根据姓名查询学生GD.Print("\n=== 根据姓名查找学生 ===");List<Student> studentsByName = StudentDAO.GetStudentsByName("张");foreach (var student in studentsByName){GD.Print($"找到学生: {student}");}// 5. 更新学生信息GD.Print("\n=== 更新学生信息 ===");if (retrievedStudent != null){retrievedStudent.Age = 22;retrievedStudent.Grade = "大四";StudentDAO.UpdateStudent(retrievedStudent);}// 6. 删除学生GD.Print("\n=== 删除学生 ===");StudentDAO.DeleteStudent(2);// 7. 验证删除结果GD.Print("\n=== 验证删除结果 ===");List<Student> remainingStudents = StudentDAO.GetAllStudents();foreach (var student in remainingStudents){GD.Print($"学生: {student}");}}public override void _ExitTree(){}
}
- 然后进行编译并且启动游戏
这个时候控制台提示信息如下
Starting SQLite database operations...=== 添加学生 ===
[2025-09-14 15:10:49.0435337] System.Data.SQLite (Preload): Native library pre-loader is trying to load native SQLite library "F:\godot_workSpace\SqlTest\.godot\mono\temp\bin\Debug\runtimes\win-x64\native\SQLite.Interop.dll"...
新增学生: 张三, 操作结果: 1
新增学生: 李四, 操作结果: 1
新增学生: 王五, 操作结果: 1=== 查询所有学生 ===
已获取 3 数量学生信息
Student [ID: 8, Name: 张三, Age: 20, Grade: 大三]
Student [ID: 9, Name: 李四, Age: 19, Grade: 大二]
Student [ID: 10, Name: 王五, Age: 21, Grade: 大三]=== 根据ID查询学生 ===
未找到学生信息: 1=== 根据姓名查找学生 ===
已获取 1 行数据包含该名称的学生: 张
找到学生: Student [ID: 8, Name: 张三, Age: 20, Grade: 大三]=== 更新学生信息 ====== 删除学生 ===
使用ID删除学生: 2, 操作结果: 0=== 验证删除结果 ===
已获取 3 数量学生信息
学生: Student [ID: 8, Name: 张三, Age: 20, Grade: 大三]
学生: Student [ID: 9, Name: 李四, Age: 19, Grade: 大二]
学生: Student [ID: 10, Name: 王五, Age: 21, Grade: 大三]
All database operations completed
-
然后我们使用工具类,找到本地的test.db打开该数据库,我们就可以看到如下数据
-
这里我使用dbeaver软件,然后选择SQlite
-
然后找到表students,我们就可以看到我们操作的表数据了
结语
- 如上我们就实现了通过c#操作godot-sqlite,然后可以用于在游戏的存档和读档