mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-21 01:36:02 +08:00
Merge branch '4.0' into 4.1-beta
# Conflicts: # spine-ts/package-lock.json # spine-ts/package.json # spine-ts/spine-canvas/package.json # spine-ts/spine-core/package.json # spine-ts/spine-player/package.json # spine-ts/spine-threejs/package.json # spine-ts/spine-webgl/package.json
This commit is contained in:
commit
fb0a658ecf
@ -336,6 +336,7 @@
|
||||
* Added `SpinePlayerConfig.draw`. If set, the callback is called each frame, just after the skeleton is drawn.
|
||||
* Added `SpinePlayerConfig.downloader`. The `spine.Downloader` instance can be shared between players so assets are only downloaded once.
|
||||
* If `SpinePlayerConfig.jsonURL` ends with an anchor, the anchor text is used to find the skeleton in the specified JSON file.
|
||||
* Added `SpinePlayer.dispose()`, disposes all CPU and GPU side resources, removes all listeners, and removes the player DOM from the parent.
|
||||
|
||||
# 3.8
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
<li><a href="/spine-player/example/embedding-binary-example.html">Embedding binary</a></li>
|
||||
<li><a href="/spine-player/example/embedding-json-example.html">Embedding JSON</a></li>
|
||||
<li><a href="/spine-player/example/editor.html">Editor</a></li>
|
||||
<li><a href="/spine-player/example/dispose.html">Disposing a player</a></li>
|
||||
</ul>
|
||||
<li>WebGL</li>
|
||||
<ul>
|
||||
|
||||
24
spine-ts/publish.sh
Executable file
24
spine-ts/publish.sh
Executable file
@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
if [ ! "$#" -eq 2 ]; then
|
||||
echo "Usage: ./publish.sh <last-version> <new-version>"
|
||||
exit
|
||||
else
|
||||
lastVersion=${1%/}
|
||||
newVersion=${2%/}
|
||||
echo "last version: $lastVersion"
|
||||
echo "new version: $newVersion"
|
||||
fi
|
||||
|
||||
sed -i '' "s/$lastVersion/$newVersion/" package.json
|
||||
sed -i '' "s/$lastVersion/$newVersion/" spine-canvas/package.json
|
||||
sed -i '' "s/$lastVersion/$newVersion/" spine-core/package.json
|
||||
sed -i '' "s/$lastVersion/$newVersion/" spine-player/package.json
|
||||
sed -i '' "s/$lastVersion/$newVersion/" spine-threejs/package.json
|
||||
sed -i '' "s/$lastVersion/$newVersion/" spine-webgl/package.json
|
||||
|
||||
rm -rf node_modules
|
||||
rm package-lock.json
|
||||
npm install
|
||||
npm publish --access public --workspaces
|
||||
49
spine-ts/spine-player/example/dispose.html
Normal file
49
spine-ts/spine-player/example/dispose.html
Normal file
@ -0,0 +1,49 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src="../dist/iife/spine-player.js"></script>
|
||||
<link rel="stylesheet" href="../css/spine-player.css">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
|
||||
<style>
|
||||
body {
|
||||
background: gray;
|
||||
margin: 0px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<div id="container" style="width:640px; height:380px"></div>
|
||||
<div>
|
||||
<button id="dispose">Dispose</button>
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
var player = createPlayer();
|
||||
|
||||
document.getElementById("dispose").addEventListener("click", event => {
|
||||
console.log("Disposing player.");
|
||||
player.dispose();
|
||||
player = createPlayer();
|
||||
});
|
||||
|
||||
function createPlayer() {
|
||||
return new spine.SpinePlayer("container", {
|
||||
skelUrl: "assets/spineboy-pro.skel",
|
||||
atlasUrl: "assets/spineboy-pma.atlas",
|
||||
animation: "run",
|
||||
premultipliedAlpha: true,
|
||||
backgroundColor: "#cccccc",
|
||||
viewport: {
|
||||
debugRender: true,
|
||||
},
|
||||
showControls: true
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -27,7 +27,7 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Animation, AnimationState, AnimationStateData, AtlasAttachmentLoader, Bone, Color, Downloader, MathUtils, MixBlend, MixDirection, Skeleton, SkeletonBinary, SkeletonData, SkeletonJson, StringMap, TextureAtlas, TextureFilter, TimeKeeper, TrackEntry, Vector2 } from "@esotericsoftware/spine-core"
|
||||
import { Animation, AnimationState, AnimationStateData, AtlasAttachmentLoader, Bone, Color, Disposable, Downloader, MathUtils, MixBlend, MixDirection, Skeleton, SkeletonBinary, SkeletonData, SkeletonJson, StringMap, TextureAtlas, TextureFilter, TimeKeeper, TrackEntry, Vector2 } from "@esotericsoftware/spine-core"
|
||||
import { AssetManager, GLTexture, Input, LoadingScreen, ManagedWebGLRenderingContext, ResizeMode, SceneRenderer, Vector3 } from "@esotericsoftware/spine-webgl"
|
||||
|
||||
export interface SpinePlayerConfig {
|
||||
@ -178,7 +178,7 @@ export interface Viewport {
|
||||
padBottom: string | number
|
||||
}
|
||||
|
||||
export class SpinePlayer {
|
||||
export class SpinePlayer implements Disposable {
|
||||
public parent: HTMLElement;
|
||||
public dom: HTMLElement;
|
||||
public canvas: HTMLCanvasElement;
|
||||
@ -211,11 +211,13 @@ export class SpinePlayer {
|
||||
public speed = 1;
|
||||
public time = new TimeKeeper();
|
||||
private stopRequestAnimationFrame = false;
|
||||
private disposed = false;
|
||||
|
||||
private viewport: Viewport = {} as Viewport;
|
||||
private currentViewport: Viewport;
|
||||
private previousViewport: Viewport;
|
||||
private viewportTransitionStart = 0;
|
||||
private eventListeners: Array<{ target: any, event: any, func: any }> = [];
|
||||
|
||||
constructor (parent: HTMLElement | string, private config: SpinePlayerConfig) {
|
||||
this.parent = typeof parent === "string" ? document.getElementById(parent) : parent;
|
||||
@ -248,12 +250,29 @@ export class SpinePlayer {
|
||||
this.initialize();
|
||||
|
||||
// Register a global resize handler to redraw, avoiding flicker.
|
||||
window.addEventListener("resize", () => this.drawFrame(false));
|
||||
this.addEventListener(window, "resize", () => this.drawFrame(false));
|
||||
|
||||
// Start the rendering loop.
|
||||
requestAnimationFrame(() => this.drawFrame());
|
||||
}
|
||||
|
||||
dispose (): void {
|
||||
this.sceneRenderer.dispose();
|
||||
this.loadingScreen.dispose();
|
||||
this.assetManager.dispose();
|
||||
for (var i = 0; i < this.eventListeners.length; i++) {
|
||||
var eventListener = this.eventListeners[i];
|
||||
eventListener.target.removeEventListener(eventListener.event, eventListener.func);
|
||||
}
|
||||
this.parent.removeChild(this.dom);
|
||||
this.disposed = true;
|
||||
}
|
||||
|
||||
addEventListener (target: any, event: any, func: any) {
|
||||
this.eventListeners.push({ target: target, event: event, func: func });
|
||||
target.addEventListener(event, func);
|
||||
}
|
||||
|
||||
private validateConfig (config: SpinePlayerConfig) {
|
||||
if (!config) throw new Error("A configuration object must be passed to to new SpinePlayer().");
|
||||
if ((config as any).skelUrl) config.binaryUrl = (config as any).skelUrl;
|
||||
@ -583,16 +602,17 @@ export class SpinePlayer {
|
||||
if (config.showControls) {
|
||||
// For manual hover to work, we need to disable hidding controls if the mouse/touch entered the clickable area of a child of the controls.
|
||||
// For this we need to register a mouse handler on the document and see if we are within the canvas area.
|
||||
document.addEventListener("mousemove", (ev: UIEvent) => {
|
||||
this.addEventListener(document, "mousemove", (ev: UIEvent) => {
|
||||
if (ev instanceof MouseEvent) handleHover(ev.clientX, ev.clientY);
|
||||
});
|
||||
document.addEventListener("touchmove", (ev: UIEvent) => {
|
||||
this.addEventListener(document, "touchmove", (ev: UIEvent) => {
|
||||
if (ev instanceof TouchEvent) {
|
||||
let touches = ev.changedTouches;
|
||||
if (touches.length) {
|
||||
let touch = touches[0];
|
||||
handleHover(touch.clientX, touch.clientY);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@ -747,6 +767,7 @@ export class SpinePlayer {
|
||||
private drawFrame (requestNextFrame = true) {
|
||||
try {
|
||||
if (this.error) return;
|
||||
if (this.disposed) return;
|
||||
if (requestNextFrame && !this.stopRequestAnimationFrame) requestAnimationFrame(() => this.drawFrame());
|
||||
|
||||
let doc = document as any;
|
||||
@ -1015,6 +1036,7 @@ export class SpinePlayer {
|
||||
class Popup {
|
||||
public dom: HTMLElement;
|
||||
private className: string;
|
||||
private windowClickListener: any;
|
||||
|
||||
constructor (private id: string, private button: HTMLElement, private player: SpinePlayer, parent: HTMLElement, htmlContent: string) {
|
||||
this.dom = createElement(/*html*/`<div class="spine-player-popup spine-player-hidden"></div>`);
|
||||
@ -1023,6 +1045,10 @@ class Popup {
|
||||
this.className = "spine-player-button-icon-" + id + "-selected";
|
||||
}
|
||||
|
||||
dispose () {
|
||||
|
||||
}
|
||||
|
||||
hide (id: string): boolean {
|
||||
this.dom.remove();
|
||||
this.button.classList.remove(this.className);
|
||||
@ -1063,7 +1089,7 @@ class Popup {
|
||||
dismissed = true;
|
||||
}
|
||||
};
|
||||
window.addEventListener("click", windowClickListener);
|
||||
this.player.addEventListener(window, "click", windowClickListener);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1074,6 +1100,7 @@ class Switch {
|
||||
|
||||
constructor (private text: string) { }
|
||||
|
||||
|
||||
create (): HTMLElement {
|
||||
this.switch = createElement(/*html*/`
|
||||
<div class="spine-player-switch">
|
||||
@ -1092,7 +1119,8 @@ class Switch {
|
||||
setEnabled (enabled: boolean) {
|
||||
if (enabled) this.switch.classList.add("active");
|
||||
else this.switch.classList.remove("active");
|
||||
this.enabled = enabled;
|
||||
this.enabled = enabled
|
||||
;
|
||||
}
|
||||
|
||||
isEnabled (): boolean {
|
||||
|
||||
@ -27,8 +27,6 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Pool } from "@esotericsoftware/spine-core";
|
||||
|
||||
export class Input {
|
||||
element: HTMLElement;
|
||||
mouseX = 0;
|
||||
@ -38,6 +36,7 @@ export class Input {
|
||||
touch1: Touch = null;
|
||||
initialPinchDistance = 0;
|
||||
private listeners = new Array<InputListener>();
|
||||
private eventListeners: Array<{ target: any, event: any, func: any }> = [];
|
||||
|
||||
constructor (element: HTMLElement) {
|
||||
this.element = element;
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Color, TimeKeeper } from "@esotericsoftware/spine-core";
|
||||
import { Color, Disposable, TimeKeeper } from "@esotericsoftware/spine-core";
|
||||
import { GLTexture } from "./GLTexture";
|
||||
import { ResizeMode, SceneRenderer } from "./SceneRenderer";
|
||||
|
||||
@ -38,7 +38,7 @@ let loaded = 0;
|
||||
const FADE_IN = 1, FADE_OUT = 1;
|
||||
const logoWidth = 165, logoHeight = 108, spinnerSize = 163;
|
||||
|
||||
export class LoadingScreen {
|
||||
export class LoadingScreen implements Disposable {
|
||||
private renderer: SceneRenderer;
|
||||
private logo: GLTexture = null;
|
||||
private spinner: GLTexture = null;
|
||||
@ -69,6 +69,10 @@ export class LoadingScreen {
|
||||
spinnerImage.onload = onload;
|
||||
}
|
||||
}
|
||||
dispose (): void {
|
||||
this.logo.dispose();
|
||||
this.spinner.dispose();
|
||||
}
|
||||
|
||||
draw (complete = false) {
|
||||
if (loaded < 2 || (complete && this.fadeOut > FADE_OUT)) return;
|
||||
|
||||
@ -73,6 +73,14 @@ export class SceneRenderer implements Disposable {
|
||||
this.skeletonDebugRenderer = new SkeletonDebugRenderer(this.context);
|
||||
}
|
||||
|
||||
dispose () {
|
||||
this.batcher.dispose();
|
||||
this.batcherShader.dispose();
|
||||
this.shapes.dispose();
|
||||
this.shapesShader.dispose();
|
||||
this.skeletonDebugRenderer.dispose();
|
||||
}
|
||||
|
||||
begin () {
|
||||
this.camera.update();
|
||||
this.enableRenderer(this.batcher);
|
||||
@ -498,14 +506,6 @@ export class SceneRenderer implements Disposable {
|
||||
} else
|
||||
this.activeRenderer = this.skeletonDebugRenderer;
|
||||
}
|
||||
|
||||
dispose () {
|
||||
this.batcher.dispose();
|
||||
this.batcherShader.dispose();
|
||||
this.shapes.dispose();
|
||||
this.shapesShader.dispose();
|
||||
this.skeletonDebugRenderer.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export enum ResizeMode {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user