-
Notifications
You must be signed in to change notification settings - Fork 2.9k
/
bone-dragging.html
126 lines (111 loc) · 5.84 KB
/
bone-dragging.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
<html>
<script src="../dist/iife/spine-webgl.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
</style>
<body>
<canvas id="canvas" style="position: absolute; width: 100%; height: 100%;"></canvas>
<script>
class App {
constructor() {
this.skeleton = null;
this.animationState = null;
this.draggableBones = [];
this.draggedBone = null;
}
loadAssets(canvas) {
canvas.assetManager.loadBinary("assets/stretchyman-pro.skel");
canvas.assetManager.loadTextureAtlas("assets/stretchyman-pma.atlas");
}
initialize(canvas) {
let assetManager = canvas.assetManager;
var atlas = assetManager.require("assets/stretchyman-pma.atlas");
var atlasLoader = new spine.AtlasAttachmentLoader(atlas);
var skeletonBinary = new spine.SkeletonBinary(atlasLoader);
skeletonBinary.scale = 1;
var skeletonData = skeletonBinary.readSkeletonData(assetManager.require("assets/stretchyman-pro.skel"));
this.skeleton = new spine.Skeleton(skeletonData);
var animationStateData = new spine.AnimationStateData(skeletonData);
this.animationState = new spine.AnimationState(animationStateData);
// Find the bones that should be draggable
let draggableBoneNames = [
"back-leg-ik-target",
"front-leg-ik-target",
"back-arm-ik-target",
"front-arm-ik-target",
"hip",
"neck2"
];
for (let boneName of draggableBoneNames) {
let bone = this.skeleton.findBone(boneName);
if (bone == null) throw Error("Couldn't find bone " + boneName);
this.draggableBones.push(bone)
}
// Setup an input listener on the canvas to process touch/mouse events.
canvas.input.addListener({
down: (x, y) => {
// Calculate the mouse position in the coordinate space of the camera, aka world space.
// The skeleton and its bones live in the same coordinate space.
let mousePosition = new spine.Vector3(x, y);
canvas.renderer.camera.screenToWorld(mousePosition, canvas.htmlCanvas.clientWidth, canvas.htmlCanvas.clientHeight);
// Find the first bone within a radius of 20 pixels to the mouse position
this.selectedBone = null;
for (let bone of this.draggableBones) {
if (mousePosition.distance(new spine.Vector3(bone.worldX, bone.worldY, 0)) < 20) {
this.selectedBone = bone;
break;
}
}
},
dragged: (x, y) => {
// If no bone was selected, bail.
if (this.selectedBone == null) return;
// Calculate the mouse position in the coordinate space of the camera, aka world space.
// The skeleton and its bones live in this coordinate space.
let mousePosition = new spine.Vector3(x, y);
canvas.renderer.camera.screenToWorld(mousePosition, canvas.htmlCanvas.clientWidth, canvas.htmlCanvas.clientHeight);
if (this.selectedBone.parent != null) {
// If the bone to be dragged has a parent, transform the mouse world position to
// the parent bone's coordinate system, and set the bone's position accordingly.
let position = new spine.Vector2(mousePosition.x, mousePosition.y);
this.selectedBone.parent.worldToLocal(position);
this.selectedBone.x = position.x;
this.selectedBone.y = position.y;
} else {
// If the dragged bone has no parent, it's the root bone and we can simply set its
// position to the mouse world position.
this.selectedBone.x = mousePosition.x;
this.selectedBone.y = mousePosition.y;
}
}
})
}
update(canvas, delta) {
this.animationState.update(delta);
this.animationState.apply(this.skeleton);
this.skeleton.updateWorldTransform();
}
render(canvas) {
let renderer = canvas.renderer;
renderer.resize(spine.ResizeMode.Expand);
canvas.clear(0.2, 0.2, 0.2, 1);
renderer.begin();
renderer.drawSkeleton(this.skeleton, true);
// Draw a circle with a radius of 20 pixels around each draggable bone
let boneColor = new spine.Color(1, 0, 0, 0.5);
let selectedBoneColor = new spine.Color(0, 1, 0, 0.5);
for (let bone of this.draggableBones) {
renderer.circle(true, bone.worldX, bone.worldY, 20, bone == this.selectedBone ? selectedBoneColor : boneColor);
}
renderer.end();
}
}
new spine.SpineCanvas(document.getElementById("canvas"), {
app: new App()
})
</script>
</body>
</html>