mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-20 17:26:01 +08:00
117 lines
4.0 KiB
HTML
117 lines
4.0 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; background: #333">
|
|
<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);
|
|
skeletonRenderer.triangleRendering = true;
|
|
|
|
// Load the assets.
|
|
assetManager = new spine.AssetManager("assets/");
|
|
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(spine.Physics.update);
|
|
bounds = skeleton.getBoundsRect();
|
|
|
|
// Spineboy's head bounding box attachment is not attached by default. Attach it.
|
|
skeleton.setAttachment("head-bb", "head");
|
|
|
|
// Setup an animation state with a default mix of 0.2 seconds.
|
|
let 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();
|
|
let mouseX = event.x - canvasRect.x;
|
|
let mouseY = event.y - canvasRect.y;
|
|
|
|
// Create and update a SkeletonBounds instance for later hit testing.
|
|
let skelBounds = new spine.SkeletonBounds();
|
|
skelBounds.update(skeleton);
|
|
|
|
// Check if the mouse coordinates are inside any of the bounding box
|
|
// attachments of the skeleton. If so, play the jump animation, followed
|
|
// by a looping run animation.
|
|
if (skelBounds.containsPoint(mouseX, mouseY)) {
|
|
let jumpEntry = animationState.setAnimation(0, "jump", false);
|
|
let walkEntry = animationState.addAnimation(0, "run", true);
|
|
}
|
|
});
|
|
|
|
requestAnimationFrame(render);
|
|
}
|
|
|
|
function render() {
|
|
// Calculate the delta time between this and the last frame in seconds.
|
|
let now = Date.now() / 1000;
|
|
let 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(spine.Physics.update);
|
|
skeletonRenderer.draw(skeleton);
|
|
|
|
requestAnimationFrame(render);
|
|
}
|
|
|
|
// Checks if the point given by x/y are within the circle.
|
|
function pointInCircle(x, y, circleX, circleY, circleRadius) {
|
|
let distX = x - circleX;
|
|
let distY = y - circleY;
|
|
return distX * distX + distY * distY <= circleRadius * circleRadius;
|
|
}
|
|
|
|
load();
|
|
</script>
|
|
|
|
</html> |