SwiftGodot


SwiftPM compatible Platforms Swift Package Index License

SwiftGodot 为 Godot 4.3 游戏引擎提供 Swift 语言绑定,使用新的 GDExtension 系统(对于 4.1 的兼容性,请使用 4.1 分支;对于 4.2 的兼容性,请使用 4.2 分支)。

SwiftGodot 可以用于构建一个可以添加到现有 Godot 项目的扩展,你的代码为游戏引擎提供服务;或者它可以作为 API 与 SwiftGodotKit 一起使用,SwiftGodotKit 将 Godot 嵌入为一个直接从 Swift 驱动的应用程序。

教程和文档

社区感兴趣的内容

从 Swift 驱动 Godot 的优势在于,在 MacOS 上你可以从 Xcode 调试你的代码以及 Godot 代码。

Screen.Recording.2023-04-02.at.11.59.18.AM.mov

为什么选择 SwiftGodot?

快速入门

SwiftGodotKick 项目可以创建一个带有 Swift 的骨架模板 GDExtension,以及一个独立的 SwiftGodotKit 项目,可用于在 MacOS 上快速迭代你的游戏。

支持的平台

目前,SwiftGodot 可以用于针对 iOS、Linux、macOS 或 Windows 平台的项目。 可能可以针对其他平台,但尚未完成对其他平台的测试,并且此时无法验证稳定性。

开发状态

SwiftGodot 构建于 GDExtension 框架之上,该框架仍处于实验性状态,因此 SwiftGodot 也仍处于实验性状态。为了修复重大错误或包含关键功能,兼容性可能会中断。 话虽如此,Godot API 的大部分表面已经实现,SwiftGodot 适合用于中小型项目。

使用 SwiftGodot

有两种使用 SwiftGodot 的方法,你可以在 SwiftPM 中通过使用此地址引用此模块 - 它将为你触发一个完整的源代码构建;或者为了在 MacOS 上快速迭代,你可以在对等方 https://github.com/migueldeicaza/SwiftGodotBinary 中使用一个方便的二进制文件

目前这需要 Swift 5.9 或 Xcode 15。

使用此存储库

你应该可以通过从 SwiftPM 将其作为包引用来完成所有设置,但如果你只想使用绑定生成器,你可能需要打开 Generator 项目并编辑 okList 变量以缩短构建时间。

从 Swift 驱动 Godot

要从 Swift 驱动 Godot,请使用配套的 SwiftGodotKit 模块,该模块直接将 Godot 嵌入到你的应用程序中,允许你从代码启动 Godot 运行时。

创建扩展

创建一个可以在 Godot 中使用的扩展需要几个组件

你的 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 中的 "Add Child Node" 命令(在 MacOS 上为 Command-A)从你的代码中引用它,然后在层次结构中找到它。

在我们上面的例子中,它将出现在 Node3D 下,因为它是一个 Node3D 子类。

社区

加入 Slack 上的社区

贡献

有想要添加的错误修复或功能请求吗? 考虑贡献! 加入我们的 社区 以开始。