[ts][player] Added controllable bones to player.

This commit is contained in:
badlogic 2018-11-08 16:00:23 +01:00
parent fe44bece46
commit 49ba1d2bd9
5 changed files with 11940 additions and 11812 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -277,25 +277,10 @@ body {
</body> </body>
<script> <script>
new spine.SpinePlayer(document.getElementById("container"), { new spine.SpinePlayer(document.getElementById("container"), {
jsonUrl: "assets/raptor-pro.json", jsonUrl: "assets/spineboy-pro.json",
atlasUrl: "assets/raptor.atlas", atlasUrl: "assets/spineboy.atlas",
animation: "walk", controlBones: ["root"],
animations: ["walk", "roar", "jump"], backgroundColor: "#cccccc"
skin: "default",
skins: ["default"],
backgroundColor: "#ff00ff",
backgroundImage: {
url: "assets/spineboy.png",
x: 0,
y: 0,
width: 300,
height: 200
},
debug: {
bones: true,
regions: true,
meshes: true,
}
}); });
</script> </script>
</body> </body>

View File

@ -62,6 +62,7 @@
height: number height: number
} }
premultipliedAlpha: boolean premultipliedAlpha: boolean
controlBones: string[]
success: (widget: SpineWidget) => void success: (widget: SpineWidget) => void
error: (widget: SpineWidget, msg: string) => void error: (widget: SpineWidget, msg: string) => void
} }
@ -181,6 +182,11 @@
} }
export class SpinePlayer { export class SpinePlayer {
static HOVER_COLOR_INNER = new spine.Color(0.478, 0, 0, 0.25);
static HOVER_COLOR_OUTER = new spine.Color(1, 1, 1, 1);
static NON_HOVER_COLOR_INNER = new spine.Color(0.478, 0, 0, 0.5);
static NON_HOVER_COLOR_OUTER = new spine.Color(1, 0, 0, 0.8);
private sceneRenderer: spine.webgl.SceneRenderer; private sceneRenderer: spine.webgl.SceneRenderer;
private dom: HTMLElement; private dom: HTMLElement;
private playerControls: HTMLElement; private playerControls: HTMLElement;
@ -200,6 +206,8 @@
private playTime = 0; private playTime = 0;
private speed = 1; private speed = 1;
private selectedBones: Bone[];
constructor(parent: HTMLElement, private config: SpinePlayerConfig) { constructor(parent: HTMLElement, private config: SpinePlayerConfig) {
this.config = this.validateConfig(config); this.config = this.validateConfig(config);
parent.appendChild(this.render()); parent.appendChild(this.render());
@ -241,6 +249,7 @@
if (config.skins.indexOf(config.skin) < 0) throw new Error("Default skin " + config.skin + " is not contained in the list of selectable skins."); if (config.skins.indexOf(config.skin) < 0) throw new Error("Default skin " + config.skin + " is not contained in the list of selectable skins.");
} }
if (!config.controlBones) config.controlBones = [];
return config; return config;
} }
@ -338,6 +347,8 @@
this.drawFrame(false); this.drawFrame(false);
} }
// Setup input handler for control bones and pan/zoom
return dom; return dom;
} }
@ -504,7 +515,7 @@
let animationDuration = this.animationState.getCurrent(0).animation.duration; let animationDuration = this.animationState.getCurrent(0).animation.duration;
this.playTime += delta; this.playTime += delta;
while (this.playTime >= animationDuration) { while (this.playTime >= animationDuration && animationDuration != 0) {
this.playTime -= animationDuration; this.playTime -= animationDuration;
} }
this.playTime = Math.max(0, Math.min(this.playTime, animationDuration)); this.playTime = Math.max(0, Math.min(this.playTime, animationDuration));
@ -544,6 +555,21 @@
this.sceneRenderer.skeletonDebugRenderer.drawMeshTriangles = this.config.debug.meshes; this.sceneRenderer.skeletonDebugRenderer.drawMeshTriangles = this.config.debug.meshes;
this.sceneRenderer.drawSkeletonDebug(this.skeleton, this.config.premultipliedAlpha); this.sceneRenderer.drawSkeletonDebug(this.skeleton, this.config.premultipliedAlpha);
// Render the selected bones
let controlBones = this.config.controlBones;
let selectedBones = this.selectedBones;
let skeleton = this.skeleton;
gl.lineWidth(2);
for (var i = 0; i < controlBones.length; i++) {
var bone = skeleton.findBone(controlBones[i]);
if (!bone) continue;
var colorInner = selectedBones[i] !== null ? SpinePlayer.HOVER_COLOR_INNER : SpinePlayer.NON_HOVER_COLOR_INNER;
var colorOuter = selectedBones[i] !== null ? SpinePlayer.HOVER_COLOR_OUTER : SpinePlayer.NON_HOVER_COLOR_OUTER;
this.sceneRenderer.circle(true, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, colorInner);
this.sceneRenderer.circle(false, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, colorOuter);
}
gl.lineWidth(1);
this.sceneRenderer.end(); this.sceneRenderer.end();
this.sceneRenderer.camera.zoom = 0; this.sceneRenderer.camera.zoom = 0;
@ -608,6 +634,7 @@
this.config.animation = skeletonData.animations[0].name; this.config.animation = skeletonData.animations[0].name;
} }
} }
if(this.config.animation) { if(this.config.animation) {
this.play() this.play()
this.timelineSlider.change = (percentage) => { this.timelineSlider.change = (percentage) => {
@ -621,9 +648,65 @@
} }
} }
// Setup the input processor and controllable bones
this.setupInput();
this.loaded = true; this.loaded = true;
} }
setupInput () {
let controlBones = this.config.controlBones;
let selectedBones = this.selectedBones = new Array<Bone>(this.config.controlBones.length);
let canvas = this.canvas;
let input = new spine.webgl.Input(canvas);
var target:Bone = null;
let coords = new spine.webgl.Vector3();
let temp = new spine.webgl.Vector3();
let temp2 = new spine.Vector2();
let skeleton = this.skeleton
let renderer = this.sceneRenderer;
input.addListener({
down: (x, y) => {
for (var i = 0; i < controlBones.length; i++) {
var bone = skeleton.findBone(controlBones[i]);
if (!bone) continue;
renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);
if (temp.set(skeleton.x + bone.worldX, skeleton.y + bone.worldY, 0).distance(coords) < 30) {
target = bone;
}
}
},
up: (x, y) => {
target = null;
},
dragged: (x, y) => {
if (target != null) {
renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);
if (target.parent !== null) {
target.parent.worldToLocal(temp2.set(coords.x - skeleton.x, coords.y - skeleton.y));
target.x = temp2.x;
target.y = temp2.y;
} else {
target.x = coords.x - skeleton.x;
target.y = coords.y - skeleton.y;
}
}
},
moved: (x, y) => {
for (var i = 0; i < controlBones.length; i++) {
var bone = skeleton.findBone(controlBones[i]);
if (!bone) continue;
renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.width, canvas.height);
if (temp.set(skeleton.x + bone.worldX, skeleton.y + bone.worldY, 0).distance(coords) < 30) {
selectedBones[i] = bone;
} else {
selectedBones[i] = null;
}
}
}
});
}
private play () { private play () {
this.paused = false; this.paused = false;
this.playButton.classList.remove("spine-player-button-icon-play"); this.playButton.classList.remove("spine-player-button-icon-play");
@ -641,20 +724,6 @@
this.playButton.classList.remove("spine-player-button-icon-pause"); this.playButton.classList.remove("spine-player-button-icon-pause");
this.playButton.classList.add("spine-player-button-icon-play"); this.playButton.classList.add("spine-player-button-icon-play");
} }
private resize () {
let canvas = this.canvas;
let w = canvas.clientWidth;
let h = canvas.clientHeight;
var devicePixelRatio = window.devicePixelRatio || 1;
if (canvas.width != Math.floor(w * devicePixelRatio) || canvas.height != Math.floor(h * devicePixelRatio)) {
canvas.width = Math.floor(w * devicePixelRatio);
canvas.height = Math.floor(h * devicePixelRatio);
}
this.context.gl.viewport(0, 0, canvas.width, canvas.height);
this.sceneRenderer.camera.setViewport(canvas.width, canvas.height);
}
} }
function isContained(dom: HTMLElement, needle: HTMLElement): boolean { function isContained(dom: HTMLElement, needle: HTMLElement): boolean {