SwiftGodot 为 Godot 4.2 游戏引擎提供了 Swift 语言绑定,使用了新的 GDExtension 系统(为了兼容 4.1 版本,请使用 4.1 分支;即将发布的 4.3 版本的预览版在 4.3 分支中)。
SwiftGodot 可以用于构建一个可以添加到现有 Godot 项目的扩展,在其中你的代码为游戏引擎提供服务;或者它可以作为 API 与 SwiftGodotKit 一起使用,SwiftGodotKit 将 Godot 嵌入为一个直接由 Swift 驱动的应用程序。
教程和文档
社区关注
从 Swift 驱动 Godot 的优势在于,在 MacOS 上,你可以从 Xcode 以及 Godot 代码中调试你的代码。
与 C# 不同,没有由 GC 引起的游戏卡顿。
SwiftGodotKick 项目可以创建一个带有 Swift 的骨架模板 GDExtension,以及一个独立的 SwiftGodotKit 项目,可以用于在 MacOS 上快速迭代你的游戏。
目前,SwiftGodot 可以用于以 iOS、Linux、macOS 或 Windows 平台为目标的项目。 可能可以以其他平台为目标,但尚未完成对其他平台的测试,目前无法验证稳定性。
SwiftGodot 构建在 GDExtension 框架之上,该框架仍处于 实验性 状态,因此 SwiftGodot 也仍处于实验性状态。为了修复重大错误或包含关键功能,兼容性可能会被破坏。 话虽如此,Godot API 表面 的大部分已被实现,SwiftGodot 适合用于中小型项目。
使用 SwiftGodot 有两种方式,你可以在 SwiftPM 中通过使用此地址引用此模块 - 它将为你触发完整的源代码构建;或者为了在 MacOS 上快速迭代,你可以使用对等 https://github.com/migueldeicaza/SwiftGodotBinary 中方便的二进制文件
目前这需要 Swift 5.9 或 Xcode 15。
你应该可以通过从 SwiftPM 引用它作为包来完成所有设置,但如果你只想处理绑定生成器,你可能想要打开 Generator 项目并编辑 okList
变量以缩短构建时间。
要从 Swift 驱动 Godot,请使用配套的 SwiftGodotKit
模块,该模块将 Godot 直接嵌入到你的应用程序中,这允许你从你的代码启动 Godot 运行时。
创建一个可以在 Godot 中使用的扩展需要几个组件
.gdextension
文件,用于描述在哪里可以找到所需的 Swift 库资源你的 Swift 代码将被编译成 Godot 将调用的共享库。 要开始使用,最简单的方法是创建一个引用 Swift Godot 包的 Swift 库包,就像这样
// swift-tools-version: 5.9
import PackageDescription
let package = Package(
name: "MyFirstGame",
products: [
.library(name: "MyFirstGame", type: .dynamic, targets: ["MyFirstGame"]),
],
dependencies: [
.package(url: "https://github.com/migueldeicaza/SwiftGodot", branch: "main")
],
targets: [
.target(
name: "MyFirstGame",
dependencies: ["SwiftGodot"])]
)
以上将为你编译所有 SwiftGodot - 或者,如果你不需要访问源代码,你可以使用 SwiftPM 的 .binaryTarget
功能,并引用我已在 GitHub 上方便发布的 .xcframework
,地址为 https://github.com/migueldeicaza/SwiftGodotBinary
下一步是创建你的源文件,并在其中施展魔法,这里我们声明一个旋转的立方体
import SwiftGodot
@Godot(.tool)
class SpinningCube: Node3D {
public override func _ready () {
let meshRender = MeshInstance3D()
meshRender.mesh = BoxMesh()
addChild(node: meshRender)
}
public override func _process(delta: Double) {
rotateY(angle: delta)
}
}
此外,你需要为你的项目编写一些胶水代码,以便可以被 Godot 加载,你可以像这样操作
/// We register our new type when we are told that the scene is being loaded
func setupScene (level: GDExtension.InitializationLevel) {
if level == .scene {
register(type: SpinningCube.self)
}
}
// Export our entry point to Godot:
@_cdecl("swift_entry_point")
public func swift_entry_point(
interfacePtr: OpaquePointer?,
libraryPtr: OpaquePointer?,
extensionPtr: OpaquePointer?) -> UInt8
{
print ("SwiftGodot Extension loaded")
guard let interfacePtr, let libraryPtr, let extensionPtr else {
print ("Error: some parameters were not provided")
return 0
}
initializeSwiftModule(interfacePtr, libraryPtr, extensionPtr, initHook: setupScene, deInitHook: { x in })
return 1
}
或者,你可以使用 #initSwiftExtension
宏
import SwiftGodot
#initSwiftExtension(cdecl: "swift_entry_point", types: [SpinningCube.self])
此外,你可以使用 EntryPointGeneratorPlugin
,它将扫描目标源文件并生成名为 swift_entry_point
的入口点,其中包含 types
数组,其中提到了所有附加了 @Godot
宏的类。 你只需要在你的 Package.swift
中添加 plugins
条目,如下所示
let package = Package(
name: "MyFirstGame",
products: [
.library(name: "MyFirstGame", type: .dynamic, targets: ["MyFirstGame"]),
],
dependencies: [
.package(url: "https://github.com/migueldeicaza/SwiftGodot", branch: "main")
],
targets: [
.target(
name: "MyFirstGame",
dependencies: ["SwiftGodot"],
// this plugin will generate a source file visible to compiler with '#initSwiftExtension(cdecl: "swift_entry_point", types: [SpinningCube.self])'
plugins: [
.plugin(name: "EntryPointGeneratorPlugin", package: "SwiftGodot")
]
)
],
)
为了使你的扩展可供 Godot 使用,你需要为所有目标平台构建二进制文件,并创建一个 .gdextension
文件,其中列出此有效负载,以及你上面声明的入口点。
你可以在名为 MyFirstGame.gdextension
的文件中创建类似这样的内容
[configuration]
entry_symbol = "swift_entry_point"
compatibility_minimum = 4.2
[libraries]
macos.debug = "res://bin/MyFirstGame"
macos.release = "res://bin/MyFirstGame"
windows.debug.x86_32 = "res://bin/MyFirstGame"
windows.release.x86_32 = "res://bin/MyFirstGame"
windows.debug.x86_64 = "res://bin/MyFirstGame"
windows.release.x86_64 = "res://bin/MyFirstGame"
linux.debug.x86_64 = "res://bin/MyFirstGame"
linux.release.x86_64 = "res://bin/MyFirstGame"
linux.debug.arm64 = "res://bin/MyFirstGame"
linux.release.arm64 = "res://bin/MyFirstGame"
linux.debug.rv64 = "res://bin/MyFirstGame"
linux.release.rv64 = "res://bin/MyFirstGame"
android.debug.x86_64 = "res://bin/MyFirstGame"
android.release.x86_64 = "res://bin/MyFirstGame"
android.debug.arm64 = "res://bin/MyFirstGame"
android.release.arm64 = "res://bin/MyFirstGame"
在上面的示例中,无论平台如何,扩展始终期望平台特定的有效负载被称为 "MyFirstGame"。 如果你想将你的扩展分发给其他用户并拥有单个有效负载,你将需要手动为这些有效负载设置不同的名称。
你需要将新的 .gdextension
文件以及它引用的资源复制到现有项目中。
一旦在那里,Godot 将为你加载它。
一旦你创建了你的扩展并将其加载到 Godot 中,你可以通过在 Godot 中使用 "添加子节点" 命令(MacOS 上为 Command-A)从你的代码中引用它,然后在层级结构中找到它。
在我们上面的示例中,它将出现在 Node3D 下,因为它是一个 Node3D 子类。
加入 Slack 上的社区 Slack
有想要添加的错误修复或功能请求? 考虑贡献! 加入我们的社区以开始。