# spine-godot 运行时文档

> **Licensing**
>
> 将官方的Spine运行时整合到你的应用程序中前请务必阅读 [Spine 运行时许可协议](/spine-runtimes-license) .

# 开始使用

## 安装
有两种不同方式引入 Spine-godot 运行时:
* **spine-godot [GDExtension](https://docs.godotengine.org/en/stable/tutorials/scripting/gdextension/index.html)**: 将一个软件包放入已有的 Godot 项目的 `bin/` 文件夹中即可. 支持 Godot 所支持的全部平台, 将来可能包括由 [W4Games](https://www.w4games.com/) 支持的游戏主机. 缺乏对 `AnimationPlayer` 的支持, 不含 [专用 C# 绑定](https://github.com/godotengine/godot-proposals/issues/8191)功能, 且缺少某个 [细碎的编辑器功能](https://github.com/godotengine/godot-proposals/issues/10985).
* **spine-godot [自定义C++引擎模块](https://docs.godotengine.org/en/stable/development/cpp/custom_modules_in_cpp.html)**: 需要自行构建Godot编辑器和Godot导出模板. 未来大概率不支持游戏主机. 支持其他功能, 如 `AnimationPlayer` 和专用的 C# 绑定.

### 下载 spine-godot GDExtension

<script>
let baseURL = "https://raw.githubusercontent.com/EsotericSoftware/spine-runtimes/refs/heads/";
let spineVersion = undefined;

async function getSpineVersion() {
    if (!spineVersion) {
        const response = await fetch("/spine/version");
        spineVersion = await response.text();
        }
    return spineVersion;
}

async function getV4ExtensionVersions() {
    const response = await fetch(baseURL + spineVersion + "/.github/workflows/spine-godot-extension-v4-all.yml");
    const v4Data = await response.text();
    const pattern = /{\s*"tag":\s*"(.*?)",\s*"version":\s*"(.*?)",\s*"dev":\s*(true|false)\s*}/g;
    const matches = v4Data.match(pattern);
    return matches.map(match => JSON.parse(match));
}

(async () => {
    const spineVersion = await getSpineVersion();
    const versions = [...(await getV4ExtensionVersions())];

    let html = "<ul>";
    for (const version of versions) {
        const versionLabel = "Godot " + version.tag.substring(0, version.tag.indexOf("-"));
        html += `<li><a href="https://spine-godot.s3.eu-central-1.amazonaws.com/${spineVersion}/${version.tag}/spine-godot-extension-${spineVersion}-${version.tag}.zip">${versionLabel}</a></li>`
    }
    html += "</ul>"
    document.querySelector("#ext-urls").innerHTML = html;
 })()
 </script>

 <div id="ext-urls"></div>
!!

请下载适用于 Godot 版本的 spine-godot GDExtension 版本. 解压 `.zip` 文件, 并将 `bin/` 文件夹复制到项目根目录. 这时, 项目中会有一个 `your-project/bin` 文件夹且其中包含一个 `your-project/bin/spine_godot_extension.gdextension` 文件. 完成后启动 Godot 编辑器即可完成安装.

### 下载 spine-godot 引擎模块
<script>

async function getV4Versions() {
    const response = await fetch(baseURL + spineVersion + "/.github/workflows/spine-godot-v4-all.yml");
    const v4Data = await response.text();
    const pattern = /{\s*"tag":\s*"(.*?)",\s*"version":\s*"(.*?)",\s*"mono":\s*(true|false)\s*}/g;
    const matches = v4Data.match(pattern);
    return matches.map(match => JSON.parse(match));
}

async function getV3Versions() {
    const response = await fetch(baseURL + spineVersion + "/.github/workflows/spine-godot.yml");
    const v3Data = await response.text();
    const tagPattern = /GODOT_TAG:\s*(.*)/;
    const versionPattern = /GODOT_VERSION:\s*(.*)/;
    function extractValue(pattern, str) {
        const match = str.match(pattern);
        return match ? match[1] : null;
    }
    const godotTag = extractValue(tagPattern, v3Data);
    const godotVersion = extractValue(versionPattern, v3Data);

    return [{
        tag: godotTag,
        version: godotVersion,
        mono: false
    }];
}

(async () => {
    const spineVersion = (await getSpineVersion());
    const versions = [...(await getV3Versions()), ...(await getV4Versions())];

    let html = "<ul>";
    for (const version of versions) {
        const mono = version.mono ? "-mono" : "";
        html += "<li>Godot " + version.tag.substring(0, version.tag.indexOf("-")) + (version.mono ? " 带 C# 支持" : "");
        html += `
            <ul>
                <li><a href="https://spine-godot.s3.eu-central-1.amazonaws.com/${spineVersion}/${version.tag}/godot-editor-windows${mono}.zip">Windows版编辑器</a></li>
                <li><a href="https://spine-godot.s3.eu-central-1.amazonaws.com/${spineVersion}/${version.tag}/godot-editor-linux${mono}.zip">Linux版编辑器</a></li>
                <li><a href="https://spine-godot.s3.eu-central-1.amazonaws.com/${spineVersion}/${version.tag}/godot-editor-macos${mono}.zip">macOS版编辑器</a></li>
                <li><a href="https://spine-godot.s3.eu-central-1.amazonaws.com/${spineVersion}/${version.tag}/spine-godot-templates-${spineVersion}-${version.tag}${mono}.tpz">适用于Windows, Linux, macOS${!version.mono ? ", Web, Android, iOS的导出模板" : "的导出模板"}</a></li>
            </ul>
        `
        html += "</li>"
    }
    html += "</ul>"
    document.querySelector("#urls").innerHTML = html;
 })()
 </script>

 <div id="urls"></div>
!!

> **注意:** 所有编辑器的构建都需要64位支持. Windows、Linux和macOS的导出模板也需要64位支持. 由于Apple的限制, iOS设备的导出模板则只支持64位ARM设备.

请从上文的链接中下载适合你操作系统的Godot编辑器及Godot导出模板.

Windows和Linux的用户, 只需解压`.zip`文件并将解压后的可执行文件放在任意目录即可开始工作. 对于macOS用户, 则需要解压`.zip`文件并将`Godot.app`放入你的`/Applications/`文件夹. 如果你有一个已存在的Godot安装副本, 你可以重命名`Godot.app`包来继续安装流程.

要安装导出模板所用的`.tpz`文件, 请打开Godot编辑器, 然后进入`Editor >  Manage export templates ...`. 点击`Install from file`, 选中你从上文的链接中下载的`.tzp`文件. 然后就可以像其他引擎一样为Windows、Linux、macOS、iOS、Android和网站[导出项目](https://docs.godotengine.org/en/stable/tutorials/export/index.html)了. 你也可以在Godot编辑器中使用Godot的[one-click deploy(一键部署)](https://docs.godotengine.org/en/stable/tutorials/export/one-click_deploy.html)功能, 直接将项目部署在Android设备和网站上.

## 示例
spine-godot运行时附带了许多功能演示的示例. 可执行如下步骤来检视示例工程:

1. 通过上文中[安装](#安装)一节内附的链接下载适合你操作系统的预构建Godot编辑器.
2. 克隆[spine-runtimes Git代码库](https://github.com/esotericsoftware/spine-runtimes). 如果你不想使用Git, 则可以下载[最新版本的ZIP压缩文件](/git/spine-runtimes/archive)并解压之.
3. 打开Godot编辑器点击`Import`, 然后根据您的 spine-godot 和 Godot 编辑器版本导入示例文件:
   - GDExtension: `spine-runtimes/spine-godot/example-v4-extension/project.godot`.
      - 解压你的 GDExtension, 并在打开 Godot 编辑器中的项目之前将 `bin/` 复制到项目根目录下!
   - C++ 引擎模块:
      - Godot 3.x: `spine-runtimes/spine-godot/example/project.godot`.
      - Godot 4.x: `spine-runtimes/spine-godot/example-v4/project.godot`.
      - 带有C#支持的Godot 4.x: `spine-runtimes/spine-godot/example-v4-csharp/project.godot`.


文件包含了如下示例项目:
* `01-helloworld`: 演示了如何使用`SpineSprite`节点来显示Spine skeleton并播放Spine skeleton动画.
* `02-animation-state-listener`: 演示了如何通过信号监听`SpineSprite`的动画状态变化.
* `03-mix-and-match`. 演示了如何由其他皮肤组合出一个新的自定义皮肤, 该功能也用在了创建混搭(mix-and-match)场景中的角色上.
* `04-simple-input`: 演示了如何播放动画以响应输入事件.
* `05-mouse-following`: 演示了如何手动让`SpineSprite` skeleton中的骨骼跟随鼠标或触摸事件.
* `06-bone-following`: 演示了如何在`SpineSprite`上使用`SpineBoneNode`来让子节点跟随skeleton中的骨骼.
* `07-slot-node`: 演示了如何使用`SpineSlotNode`让子节点跟随skeleton中的一个槽位, 同时将子节点置入`SpineSprite`的正确渲染顺序.
* `08-animation-player`: 演示了如何使用`SpineAnimationTrack`节点, 通过Godot的`AnimationPlayer`用户界面创建过场动画.  *注意: 该示例不适用于GDExtension版的spine-godot*
* `09-custom-material`: 演示了如何通过`SpineSlotNode`将自定义material应用于整个`SpineSprite`或某个槽位中.
* `10-2d-lighting`: 演示了如何将带有法线贴图的 `SpineSprite`应用于Godot的2D光照系统.
* `11-bone-node`: 演示了使用`SpineBoneNode`实例通过Godot物理引擎驱动`SpineSprite`的骨骼.  
* `12-bone-node`: 使用 Celestial Circus skeleton演示了 Spine 的物理效果.
* `13-load-from-disk`: 演示了如何从磁盘将 Spine .skel/.json 和 .atlas文件加载到运行时中.

## 通过源代码编译 spine-godot 运行时
如果你需要自己编译spine-godot GDExtension或者spine-godot 引擎模块(比如Godot 编辑器和导出模板), 例如: 你需要使用特定Godot版本, 加入某些定制C++模块, 或者想更改spine-godot运行时行为, 针对这些情况我们提供了shell脚本来简化编译流程.

> **注意:** 在尝试这种编译方式前, 请确保已按照[Godot的官方说明](https://docs.godotengine.org/en/stable/development/compiling/index.html)安装了所有构建所需的依赖项.

### 编译 GDExtension

要构建GDExtension二进制文件, 请先克隆[spine-runtimes 代码库](https://github.com/esotericsoftware/spine-runtimes). 在你克隆到本地的Spine Runtimes目录中, 通过Bash shell中运行以下命令(在Windows中可使用Git Bash):

```
cd spine-godot
./build/setup-extension.sh 3.5.2-stable false
./build/build-extension.sh <os>
```

`setup-extension.sh` 构建负责克隆外部依赖项并设置构建环境. `setup-extension.sh` 的第一个参数是构建GDExtension的Godot代码库分支(repository branch)或提交哈希(commit hash). 第二个参数指定是否要编译包含调试信息的构建版本. 可选值为`true`或`false`. 设置脚本将克隆适当版本的 `godot-cpp`, 如需创建调试构建, 它也会克隆 Godot 编辑器仓库. 它最后还会将 `spine-godot/spine_godot_extension.gdextension` 文件复制到 `spine-godot/example-v4-extension/bin` 中.

`build-extension.sh` 脚本负责执行构建并生成用于指定操作系统的 GDExtension 二进制文件. `build-extension.sh` 参数指定了你的目标操作系统. 如果你想为本机执行构建, 可以省略这一参数. 可选值为 `windows`, `linux`, `macos`, `ios`, `android` 和 `web`. 脚本将把GDExtension 二进制文件放在 `spine-godot/example-v4-extension/bin` 的子目录下.

编译过程生成的Godot编辑器二进制文件可在`spine-godot/godot/bin`中找到.

#### 使用 GitHub Actions 执行构建
[spine-runtimes代码库](https://github.com/EsotericSoftware/spine-runtimes) 中的 `.github/workflows/spine-godot-extension-v4.yml`, 和 `.github/workflows/spine-godot-extension-v4-all.yml` 文件包含了 GitHub 工作流(workflow), 它们能通过GitHub Actions构建 spine-godot GDExtension. 相比本地编译过程要更加简单. 若要使用GitHub工作流, 请执行以下操作:

1. 克隆[spine-runtimes代码库](https://github.com/EsotericSoftware/spine-runtimes)
2. 在克隆的代码库里启用GitHub工作流(workflow)
3. 手动触发 `spine-godot-extension-v4-all` 工作流.

生成的二进制文件将作为工件(artifact)附加到运行成功的工作流中.

### 编译 C++ 引擎模块
#### Godot 3.5.x

要构建Godot编辑器二进制文件, 请先克隆[spine-runtimes 代码库](https://github.com/esotericsoftware/spine-runtimes). 在你克隆到本地的Spine Runtimes目录中, 通过Bash shell中运行以下命令(在Windows中可使用Git Bash):

```
cd spine-godot
./build/setup.sh 3.5.2-stable false
./build/build.sh release_debug
```

`setup.sh`的第一个参数是构建所需Godot编辑器的Godot代码库分支(repository branch)或提交哈希(commit hash). 第二个参数指定你是否要编译开发版的编辑器. 可选值为`true`或`false`. 若置为true, 且将`LIVEPP`环境变量设置为了Live++的安装目录, 则构建时将添加对Windows版[Live++](https://liveplusplus.tech/)的支持, 并禁用一些模块以加快编译速度.

`build.sh`的第一个参数指定了生成二进制文件的优化级别. 若值为`debug`则允许完全调试编辑器, 但由于缺少优化可能会很慢; `release_debug`则一般用于Godot编辑器的发布版构建.

编译过程生成的Godot编辑器二进制文件可在`spine-godot/godot/bin`中找到.

要构建特定平台的导出模板, 需要在Bash shell中运行以下命令(在Windows中可使用Git Bash):

```
cd spine-godot
./build/setup.sh 3.5.2-stable false
./build/build-templates.sh windows
```

`setup.sh`的第一个参数是构建所需Godot编辑器的Godot代码库分支(repository branch)或提交哈希(commit hash). 第二个参数必须置为`false`.

`built-templates.sh`的第一个参数是导出模板所面向的平台. 可用值包括`windows`、`linux`、`macos`、`web`、`android`和`ios`. 注意, macOS和iOS的导出模板只能在运行macOS的计算机上构建. 详情见[Godot的官方说明](https://docs.godotengine.org/en/stable/development/compiling/index.html).

编译过程生成的Godot导出模板二进制文件可在`spine-godot/godot/bin`中找到.

#### Godot 4.x

要构建Godot编辑器二进制文件, 请先克隆[spine-runtimes 代码库](https://github.com/esotericsoftware/spine-runtimes). 在你克隆到本地的Spine Runtimes目录中, 通过Bash shell中运行以下命令(在Windows中可使用Git Bash):

```
cd spine-godot
./build/setup.sh 4.1-stable false
./build/build-v4.sh
```

`setup.sh`的第一个参数是构建所需Godot编辑器的Godot代码库分支(repository branch)或提交哈希(commit hash). 第二个参数指定你是否要编译开发版的编辑器. 可选值为`true`或`false`. 若置为true, 且将`LIVEPP`环境变量设置为了Live++的安装目录, 则构建时将添加对Windows版[Live++](https://liveplusplus.tech/)的支持, 并禁用一些模块以加快编译速度.

编译过程生成的Godot编辑器二进制文件可在`spine-godot/godot/bin`中找到.

要构建特定平台的导出模板, 需要在Bash shell中运行以下命令(在Windows中可使用Git Bash):

```
cd spine-godot
./build/setup.sh 4.1-stable false
./build/build-templates-v4.sh windows
```

`setup.sh`的第一个参数是构建所需Godot编辑器的Godot代码库分支(repository branch)或提交哈希(commit hash). 第二个参数必须置为`false`.

`built-templates-v4.sh`的第一个参数是导出模板所面向的平台. 可用值包括`windows`、`linux`、`macos`、`web`、`android`和`ios`. 注意, macOS和iOS的导出模板只能在运行macOS的计算机上构建. 详情见[Godot的官方说明](https://docs.godotengine.org/en/stable/development/compiling/index.html).

编译过程生成的Godot导出模板二进制文件可在`spine-godot/godot/bin`中找到.

#### 支持C#的Godot 4.x
> **注意:** 支持C#的Godot 4.x目前仅适用于Windows、Linux和macOS. 一旦上游的Godot发布了对移动设备和网站部署的支持, spine-godot运行时也将尽快跟进适配.

要构建支持C#的Godot编辑器二进制文件, 请先克隆[spine-runtimes 代码库](https://github.com/esotericsoftware/spine-runtimes). 在你克隆到本地的Spine Runtimes目录中, 通过Bash shell中运行以下命令(在Windows中可使用Git Bash):

```
cd spine-godot
./build/setup.sh 4.1-stable false true
./build/build-v4.sh true
```

`setup.sh`的第一个参数是构建所需Godot编辑器的Godot代码库分支(repository branch)或提交哈希(commit hash). 第二个参数指定你是否要编译开发版的编辑器. 可选值为`true`或`false`. 若置为true, 且将`LIVEPP`环境变量设置为了Live++的安装目录, 则构建时将添加对Windows版[Live++](https://liveplusplus.tech/)的支持, 并禁用一些模块以加快编译速度. 第三个参数是可选参数, 用于指定是否支持C#. 可选值为`true`或`false`. 在本例中参数置为了`true`以启用C#支持.

`build-v4.sh`的参数也是可选的, 用于指定是否支持C#. 可选值为`true`或`false`. 在本例中参数置为了`true`以启用C#支持.

编译过程生成的Godot编辑器二进制文件可在`spine-godot/godot/bin`中找到.

此外你还会在 `spine-godot/godot/bin` 目录下发现一个文件夹 `GodotSharp`, 其中包含了Godot API相关的所有C#程序集实现, 同时也包括了spine-godot运行时的API. 创建新项目时你需要通过[NuGet](https://www.nuget.org/)来链接这些程序集. 请阅读下文中的[C#项目设置](#C#项目设置)一节了解更多信息.

要构建特定平台的导出模板, 需要在Bash shell中运行以下命令(在Windows中可使用Git Bash):

```
cd spine-godot
./build/setup.sh 4.1-stable false
./build/build-templates-v4.sh windows
```

`setup.sh`的第一个参数是构建所需Godot编辑器的Godot代码库分支(repository branch)或提交哈希(commit hash). 第二个参数必须置为`false`.

`built-templates-v4.sh`的第一个参数是导出模板所面向的平台. 可用值包括`windows`、`linux`、`macos`、`web`、`android`和`ios`. 注意, macOS和iOS的导出模板只能在运行macOS的计算机上构建. 详情见[Godot的官方说明](https://docs.godotengine.org/en/stable/development/compiling/index.html).

编译过程生成的Godot导出模板二进制文件可在`spine-godot/godot/bin`中找到.

#### 使用 GitHub Actions 执行构建
[spine-runtimes代码库](https://github.com/EsotericSoftware/spine-runtimes) 中的 `.github/workflows/spine-godot-v4.yml`, 和 `.github/workflows/spine-godot-v4-all.yml` 文件包含了 GitHub 工作流(workflow), 它们能通过GitHub Actions构建 spine-godot GDExtension. 相比本地编译过程要更加简单. 若要使用GitHub工作流, 请执行以下操作:

1. 克隆[spine-runtimes代码库](https://github.com/EsotericSoftware/spine-runtimes)
2. 在克隆的代码库里启用GitHub工作流(workflow)
3. 手动触发`spine-godot`, `spine-godot-v4`, 或`spine-godot-v4-all` 工作流.

生成的二进制文件将作为工件(artifact)附加到运行成功的工作流中.

## C#项目设置
> **注意:** spine-godot GDExtension尚未支持 [C# 绑定](https://github.com/godotengine/godot-proposals/issues/8191). 以下指南内容仅适用于上文中提及的 spine-godot C++ 引擎模块及对应的自定义 Godot 编辑器构建.

如果使用了支持C#的Godot编辑器, 那么在建立Godot新项目时, 需要多做一步设置.

首先, 应使用从上文[安装](#安装)一节中下载的支持C#的Godot编辑器创建Godot项目.

然后, 关闭Godot并打开项目文件夹. 在项目根目录下新建一个名为`godot-nuget`的文件夹.

并将Godot编辑器ZIP文件里的Godot C#程序集复制到该文件夹中. 你需要复制的文件如所示:

* <code>GodotSharpEditor.&lt;version>.snupkg</code>
* <code>Godot.NET.Sdk.&lt;version>.nupkg</code>
* <code>Godot.SourceGenerators.&lt;version>.nupkg</code>
* <code>GodotSharp.&lt;version>.nupkg</code>
* <code>GodotSharp.&lt;version>.snupkg</code>
* <code>GodotSharpEditor.&lt;version>.nupkg</code>

<code>&lt;version></code>取决于您从本页下载的 Godot 版本，例如 `4.1.1`.

下载并解压Godot编辑器的ZIP文件后, 可在以下文件夹中找到这些文件:

* Windows: `godot-editor-windows-mono.zip\GodotSharp\Tools\`
* Linux: `godot-editor-linux-mono.zip/GodotSharp/Tools/`
* macOS: `Godot.app/Contents/Resources/GodotSharp/Tools`, 或右键单击Finder中的Godot.app文件选择`Show Package Contents`, 然后导航至`Contents/Resources/GodotSharp/Tools/`

最后, 在项目根目录下新建一个名为`nuget.config`的文件, 其内容如下:

```
<configuration>
    <packageSources>
        <!-- package source is additive -->
        <add key="godot-nuget" value="./godot-nuget" />
    </packageSources>
</configuration>
```

该配置文件把`godot-nuget`目录配置为NuGet软件包的源. 你将使用`godot-nuget`目录中的程序集, 它包含了spine-godot运行时的C#绑定, 而非从NuGet包存储库中获取官方的Godot C#程序集.

现在你可以再在Godot中打开项目, 并使用Godot和spine-godot C# API替代GDScript了！

> **注意:** 如果你之前使用过官方的 Godot C#编辑器构建, 那么你的`$USER_HOME/.nuget`目录下可能已经残留了官方 Godot C#组件的 NuGet 缓存. 遗憾的是, NuGet 不会将它们替换为启用了 Spine 的组件. 因此在构建启用了 Spine 的 Godot C#项目前, 请务必清空你的 NuGet 缓存!

更多详情请阅读[Godot C#官方文档](https://docs.godotengine.org/en/stable/tutorials/scripting/c_sharp/index.html).

## 更新spine-godot运行时

在更新项目中的spine-godot运行时之前, 请先阅读[Spine 编辑器和运行时版本管理指南](/spine-runtime-architecture#版本控制).

如需更新 spine-godot GDExtension, 从上文的[`安装`](#安装)一节中下载最新版本并复制到Godot项目中即可.

如需更新 spine-godot C++ 引擎模块:

1. 从上文的[`安装`](#安装)一节中下载最新的预编译Godot编辑器和运行时二进制文件.
2. 从上文的[`安装`](#安装)一节中下载最新的预编译Godot导出模板二进制文件.
3. 打开Godot编辑器安装导出模板, 具体做法是导航至`Editor >  Manage export templates ...`, 单击`Install from file`后选中下载的`.tzp`文件.
4. 如果要从一个Spine主版本切换到另一个版本, 应使用与Spine运行时版本匹配的Spine编辑器版本重新导出Spine项目, 并替换Godot项目中的旧版导出文件. 在Godot中打开Godot项目将自动触发更新文件的重导入.
5. 如果你在Godot中使用C#, 请按上文所述, 将新版编辑器`GodotSharp`目录中的新程序集复制到项目的`godot-nuget/`目录中.


# 使用 spine-godot
spine-godot运行时支持加载、播放和操作由Spine创建的动画. [spine-godot](/git/spine-runtimes/tree/spine-godot)运行时是用C++编写的, 基于通用[spine-cpp](/spine-cpp)的运行时. spine-godot运行时包装了spine-cpp的类和函数, 并将其暴露给GDScript. 除了暴露大部分spine-cpp API外, spine-godot运行时还提供了Godot节点, 以方便显示Spine skeleton并与之交互.

请查阅[Spine 运行时指南](/spine-runtimes-guide)
以了解Spine运行时架构的详细信息.

## 资产管理
### 为Godot导出资产
![](/img/spine-runtimes-guide/spine-ue4/export.png)
请遵循Spine用户指南中的步骤操作, 以了解如何:

1. [导出 skeleton & 动画数据](/spine-export)
2. [导出包含skeleton图像的texture atlases](/spine-texture-packer)

导出skeleton数据和texture atlas将生成以下文件:

![](/img/spine-runtimes-guide/spine-godot/exported-files.png)

1. `skeleton-name.spine-json` 或 `skeleton-name.skel`, 包含了skeleton和动画数据.
2. `skeleton-name.atlas`, 包含了texture atlas相关的信息.
3. 一张或多张`.png`图像文件, 每个文件代表了texture atlas中的一页, 而texture atlas包含了skeleton所需的全部图片.

> **注意:** 建议选择二进制格式导出而非JSON导出, 因为二进制格式文件尺寸更小, 加载更快. 如果你必须使用JSON, 请确保文件扩展名为`.spine-json`而非`.json`. 若现有项目仍然使用`.json`导出文件, 可以使用该[Python脚本](/git/spine-runtimes/spine-godot/convert.py)将其扩展名转换为`.spine-json`.

spine-godot运行时可以将这些文件导入为Godot特定的资源文件类型.

> **注意:** 由于Godot的技术限制, spine-godot运行时目前不支持使用预乘alpha导出的atlas. 因为Godot默认对非预乘的texture图像执行出血裁切(bleed)操作. 一般来说这足以避免使用预乘alpha时常出现的显示瑕疵.

### 导入至Godot
![](/img/spine-runtimes-guide/spine-godot/import-general.png)
1. 在Godot编辑器中打开Godot项目.
2. 将`.skel/.spine-json`, `.atlas`和`.png`文件拖动到选中的文件夹中.

资产导入器将为`.skel`或`.spine-json`skeleton文件创建`SpineSkeletonFileResource`, 为`.atlas`文件创建`SpineAtlasAssetResource`, 为atlas中的每个`.png`文件创建Godot texture资源文件.

> **注意:** 在`SpineAtlasResource`的导入设置中, 你还可以指定每个atlas页所用法线贴图的前缀. 默认情况下前缀是`n'. 法线贴图是启用2D光照所必需的, 但也是可选设置.

在导入源文件后, 现在可以创建一个`SpineSkeletonDataResource`, 它结合了`SpineSkeletonFileResource`和 `SpineAtlasResource`以供`SpineSprite`使用.

在Godot编辑器的文件系统面板上, 右击你放置Spine资产的文件夹, 然后选择`New Resource...`. 在弹出的对话框中, 选择 `SpineSkeletonDataResource`后点击`Create`给资源起个名字, 最后点击`Save`.

双击新创建的资源, 使其在检查器面板中显示. 为skeleton分配先前导入的atlas资源和skeleton文件资源. skeleton数据资源也存储了可在检查器中修改的[动画mix时间](/spine-applying-animations#混合时间).

![](/img/spine-runtimes-guide/spine-godot/skeleton-data-resource.png)

> **注意:** 一个结合了某个skeleton文件和atlas的skeleton数据资源可以被所有显示该组合的`SpineSprite`的全部实例共享. 不要将skeleton数据资源定义为`SpineSprite`中的内联(inline)资源, 因为这将成倍增大游戏所需要加载的数据量.


### 更新Spine资产
在开发过程中, 你可能会经常更新你的Spine skeleton数据和texture atlas文件. 你只要简单地覆盖这些源文件(`.spine-json`, `.skel`, `.atlas`, `.png`)--从Spine编辑器重新导出文件, 并替换Godot项目中的现有文件--即可完成更新. 

Godot编辑器将检测到这些源文件的更改, 并自动重导入对应资产, 并在此过程中更新引用这些资产的其他资源. 如果Godot编辑器不能识别自动源文件的变化, 也可以在Godot编辑器中文件的[导入设置面板](https://docs.godotengine.org/en/stable/tutorials/assets_pipeline/import_process.html#changing-import-parameters)中手动地强制执行重新导入操作.

## 节点
spine-godot运行时提供了一组节点, 来显示从Spine导出的skeleton、播放skeleton动画并对其进行修改.

### SpineSprite 节点
![](/img/spine-runtimes-guide/spine-godot/sprite-node.png)

`SpineSprite`节点显示存储在`SkeletonDataResource`中的skeleton数据和atlas. 该节点暴露了一个[动画状态](/spine-applying-animations)API, 通过它可以播放和设置skeleton动画. 你可以通过`SpineSprite.get_animation_state()`来访问`SpineAnimationState`. 该节点还通过`SpineSprite.get_skeleton()`暴露了[skeleton实例](/spine-runtime-skeletons)(`SpineSkeleton`), 通过它你可以查询到skeleton的所有属性, 包括骨骼、槽位、附件、皮肤和约束.

#### 创建SpineSprite

创建`SpineSprite`节点只需点击场景面板上的`+`按钮并选择`SpineSprite`. 然后将`SpineSprite`节点需显示的`SkeletonDataResource`分配给检查器中的相应属性即可, 如上图所示.

你可以使用相应的工具和键盘快捷键在Godot编辑器视口中自由变换`SpineSprite`节点. skeleton在Godot编辑器中`SpineSprite`的边界框, 与skeleton在Spine编辑器的设置模式下的边界框完全一致.

#### 检视骨骼, 槽位和附件
一旦你为`SpineSprite`分配了一个`SkeletonDataResource`, 就可以检视skeleton的骨骼、槽位和附件.

在编辑器视口中选中`SpineSprite`. 在`Debug`属性面板里就能选中欲检查的skeleton组件.

![](/img/spine-runtimes-guide/spine-godot/debug.png)

你可以在编辑器视口中将鼠标悬停在你感兴趣的组件上, 这时将显示其名称.

#### 预览动画
通过设置`Preview`属性面板, 可以在编辑器视口中直接回放动画.

![](/img/spine-runtimes-guide/spine-godot/preview.png)

当勾选了`Preview Frame`时, 将显示动画在当前`Preview Time`的帧. 你可以拖动`Preview Time`滑块来浏览动画.

#### 设置自定义material
`Materials`属性面板可以为每个Spine blend模式单独设置自定义material. 这些material将应用于`SpineSprite`中的所有槽位及其附件.

![](/img/spine-runtimes-guide/spine-godot/materials.png)

可以使用`SpineSlotNode`来设置某个特定槽位的material, 它将覆盖`SpineSprite`上设置的自定义material.

详情参见示例项目中的`example/09-custom-material`场景.

#### 设置更新模式
默认情况下, `SpineSprite`会在每一帧中尽快地更新其底层数据. 可以设置`Update Mode`属性来改变这种行为.

![](/img/spine-runtimes-guide/spine-godot/update-mode.png)

默认值的是`Process`模式, 其更新频率依赖于帧率. `Physics`模式以固定的时间间隔更新`SpineSprite`(默认为每秒60次), 当你需要编写与Godot物理引擎互操作的代码时该模式就能发挥价值了. `Manual`模式则禁用了所有自动更新. 当使用`Manual`模式后, 在重写`_process(delta)`或`_physics_process(delta)`时, 需要调用`SpineSprite.update_skeleton()`来手动更新`SpineSprite`. 使用该模式可以完全掌控`SpineSprite`的更新时机.

更多详情请参见Godot官方文档中的[Idle and Physics Processing](https://docs.godotengine.org/en/stable/tutorials/scripting/idle_and_physics_processing.html) 一章.

#### `SpineSprite`动画
`SpineSprite`的动画效果是通过GDScript或C#代码实现的. 下文中包含了使用GDScript编写的示例代码, 这些代码也可直接转换为 spine-godot C# API. 可查看[Godot C# 文档](https://docs.godotengine.org/en/stable/tutorials/scripting/c_sharp/index.html)进一步了解如何从GDScript将API映射为C#代码.

`SpineSprite`通过`get_animation_state()`函数暴露了`SpineAnimationState`对象. 请见Spine运行时指南中的[应用动画](/spine-applying-animations#AnimationState-API)一章以获得更深入的信息, 特别是关于动画轨道和队列动画的内容.

要在`SpineSprite`的轨道0上设置某个动画, 应调用`SpineAnimationState.set_animation()`:

```
extends SpineSprite

func _ready():
   var animation_state = get_animation_state()
   animation_state.set_animation("walk", true, 0)
```

第一个参数是动画的名称, 第二个参数是指定是否循环播放动画, 最后一个参数是指定应该在哪个轨道上播放动画.

用动画状态方法也能队列动画:

```
extends SpineSprite

func _ready():
   var animation_state = get_animation_state()
   animation_state.set_animation("idle", true, 0)
   animation_state.add_animation("walk", 0.5, true, 0)
```

`add_animation()`的第一个参数是动画名称. 第二个参数指定了播放延迟时间(单位为秒), 延迟后该动画将取代轨道上的前一个动画. 第三个参数指定是否需要循环播放该动画. 最后一个参数是指定应该在哪个轨道上播放动画.

当设置或添加某个动画到动画状态轨道时, 会返回一个`SpineTrackEntry`实例, 它可以进一步修改该的动画播放时的属性. 例如, 你可以将轨道条目设置为逆向播放动画:

```
var track_entry = animation_state.add_animation("walk", 0.5, true, 0)
track_entry.set_reverse(true)
```

> **注意:** 只应在函数内封装`SpineTrackEntry`实例. 虽然函数内会多次重用轨道条目, 但其所代表的动画一旦播放完成, 实例就会失效.

可使用`set_empty_animation()`和`add_empty_animation()`在一条动画轨道上设置或队列空动画, 以便将skeleton丝滑地重置到setup pose:

```
animation_state.set_empty_animation(0, 0.5)
animation_state.add_empty_animation(0, 0.5, 0.5)
```

`set_empty_animation()`的第一个参数指定了轨道. 第二个参数则指定mix时长(单位为秒), 该时长用于以mix的方式淡出之前的动画并淡入到"空"动画.

`add_empty_animation()`的第一个参数指定了轨道. 第二个参数指定了mix时长(单位为秒), 该时长用于以mix的方式淡出之前的动画并淡入到"空"动画. 第三个参数表示延迟时间(单位为秒), 延迟后"空"动画将以mix的方式取代轨道上的前一个动画.

可以通过`clear_track(track_id)`立即清空一条轨道上的所有动画. 要一次性清空全部轨道, 可调用`clear_tracks()`. 清空动画将保持skeleton最后所处的姿态.

要将skeleton的姿态重置为setup pose, 可以使用`SpineSprite.get_skeleton().set_to_setup_pose()`. 这将把骨骼和槽位重置为setup pose中的配置. 使用`SpineSprite.get_skeleton().set_slots_to_setup_pose()`则只将槽位重置为setup pose中的配置.

#### 信号(Signals)
`SpineSprite`暴露了多个信号, 通过信号可在`SpineSprite`的生命周期内响应事件.

为响应动画状态的更改, 可以连接如下信号:

* `animation_started`, 当动画开始时触发.
* `animation_interrupted`, 当清空动画轨道或设置了某个新动画时触发.
* `animation_completed`, 当某条轨道上的动画完成了一个循环时触发.
* `animation_ended`, 当不再应用某个动画时触发.
* `animation_disposed`, 当销毁动画轨道条目时触发.
* `animation_event`,  当用户定义的[事件](/spine-events#事件)发生时触发.

除了动画状态事件, `SpineSprite`还提供了其高级生命周期事件的信号:

* `before_animation_state_update`, 在以当前delta时间更新动画状态前触发.
* `before_animation_state_apply`, 在skeleton姿态应用动画状态前触发.
* `before_world_transforms_change`, 在skeleton的世界变换(world transforms)被更新前触发.
* `world_transforms_changed`, 在skeleton的世界变换(world transforms)更新后触发.

这些信号在手动更新骨骼或其他skeleton组件时可以派上用场. 一般来说, 建议使用`SpineBoneNode`或`SpineSlotNode`节点, 因为它们省去了复杂的手动更新操作, 同时覆盖了99%的用例--比如根据鼠标光标位置放置骨骼.

详见示例项目中的`example/02-animation-state-listeners`场景.

#### Mix-and-match 皮肤
![](/img/spine-runtimes-guide/spine-godot/mix-and-match.png)

许多应用程序和游戏允许其用户用许多独立部件自定义组合出虚拟形象, 比如头发、眼睛、裤子, 或耳环或包等配饰. 在Spine中, 这可以通过[Mix-and-match皮肤](/spine-examples-mix-and-match)来实现.

你可以通过其他皮肤组合出自定义的皮肤, 方法如下:

```
var custom_skin = new_skin("custom-skin")
var data = get_skeleton().get_data()
custom_skin.add_skin(data.find_skin("skin-base"))
custom_skin.add_skin(data.find_skin("nose/short"))
custom_skin.add_skin(data.find_skin("eyelids/girly"))
custom_skin.add_skin(data.find_skin("eyes/violet"))
custom_skin.add_skin(data.find_skin("hair/brown"))
custom_skin.add_skin(data.find_skin("clothes/hoodie-orange"))
custom_skin.add_skin(data.find_skin("legs/pants-jeans"))
custom_skin.add_skin(data.find_skin("accessories/bag"))
custom_skin.add_skin(data.find_skin("accessories/hat-red-yellow"))
get_skeleton().set_skin(custom_skin)
get_skeleton().set_slots_to_setup_pose()
```

首先使用`SpineSprite.new_skin(name)`创建自定义皮肤. 接下来从由`SpineSprite`管理的`SpineSkeletonData`中获取`SpineSkeletonData`. 通过它就能用`SpineSkeletonData.find_skin()`来按名称查找皮肤. 通过`SpineSkin.add_skin()`添加所有需要组合的皮肤. 最后通过`SpineSkeleton.set_skin()`给skeleton设置新的皮肤.

详见示例项目中的`example/03-mix-and-match`场景.

#### 获取和设置骨骼变换
`SpineSprite`包装了Spine[运行时skeleton](/spine-runtime-skeletons), 它由骨骼、槽位、附件和约束构成. skeleton在Spine编辑器中管理着以skeleton原点为基准的坐标系的骨骼变换.

`SpineSprite`类提供了辅助方法`get_global_bone_transform(name)`和`set_global_bone_transform(name, transform)`, 你可在Godot画布空间中获取和设置骨骼变换. 注意, 检索或设置变换不会保存骨骼倾斜(skew).

如果想手动设置骨骼变换, 必须在`SpineSprite`每次更新骨骼的世界变换前完成. 你可以响应`before_world_transforms_change`信号来适时地介入生命周期.

直接设置骨骼变换的另一个方法是使用`SpineBoneNode`.

### SpineBoneNode
![](/img/spine-runtimes-guide/spine-godot/bone-node.png)

`SpineBoneNode`可以跟随一个skeleton的骨骼, 也可以驱动其变换. 当你想根据某些输入(例如鼠标位置)控制骨骼变换, 请使用`SpineBoneNode`的驱动模式; 如果你想让另一个节点跟随skeleton中的某骨骼, 例如将`CollisionShape`附加到`SpineSprite`的骨骼上, 则须使用`SpineBoneNode`的跟随模式.

创建`SpineBoneNode`的方法是: 右击需要附加节点的`SpineSprite`, 并选中`Add child node...`. 从可用的节点类型列表中选择 `SpineBoneNode`并为其命名. 然后便可在检查器中修改该节点的设置.

> **注意:** `SpineBoneNode`必须始终是`SpineSprite`的直接子节点, 否则它将无法找到需跟随或驱动的骨骼.

![](/img/spine-runtimes-guide/spine-godot/bone-node-properties.png)

`Bone Name`属性下拉框会显示所有可用的骨骼以供选择. `Bone Mode`指定了节点应该跟随`SpineSprite`中的骨骼还是驱动它. 该节点可以随时启用和禁用, 以便按需开关跟随和驱动功能.

`SpineBoneNode`也将显示在编辑器视口中. `Debug`面板中的属性定义了其外观.

若需了解如何使用鼠标移动来让`SpineBoneNode`驱动`SpineSprite`的骨骼, 请查看`example/05-mouse-following`场景.

若需了解如何使用`SpineBoneNode`来跟随`SpineSprite`的骨骼, 请查看`example/06-bone-following`场景. 该示例中的`SpineBoneNode`包含一个子节点, 它将显示在`SpineSprite`中被跟随骨骼.

> **注意:** `SpineSprite`不会正确排序子节点的绘制顺序. 当你想在`SpineSprite`多个组件的绘制顺序中插入任意的节点时, `SpineSlotNode`是更适合的选择.

### SpineSlotNode
![](/img/spine-runtimes-guide/spine-godot/slot-node.png)

`SpineSlotNode`可以在`SpineSprite`的绘制顺序中插入任意节点. 它用于将粒子系统、自定义精灵(Sptite)、甚至其他`SpineSprite`节点附加到skeleton的特定[槽位](/spine-slots)上. `SpineSlotNode`的子节点将被渲染在该槽位的所有活动附件之上. 你也可以使用`SpineSlotNode`来覆盖某个特定槽位的material.

创建`SpineSlotNode`的方法是: 右击需要附加节点的`SpineSprite`, 并选中`Add child node...`. 从可用的节点类型列表中选择 `SpineSlotNode`并为其命名. 然后便可在检查器中修改该节点的设置.

> **注意:** `SpineSlotNode`必须始终是`SpineSprite`的直接子节点, 否则它将无法找到其所属槽位.

![](/img/spine-runtimes-guide/spine-godot/slot-node-properties.png)

`Slot Name`属性下拉框会显示所有可用的槽位以供选择. `Materials`面板可设置materials, 它用于覆盖该槽位的默认material.

若需了解如何使用 `SpineSlotNode`在 `SpineSprite`的绘制顺序中插入节点的例子, 请查看`example/07-slot-node`场景.

若需了解如何使用`SpineSlotNode`来覆盖`SpineSprite`中某个槽位的material, 请查看`example/09-custom-material`场景.

### SpineAnimationTrack
![](/img/spine-runtimes-guide/spine-godot/animation-track.png)

> **注意:** 由于Godot的动画引擎的诸多限制, 第三方插件尚无法完整支持其诸如导入3D角色动画等功能, 所以 `SpineAnimationTrack` 仍为具有高度实验性的功能. 当前亦不被spine-godot GDExtension支持.

`SpineAnimationTrack`节点可通过Godot的[动画播放器](https://docs.godotengine.org/en/stable/classes/class_animationplayer.html)和强大的[动画编辑器](https://docs.godotengine.org/en/stable/tutorials/animation/introduction.html)对`SpineSprite`进行动画制作. 它非常适合使用Godot动画编辑器来创建过场场景, 摆脱了通过代码手工制作场景的繁琐.

创建`SpineAnimationTrack`的方法是: 右击需要附加节点的`SpineSprite`, 并选中`Add child node...`. 从可用的节点类型列表中选择 `SpineAnimationTrack`并为其命名. 然后便可在检查器中修改该节点的设置.

> **注意:** `SpineAnimationTrack`必须始终是`SpineSprite`的直接子节点, 否则它将无法找到其所属槽位.

当创建`SpineAnimationTrack`时会自动附加一个`AnimationPlayer`节点作为其子节点.

然后key好`SpineAnimationTrack`和其子节点`AnimationPlayer`就能播放`SpineSprite`动画. 你通过key入子节点`AnimationPlayer`来设置动画的播放. 要修改动画的属性, 比如是否循环播放、是否反向播放等等, 可以key入`SpineAnimationTrack`属性.

这种双层设置可使动画编辑器显示子节点`AnimationPlayer`中key入动画的持续时间, 这让创建复杂的动画序列变得更加容易. 它还允许在动画编辑器中拖动时间轴预览动画.

> **注意:** 由于Godot动画编辑器的技术限制, 无法在编辑器中预览`SpineSkeletonDataResource`中定义的mix时间.

你可以在一个`SpineSprite`上附加多个`SpineAnimationTrack`节点. 这可以叠加多个动画. 每个`SpineAnimationTrack`都有一个[轨道索引号](/spine-applying-animations#通道(Track)). 如果key入了相同的skeleton属性, 那么索引号较高的轨道上的动画会覆盖较索引号上的动画行为.

更多示例请查看`example/08-animation-player`场景. 该场景根节点上的`AnimationPlayer`包含两个动画, 它们key了 `SpineAnimationTrack`节点及其`AnimationPlayer`子节点. `slow-moonwalk`动画阐明了`SpineAnimationTrack`的基本原理. 而`cutscene`动画则是一个更复杂的动画, 演示了如何使用多轨key和复杂动画序列.

# 2D光照
![](/img/spine-runtimes-guide/spine-godot/2d-lighting.png)

spine-godot集成了[Godot的2D光照系统](https://docs.godotengine.org/en/stable/tutorials/2d/2d_lights_and_shadows.html).

要使用Godot的2D光照系统, 你需要为texture atlas提供法线贴图. 构成texture atlas页的每个`.png`都须在其旁边放置一张对应的`.png`法线贴图. 法线贴图文件须有统一的前缀. 默认前缀为`n_`. 例如, 一张名为`raptor.png`的texture atlas页图像旁边必须有一张名为`n_raptor.png`的法线贴图.

在导入texture atlas时, spine-godot将尝试为每个texture atlas的页查找并加载法线贴图. 你可以在texture atlas的导入视图中设置自定义的法线贴图前缀.

![](/img/spine-runtimes-guide/spine-godot/normal-map.png)

一旦成功导入texture atlas页和法线贴图, 你就可以将Godot的2D光照系统用于`SpineSprite`节点上\.

详见示例中的`10-2d-lighting`场景.

# 从磁盘加载 .skel/.json/.atlas 文件
为了修改(modding)目的, 从磁盘上的任意位置加载并导出 Spine 资产可能会很有用. 大致做法是使用 `SpineSkeletonFileResource.load_from_file()` 函数先加载 `.skel` 和 `.json` 格式的skeleton文件, 然后使用 `SpineAtlasResource.load_from_atlas_file()` 函数来加载 `.atlas` 文件.

一般步骤如下:
- 加载 skelton 文件
- 加载 atlas 文件
- 用 skeleton 和 atlas 构建对应 `SpineSkeletonDataResource`
- 最后用 `SpineSkeletonDataResource` 创建一个或多个 `SpineSprite` 实例. 请注意这里的数据资源(`SpineSkeletonDataResource`)是多实例共享的!

这几步可用GDScript以如下方式实现:

```
	# Load the skeleton file
	var skeleton_file_res = SpineSkeletonFileResource.new();
	skeleton_file_res.load_from_file("/Users/badlogic/workspaces/spine-runtimes/examples/coin/export/coin-pro.skel");
	
	# Load the atlas file
	var atlas_res = SpineAtlasResource.new();
	atlas_res.load_from_atlas_file("/Users/badlogic/workspaces/spine-runtimes/examples/coin/export/coin.atlas");
	
	# Create a skeleton data resource, you can share this across multiple sprites
	var skeleton_data_res = SpineSkeletonDataResource.new();
	skeleton_data_res.skeleton_file_res = skeleton_file_res;
	skeleton_data_res.atlas_res = atlas_res
	
	# Create a sprite from the skeleton data and add it as a child
	var sprite = SpineSprite.new();
	sprite.skeleton_data_res = skeleton_data_res;
	sprite.position.x = 200;
	sprite.position.y = 200;
	sprite.get_animation_state().set_animation("animation", true, 0);
	self.add_child(sprite)
```

亦可参见示例 `13-load-from-disk`.

# 访问Spine运行时API
spine-godot将几乎所有的Spine运行时API都映射到了GDSCript. 由`SpineSprite`返回的对象, 如通过`SpineSprite.get_skeleton()`返回的`SpineSkeleton`均为spine-cpp API到GDScript的1:1翻译. 因此你可以将[Spine运行时指南](/spine-runtimes-guide)中几乎所有通用操作以GDScripts实现.

但由于GDScript的特性, 有一些已知的限制:

* 任何返回的数组或映射(map)均为内部数组的副本. 修改它们不会产生任何影响.
* 无法在某个 `SpineTrackEntry` 对象上设置监听器. 只能在`SpineSprite`上设置信号.
* 无法直接创建、添加或删除骨骼、槽位和其他Spine对象.
* 附件和时间轴的C++类内部结构没有暴露给GDScript.