Spine Web Player

Spine Web Player可轻松地将Spine动画嵌入到你的网站上.

Web Player包含控件, 用户可以:

  • 暂停/恢复当前播放的动画.
  • 刷新时间线.
  • 改变播放速度.
  • 从可选动画列表中选中一个动画.
  • 从可选皮肤列表中选中一个皮肤.
  • 隐藏/显示区域、网格或骨骼等的调试渲染.
  • 拖动skeleton的骨骼.

可以禁用Web Player的控件来只用于显示动画, 而无需用户输入(示例).

注意: Spine Web Player使用WebGL进行渲染. 虽然WebGL被所有流行的桌面和移动浏览器的最新版本所支持, 但也存在与旧浏览器的兼容性问题.

为Web Player导出文件

Spine Web Player可以显示以JSON格式从Spine编辑器导出的Spine Skeleton.

Export

除了导出的.json文件外, Web Player还需要一个由.atlas文件和一个或多个.png文件组成的texture atlas. 请参阅Spine用户指南中关于如何导出skeleton为JSON以及如何导出texture atlas的详细信息.

我们将使用Spineboy项目来完成下文中的示例, 为此导出了以下文件:

Spineboy files

这些文件应上传至一个网络服务器上, 再通过URL访问.

.png文件需要与.altas文件在同一路径下. 例如, 如果.atlas文件可以通过https://mysite.com/assets/spineboy.atlas访问, .png文件也应可通过https://mysite.com/assets/spineboy.png访问.

嵌入Web Player

将Web Player嵌入你的网站需要完成简单的几步, 详细步骤如下:

添加JavaScript & CSS文件

Spine Web Player由两个文件组成: spine-player.jsspine-player.css. JS文件包含播放功能所需的JavaScript代码, 而CSS文件定义了Player的UI.

这两个文件可以像这样嵌入网页:

<script src="https://unpkg.com/@esotericsoftware/spine-player@4.1.*/dist/iife/spine-player.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@esotericsoftware/spine-player@4.1.*/dist/spine-player.css">

在该示例中, 这两个文件是通过UNPKG(一个快速的NPM CDN)加载的. 这些URL包含一个版本号(4.0), 它必须与你用来导出skeleton和atlas的Spine编辑器版本相匹配. 像这样加载文件可以确保SpineWeb Player始终使用最新的JavaScript代码和CSS.

在UNPKG CDN上使用.min.js.min.css文件扩展名, 则能使文件最小化:

<script src="https://unpkg.com/@esotericsoftware/spine-player@4.1.*/dist/iife/spine-player.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@esotericsoftware/spine-player@4.1.*/dist/spine-player.min.css">

如果你不想使用UNPKG, 也可以通过从UNPKG下载文件或从我们的GitHub仓库上提供的源代码构建文件, 然后自己托管这些文件. 在这里还可以找到关于如何通过NPM或Yarn来使用Spine Web Player的说明.

创建container元素

Web Player需要一个可加载于其中的包裹元素. 最简单的方法是创建一个带有iddiv元素:

<div id="player-container" style="width: 640px; height: 480px;"></div>

初始化Player

最后一步, 用一段简短的JavaScript代码来初始化Web Player:

<script>
new spine.SpinePlayer("player-container", {
      skeleton: "/files/spineboy/export/spineboy-pro.json",
      atlas: "/files/spineboy/export/spineboy.atlas",
});
</script>

这将在player-container元素中创建一个新的SpinePlayer. Web Player从相对路径URL/files/spineboy/export/spineboy-pro.json加载了skeleton的.json, 从/files/spineboy/export/spineboy.atlas加载了.atlas文件. 这个texture atlas有一个名为spineboy.png的页, 所以该图片是相对于/files/spineboy/export/spineboy.png.atlas文件来加载的.

组合在一起

以上的Web Player代码是可修改的!可以用它来试试下一节中的配置选项.

使用上述代码, Web Player将把其所有可配置的属性置为默认值: 播放哪种动画, 背景颜色等等等等. 你可以通过下面详述的配置进一步定制Web Player的外观和行为.

大功告成

Spine Web Player提供了广泛的配置选项, 以适应您的需求.

JSON, 二进制和 atlas URL

在上面的例子中, 包含了两个必填的配置属性 skeletonatlas. 它们指定了Web Player应从何处加载skeleton的.json或二进制.skel文件以及.atlas文件. 在这里填入相对URL和绝对URL都是可以的:

<script>
new spine.SpinePlayer("player-container", {
// Relative URLs
skeleton: "assets/spineboy.json",
atlas: "assets/spineboy.atlas",
});

