111 lines
3.7 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<!--<script src="https://unpkg.com/@esotericsoftware/spine-canvas@4.0.*/dist/iife/spine-canvas.js"></script>-->
<script src="../dist/iife/spine-canvas.js"></script>
</head>
<body style="margin: 0; padding: 0;">
<canvas id="canvas" style="width: 100%; height: 100vh;"></canvas>
</body>
<script>
let lastFrameTime = Date.now() / 1000;
let canvas, context;
let assetManager;
let skeleton, animationState, bounds;
let skeletonRenderer;
async function load() {
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
skeletonRenderer = new spine.SkeletonRenderer(context);
// 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();
// 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"));
// Instantiate a new skeleton based on the atlas and skeleton data.
skeleton = new spine.Skeleton(skeletonData);
skeleton.setToSetupPose();
skeleton.updateWorldTransform();
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);
// Add a click listener to the canvas which checks if Spineboy's head
// was clicked.
canvas.addEventListener('click', event => {
// Make the mouse click coordinates relative to the canvas.
let canvasRect = canvas.getBoundingClientRect();
var mouseX = event.x - canvasRect.x;
var mouseY = event.y - canvasRect.y;
// Find the "head" bone.
var headBone = skeleton.findBone("head");
// If the mouse pointer is within 100 pixels of the head bone, fire the jump animation event.
// Afterwards, loop the run animation.
if (pointInCircle(mouseX, mouseY, headBone.worldX, headBone.worldY, 100)) {
var jumpEntry = animationState.setAnimation(0, "jump", false);
var walkEntry = animationState.addAnimation(0, "run", true);
}
});
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 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);
requestAnimationFrame(render);
}
// Checks if the point given by x/y are within the circle.
function pointInCircle(x, y, circleX, circleY, circleRadius) {
var distX = x - circleX;
var distY = y - circleY;
return distX * distX + distY * distY <= circleRadius * circleRadius;
}
load();
</script>
</html>