|
@@ -1,181 +1,86 @@
|
|
|
+<!DOCTYPE html>
|
|
|
<html>
|
|
|
-<script src="../dist/iife/spine-canvas.js"></script>
|
|
|
-<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
|
|
|
-<style>
|
|
|
- * {
|
|
|
- margin: 0;
|
|
|
- padding: 0;
|
|
|
- }
|
|
|
-
|
|
|
- body,
|
|
|
- html {
|
|
|
- height: 100%
|
|
|
- }
|
|
|
|
|
|
- canvas {
|
|
|
- position: absolute;
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- }
|
|
|
-</style>
|
|
|
+<head>
|
|
|
+ <!--<script src="https://unpkg.com/@esotericsoftware/[email protected].*/dist/iife/spine-canvas.js"></script>-->
|
|
|
+ <script src="../dist/iife/spine-canvas.js"></script>
|
|
|
+</head>
|
|
|
|
|
|
-<body>
|
|
|
- <canvas id="canvas"></canvas>
|
|
|
+<body style="margin: 0; padding: 0;">
|
|
|
+ <canvas id="canvas" style="width: 100%; height: 100vh;"></canvas>
|
|
|
</body>
|
|
|
-<script>
|
|
|
-
|
|
|
- var lastFrameTime = Date.now() / 1000;
|
|
|
- var canvas, context;
|
|
|
- var assetManager;
|
|
|
- var skeleton, state, bounds;
|
|
|
- var skeletonRenderer;
|
|
|
|
|
|
- var skelName = "spineboy-ess";
|
|
|
- var animName = "walk";
|
|
|
+<script>
|
|
|
+ let lastFrameTime = Date.now() / 1000;
|
|
|
+ let canvas, context;
|
|
|
+ let assetManager;
|
|
|
+ let skeleton, animationState, bounds;
|
|
|
+ let skeletonRenderer;
|
|
|
|
|
|
- function init() {
|
|
|
+ async function load() {
|
|
|
canvas = document.getElementById("canvas");
|
|
|
- canvas.width = window.innerWidth;
|
|
|
- canvas.height = window.innerHeight;
|
|
|
context = canvas.getContext("2d");
|
|
|
-
|
|
|
skeletonRenderer = new spine.SkeletonRenderer(context);
|
|
|
- // enable debug rendering
|
|
|
- skeletonRenderer.debugRendering = true;
|
|
|
- // enable the triangle renderer, supports meshes, but may produce artifacts in some browsers
|
|
|
- skeletonRenderer.triangleRendering = false;
|
|
|
-
|
|
|
- assetManager = new spine.AssetManager("assets/");
|
|
|
|
|
|
- assetManager.loadText(skelName + ".json");
|
|
|
- assetManager.loadText(skelName.replace("-pro", "").replace("-ess", "") + ".atlas");
|
|
|
- assetManager.loadTexture(skelName.replace("-pro", "").replace("-ess", "") + ".png");
|
|
|
+ // Load the assets.
|
|
|
+ assetManager = new spine.AssetManager("https://esotericsoftware.com/files/examples/4.0/spineboy/export/");
|
|
|
+ assetManager.loadText("spineboy-ess.json");
|
|
|
+ assetManager.loadTextureAtlas("spineboy.atlas");
|
|
|
+ await assetManager.loadAll();
|
|
|
|
|
|
- requestAnimationFrame(load);
|
|
|
- }
|
|
|
+ // Create the texture atlas and skeleton data.
|
|
|
+ let atlas = assetManager.require("spineboy.atlas");
|
|
|
+ let atlasLoader = new spine.AtlasAttachmentLoader(atlas);
|
|
|
+ let skeletonJson = new spine.SkeletonJson(atlasLoader);
|
|
|
+ let skeletonData = skeletonJson.readSkeletonData(assetManager.require("spineboy-ess.json"));
|
|
|
|
|
|
- function load() {
|
|
|
- if (assetManager.isLoadingComplete()) {
|
|
|
- var data = loadSkeleton(skelName, animName, "default");
|
|
|
- skeleton = data.skeleton;
|
|
|
- state = data.state;
|
|
|
- bounds = data.bounds;
|
|
|
- requestAnimationFrame(render);
|
|
|
- } else {
|
|
|
- requestAnimationFrame(load);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- function loadSkeleton(name, initialAnimation, skin) {
|
|
|
- if (skin === undefined) skin = "default";
|
|
|
-
|
|
|
- // Load the texture atlas using name.atlas and name.png from the AssetManager.
|
|
|
- // The function passed to TextureAtlas is used to resolve relative paths.
|
|
|
- atlas = new spine.TextureAtlas(assetManager.require(name.replace("-pro", "").replace("-ess", "") + ".atlas"));
|
|
|
- atlas.setTextures(assetManager);
|
|
|
-
|
|
|
- // Create a AtlasAttachmentLoader, which is specific to the WebGL backend.
|
|
|
- atlasLoader = new spine.AtlasAttachmentLoader(atlas);
|
|
|
-
|
|
|
- // Create a SkeletonJson instance for parsing the .json file.
|
|
|
- var skeletonJson = new spine.SkeletonJson(atlasLoader);
|
|
|
-
|
|
|
- // Set the scale to apply during parsing, parse the file, and create a new skeleton.
|
|
|
- var skeletonData = skeletonJson.readSkeletonData(assetManager.require(name + ".json"));
|
|
|
- var skeleton = new spine.Skeleton(skeletonData);
|
|
|
- skeleton.scaleY = -1;
|
|
|
- var bounds = calculateBounds(skeleton);
|
|
|
- skeleton.setSkinByName(skin);
|
|
|
-
|
|
|
- // Create an AnimationState, and set the initial animation in looping mode.
|
|
|
- var animationState = new spine.AnimationState(new spine.AnimationStateData(skeleton.data));
|
|
|
- animationState.setAnimation(0, initialAnimation, true);
|
|
|
- animationState.addListener({
|
|
|
- event: function (trackIndex, event) {
|
|
|
- // console.log("Event on track " + trackIndex + ": " + JSON.stringify(event));
|
|
|
- },
|
|
|
- complete: function (trackIndex, loopCount) {
|
|
|
- // console.log("Animation on track " + trackIndex + " completed, loop count: " + loopCount);
|
|
|
- },
|
|
|
- start: function (trackIndex) {
|
|
|
- // console.log("Animation on track " + trackIndex + " started");
|
|
|
- },
|
|
|
- end: function (trackIndex) {
|
|
|
- // console.log("Animation on track " + trackIndex + " ended");
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- // Pack everything up and return to caller.
|
|
|
- return { skeleton: skeleton, state: animationState, bounds: bounds };
|
|
|
- }
|
|
|
-
|
|
|
- function calculateBounds(skeleton) {
|
|
|
- var data = skeleton.data;
|
|
|
+ // Instantiate a new skeleton based on the atlas and skeleton data.
|
|
|
+ skeleton = new spine.Skeleton(skeletonData);
|
|
|
skeleton.setToSetupPose();
|
|
|
skeleton.updateWorldTransform();
|
|
|
- var offset = new spine.Vector2();
|
|
|
- var size = new spine.Vector2();
|
|
|
- skeleton.getBounds(offset, size, []);
|
|
|
- return { offset: offset, size: size };
|
|
|
+ bounds = skeleton.getBoundsRect();
|
|
|
+
|
|
|
+ // Setup an animation state with a default mix of 0.2 seconds.
|
|
|
+ var animationStateData = new spine.AnimationStateData(skeleton.data);
|
|
|
+ animationStateData.defaultMix = 0.2;
|
|
|
+ animationState = new spine.AnimationState(animationStateData);
|
|
|
+
|
|
|
+ // Start rendering.
|
|
|
+ requestAnimationFrame(render);
|
|
|
}
|
|
|
|
|
|
function render() {
|
|
|
+ // Calculate the delta time between this and the last frame in seconds.
|
|
|
var now = Date.now() / 1000;
|
|
|
var delta = now - lastFrameTime;
|
|
|
lastFrameTime = now;
|
|
|
|
|
|
- resize();
|
|
|
-
|
|
|
- context.save();
|
|
|
- context.setTransform(1, 0, 0, 1, 0, 0);
|
|
|
- context.fillStyle = "#cccccc";
|
|
|
- context.fillRect(0, 0, canvas.width, canvas.height);
|
|
|
- context.restore();
|
|
|
-
|
|
|
- state.update(delta);
|
|
|
- state.apply(skeleton);
|
|
|
+ // Resize the canvas drawing buffer if the canvas CSS width and height changed
|
|
|
+ // and clear the canvas.
|
|
|
+ if (canvas.width != canvas.clientWidth || canvas.height != canvas.clientHeight) {
|
|
|
+ canvas.width = canvas.clientWidth;
|
|
|
+ canvas.height = canvas.clientHeight;
|
|
|
+ }
|
|
|
+ context.clearRect(0, 0, canvas.width, canvas.height);
|
|
|
+
|
|
|
+ // Center the skeleton and resize it so it fits inside the canvas.
|
|
|
+ skeleton.x = canvas.width / 2;
|
|
|
+ skeleton.y = canvas.height - canvas.height * 0.1;
|
|
|
+ let scale = canvas.height / bounds.height * 0.8;
|
|
|
+ skeleton.scaleX = scale;
|
|
|
+ skeleton.scaleY = -scale;
|
|
|
+
|
|
|
+ // Update and apply the animation state, update the skeleton's
|
|
|
+ // world transforms and render the skeleton.
|
|
|
+ animationState.update(delta);
|
|
|
+ animationState.apply(skeleton);
|
|
|
skeleton.updateWorldTransform();
|
|
|
skeletonRenderer.draw(skeleton);
|
|
|
|
|
|
- context.strokeStyle = "green";
|
|
|
- context.beginPath();
|
|
|
- context.moveTo(-1000, 0);
|
|
|
- context.lineTo(1000, 0);
|
|
|
- context.moveTo(0, -1000);
|
|
|
- context.lineTo(0, 1000);
|
|
|
- context.stroke();
|
|
|
-
|
|
|
requestAnimationFrame(render);
|
|
|
}
|
|
|
|
|
|
- function resize() {
|
|
|
- var w = canvas.clientWidth;
|
|
|
- var h = canvas.clientHeight;
|
|
|
- if (canvas.width != w || canvas.height != h) {
|
|
|
- canvas.width = w;
|
|
|
- canvas.height = h;
|
|
|
- }
|
|
|
-
|
|
|
- // magic
|
|
|
- var centerX = bounds.offset.x + bounds.size.x / 2;
|
|
|
- var centerY = bounds.offset.y + bounds.size.y / 2;
|
|
|
- var scaleX = bounds.size.x / canvas.width;
|
|
|
- var scaleY = bounds.size.y / canvas.height;
|
|
|
- var scale = Math.max(scaleX, scaleY) * 1.2;
|
|
|
- if (scale < 1) scale = 1;
|
|
|
- var width = canvas.width * scale;
|
|
|
- var height = canvas.height * scale;
|
|
|
-
|
|
|
- context.setTransform(1, 0, 0, 1, 0, 0);
|
|
|
- context.scale(1 / scale, 1 / scale);
|
|
|
- context.translate(-centerX, -centerY);
|
|
|
- context.translate(width / 2, height / 2);
|
|
|
- }
|
|
|
-
|
|
|
- (function () {
|
|
|
- init();
|
|
|
- }());
|
|
|
-
|
|
|
+ load();
|
|
|
</script>
|
|
|
|
|
|
</html>
|