前言
查阅了很多资料都没有关于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 Node
func _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,然后可以用于在游戏的存档和读档