new spine.SpinePlayer("player-container", {
// Absolute URLs
skeleton: "https://esotericsoftware.com/files/examples/4.2/spineboy/export/spineboy-pro.skel",
atlas: "https://esotericsoftware.com/files/examples/4.2/spineboy/export/spineboy-pma.atlas"
});
</script>

当使用另一个域上的绝对路径URL时, 浏览器有可能无法加载资产. 这通常是由于托管资产的服务器上没有启用CORS.

内嵌数据

若您不希望从 URL 加载数据, 也可以在 JavaScript 源代码中直接嵌入原生 .json/.skel.atlas.png文件. 使用 rawDataURIs 配置属性即可实现:

new spine.SpinePlayer("player", {
      skeleton: "raptor-pro.json",
      atlas: "raptor-pma.atlas",
      rawDataURIs: {
         "raptor-pro.json": "data:application/json;base64,<base64 encoded raptor-pro.json>",
         "raptor-pma.atlas": "data:application/octet-stream;base64,<base64 encoded raptor-pma.atlas>",
         "raptor-pma.png": "data:image/png;base64,<base64 encoded raptor-pma.png>"
      }
}

rawDataURIs 也可用于使用来自不同路径甚至其他域(如果启用了 CORS)中的atlas图片.

         "raptor-pma.png": "https://example.com/assets/raptor.png"

默认动画

默认情况下, Web Player会播放在skeleton中找到的第一个动画. 默认动画也可以在配置中明确指定:

<script>
new spine.SpinePlayer("player-container", {
...
animation: "walk" // Player will start with "walk" animation
});
</script>

动画限制

Web Player允许用户选择活动的动画. 可以用animations属性来限制可选动画集:

<script>
new spine.SpinePlayer("player-container", {
...
animations: ["walk", "run", "jump"] // The user can only select one of these three animations
});
</script>

若只能选择一个动画, 动画按钮将被Web Player隐藏, 这可能是因为skeleton中只有一个动画, 或者是animations列表中只有一个动画.

默认mix时长

当在两个动画之间切换时, Web Player将默认动画mix时长为0.25秒, 以显示平滑的过渡. 这个mix时长可以通过defaultMix属性设置:

<script>
new spine.SpinePlayer("player-container", {
...
defaultMix: 0.1 // Mix animation changes for 0.1 seconds
});
</script>

默认皮肤

默认情况下, Web Player将使用skeleton的默认皮肤, 它们是Spine编辑器中的非皮肤附件. 活动皮肤可以在配置中通过skin属性显式指定:

<script>
new spine.SpinePlayer("player-container", {
...
skin: "funky" // Start with the "funky" skin
});
</script>

皮肤限制

Web Player允许用户选择活动皮肤. 可以通过skin属性来限制可选皮肤集:

<script>
new spine.SpinePlayer("player-container", {
...
skins: ["default", "funky"] // The user can only select one of these two skins
});
</script>

若只能选择一个皮肤, 皮肤按钮将被Web Player隐藏, 这可能是因为skeleton中只有一个皮肤, 或者skins列表中只有一个皮肤.

Premultiplied alpha

默认情况下, Web Player在加载图像时会启用premultiplied alpha. 要禁用premultiplied alpha, 必须设置premultipliedAlpha配置属性:

<script>
new spine.SpinePlayer("player-container", {
...
premultipliedAlpha: false // Disable premultiplied alpha rendering
});
</script>

我们建议对所有Spine Web Player需显示的资产均使用premultiplied alpha. 它减少了不使用premultiplied alpha时可能出现的伪影和接缝问题.

隐藏控件

可以通过showControls配置属性来隐藏Web Player的控件:

<script>
new spine.SpinePlayer("player-container", {
...
showControls: false // Hide the player controls
});
</script>

Debug信息可视化

默认情况下, Web Player不显示任何调试的可视化信息, 如区域、网格三角形、骨骼等. 这些信息的显示可以由用户通过Web Player控件手动启用. 可以用debug属性来指定默认启用哪些调试信息的显示:

<script>
new spine.SpinePlayer("player-container", {
...
debug: {
    bones: true,
    regions: true,
    meshes: true,
    bounds: true,
    paths: true,
    clipping: true,
    points: true,
    hulls: true
}
});
</script>

当然, 你可以略过任何你不想默认启用的可视化信息, 或将其各自属性置为false.

背景色

Web Player的背景色可以通过backgroundColor配置属性设置. 该颜色须被设置为十六进制的RGBA颜色(#rrggbbaa).

<script>
new spine.SpinePlayer("player-container", {
...
backgroundColor: "#ff00ffff" // Magenta player background
});
</script>

Web Player可以切换为全屏. 全屏模式单独的背景色可以通过fullscreenBackgroundColor配置属性设置. 如果没有指定, 全屏背景色将与backgroundColor相同.

<script>
new spine.SpinePlayer("player-container", {
...
backgroundColor: "#ff00ffff" // Magenta player background
fullScreenBackgroundColor: "#00ff00ff" // Green player background in fullscreen mode
});
</script>

背景图片

Web Player也可以在skeleton后显示一张背景图片, 而非纯背景色. 该图像可以通过backgroundImage配置属性指定:

<script>
new spine.SpinePlayer("player-container", {
...
backgroundImage: { // Display a background image behind the skeleton
    url: "assets/background.png",
    x: 0,
    y: 0,
    width: 330,
    height: 330
}
});
</script>

url是背景图片的相对或绝对URL. xy属性指定了图像的左下角在skeleton的世界坐标空间中的位置. widthheight属性指定了图像的尺寸.

半透明Web Player

默认情况下Web Player是不透明的, 它被绘制在任何其后的其他HTML元素上. alpha配置属性可以与backgroundColor属性结合使用, 使Web Player成为半透明的, 让后面的HTML元素透过Web Player.

<script>
new spine.SpinePlayer("player-container", {
...
alpha: true, // Enable player translucency
backgroundColor: "#00000000" // Background is fully transparent
});
</script>

视口

Web Player 总是试图填充它所嵌入的容器元素. 当选中了一个动画(或在配置中指定), Web Player 会确保该动画在 Web Player 可用的空间内完全可见.

Viewport

在上图中, 绿色矩形代表了为 Spineboy 自动计算的run动画边界框. 默认情况下, 它每边都被 pad 了10%. 由此产生的视口, 由红色矩形表示, 然后保持视口长宽比后被嵌入到 Web Player 的可用空间中.

这种自动视口机制可以通过 Web Player 的配置来定制. 如果没有给出视口配置, Web Player 自动将采用上述行为默认行为.

你可以设置用于所有动画的全局视口, 像这样:

<script>
new spine.SpinePlayer("player-container", {
...
viewport: {
    x: 0,
    y: 0,
    width: 300,
    height: 300,
    padLeft: "5%",
    padRight: "5%",
    padTop: "5%",
    padBottom: "5%"
}
});
</script>

xy属性指定视口的左下角在skeleton的世界坐标空间中的位置. widthheight属性指定了视口的尺寸. 如果这些属性中的任何一个被省略, Web Player就会忽略所有其他的属性, 转而使用上述的自动行为.

padLeftpadRightpadToppadBottom属性指定了要添加到视口各边的填充量. 在上面的例子中, 它们表为百分比. 你也可以指定在skeleton的世界坐标空间中的绝对数值. 如果这些属性中的一个被省略了, Web Player就会使用默认值10%.

你可以通过指定debugRender属性来可视化视口, 如上图所示:

<script>
new spine.SpinePlayer("player-container", {
...
viewport: {
    ...
    debugRender: true // Show the viewport bounds
}
});
</script>

当Web Player在动画之间切换时, 它会将新旧动画的视口间进行0.2秒的插值. 这个视口转换时间可以通过transitionTime属性设置:

<script>
new spine.SpinePlayer("player-container", {
...
viewport: {
    ...
    transitionTime: 1 // Transition between viewports for 1 second
}
});
</script>

有时, 为一个特定的动画指定一个视口是很有帮助的. 这可以通过animations属性来实现:

<script>
new spine.SpinePlayer("player-container", {
...
viewport: {
    ...
    animations: {
       "walk": {
         x: 0,
         y: 0,
         width: 300,
         height: 300,
         padLeft: "5%",
         padRight: "5%",
         padTop: "5%",
         padBottom: "5%"
       },
       "run": {
         padTop: "20%",
       }
    }
}
});
</script>

在上例中, 我们为walkrun动画各指定了一个视口. 对于walk动画, 我们定义了完整的视口边界, 包括padding. 全局视口(如果没有给出全局视口, 则为自动行为)将完全覆盖这个动画.

而对于run动画, 我们只指定了顶部的padding. 所有其他的视口设置值将来自全局视口设置, 或者是自动行为.

生命周期回调

Web Player 提供了可选的回调函数, 用于介入资产加载生命周期和渲染循环. 所有回调函数都将 SpinePlayer 实例作为其第一个参数. 以下示例一目了然地展示了所有可用的回调函数:

<script>
new spine.SpinePlayer("player-container", {
...
// Called each frame while assets are still being loaded.
loading: function (player, delta) {
    console.log("Still loading...");
},
// Called when the skeleton and its assets have been successfully loaded.
success: function (player) {
    console.log("Skeleton loaded!");
},
// Called when the skeleton could not be loaded or rendered.
error: function (player, reason) {
    alert(reason);
},
// Called at the start of each frame, before the skeleton is posed or drawn.
frame: function (player, delta) {
    console.log("Frame start, delta: " + delta);
},
// Called instead of the default skeleton.updateWorldTransform(Physics.update).
updateWorldTransform: function (player, delta) {
    player.skeleton.updateWorldTransform(spine.Physics.update);
},
// Called after the skeleton is posed, before it is drawn.
update: function (player, delta) {
    console.log("Skeleton posed, about to draw.");
},
// Called after the skeleton is drawn.
draw: function (player, delta) {
    console.log("Skeleton drawn.");
}
});
</script>

当资源正在加载时, loading 回调函数每帧都会被调用. 它的 delta 是原始的帧间隔时间, 不受暂停或速度的影响. 加载完成后, 将会调用 successerror 回调. 成功时, Web Player 的 skeletonanimationState 属性变得可用, 渲染循环开始. 每一帧中, 以下回调函数按顺序被调用: frame → 动画更新 → updateWorldTransformupdate → 绘制skeleton → draw. 它们的 delta 参数以秒为单位, 已经根据 Web Player 的速度和暂停状态进行了缩放(暂停时为 0).

回调函数 参数 描述
loading player, delta 在 skeleton 可用前资源加载过程中每帧调用. delta 是原始的帧间隔时间(不受暂停或速度影响). 使用此回调来实现自定义加载指示器.
success player 当 skeleton 及其资源成功加载后调用. 从此时起, Web Player 的 skeletonanimationState 属性将会可用. 如果在此回调中设置了轨道0上的动画, Web Player 将不会设置自己的默认动画.
error player, reason 当 skeleton 无法加载或渲染时调用. reason 参数是一个人类可读的错误消息.
frame player, delta 在 skeleton 摆出姿势或绘制 skeleton 之前, 于每帧开始时调用. 使用此回调在动画状态更新前执行自定义逻辑.
updateWorldTransform player, delta 替代默认的 skeleton.updateWorldTransform(Physics.update) 调用. 使用此回调来自定义世界变换的计算方式, 例如使用不同的 Physics 模式. 如果未设置, Web Player 会自动调用 player.skeleton.updateWorldTransform(spine.Physics.update).
update player, delta Skeleton 摆出姿势后到绘制 skeleton 之前这期间, 于每帧中调用(在 updateWorldTransform 之后). 使用此回调在渲染前检查或修改 skeleton 的状态. 如果在此处修改了 skeleton, 请调用 player.skeleton.updateWorldTransform(spine.Physics.none) 使更改生效.
draw player, delta 在每帧中绘制了 skeleton 后调用. 使用此回调可通过 Web Player 的 SceneRenderer 进行自定义 skeleton 渲染.

高级回放设置

Web Player提供了函数 setAnimation(name: string, loop: boolean) 来设置一个动画的名称并指定它是否循环. 这个函数根据指定的动画来调整视口.

setAnimationsuccess 回调触发后才能被调用, 这个回调在 atlas 和 skeleton数据加载完成时就会触发.

<script>
new spine.SpinePlayer("player-container", {
...
success: function (player) {
    player.setAnimation("run", true);
}
});
</script>

为了实现更多的控制, 可以直接访问Web Player的SkeletonAnimationState来设置skeleton上的附件, 改变skeleton的皮肤, 队列动画, 在不同的轨道上一次播放多个动画及更多操作. Web Player提供了skeletonanimationState属性:

<script>
new spine.SpinePlayer("player-container", {
...
success: function (player) {
    player.skeleton.setAttachment("weapon", "sword");
    player.animationState.setAnimation(0, "jump");
    player.animationState.addAnimation(0, "walk", true, 0);
}
});
</script>

当直接访问这些属性时, 建议设置showControls: false, 这样控件输入就不会干扰你代码所设置的配置.

默认情况下, 视口是基于默认动画中skeleton的边界. 与Web Player的setAnimation函数不同, 当用动画状态来改变动画时视口也保持不变.