From be6b19afa55bbed2c1918a72f20c18d6cc3cd87f Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 14 Dec 2022 14:35:09 +0100 Subject: [PATCH] [phaser] Bounds calculation, hit area support, more examples. # Conflicts: # spine-ts/package-lock.json --- .../spine-phaser/example/basic-example.html | 44 +++++++ .../example/{index.js => batching-test.html} | 26 +++-- .../spine-phaser/example/bounds-test.html | 56 +++++++++ spine-ts/spine-phaser/example/index.html | 9 +- .../example/multi-scene-test.html | 65 +++++++++++ .../spine-phaser/example/visibility-test.html | 50 ++++++++ spine-ts/spine-phaser/src/SpineGameObject.ts | 108 +++++++++++++++--- 7 files changed, 332 insertions(+), 26 deletions(-) create mode 100644 spine-ts/spine-phaser/example/basic-example.html rename spine-ts/spine-phaser/example/{index.js => batching-test.html} (75%) create mode 100644 spine-ts/spine-phaser/example/bounds-test.html create mode 100644 spine-ts/spine-phaser/example/multi-scene-test.html create mode 100644 spine-ts/spine-phaser/example/visibility-test.html diff --git a/spine-ts/spine-phaser/example/basic-example.html b/spine-ts/spine-phaser/example/basic-example.html new file mode 100644 index 000000000..0e3b7a75c --- /dev/null +++ b/spine-ts/spine-phaser/example/basic-example.html @@ -0,0 +1,44 @@ + + + + + + + + + Spine Phaser Example + + +

Basic example

+ + + \ No newline at end of file diff --git a/spine-ts/spine-phaser/example/index.js b/spine-ts/spine-phaser/example/batching-test.html similarity index 75% rename from spine-ts/spine-phaser/example/index.js rename to spine-ts/spine-phaser/example/batching-test.html index d9a465510..8626d4cd6 100644 --- a/spine-ts/spine-phaser/example/index.js +++ b/spine-ts/spine-phaser/example/batching-test.html @@ -1,9 +1,17 @@ - -/// -/// -/// -/// - + + + + + + + + + Spine Phaser Example + + +

Batching test

+ + + \ No newline at end of file diff --git a/spine-ts/spine-phaser/example/bounds-test.html b/spine-ts/spine-phaser/example/bounds-test.html new file mode 100644 index 000000000..6a62b8fae --- /dev/null +++ b/spine-ts/spine-phaser/example/bounds-test.html @@ -0,0 +1,56 @@ + + + + + + + + + Spine Phaser Example + + +

Bounds test

+ + + \ No newline at end of file diff --git a/spine-ts/spine-phaser/example/index.html b/spine-ts/spine-phaser/example/index.html index ef3e1dfcf..b15fdf427 100644 --- a/spine-ts/spine-phaser/example/index.html +++ b/spine-ts/spine-phaser/example/index.html @@ -5,11 +5,16 @@ - Spine Phaser Example

Spine Phaser

+ - \ No newline at end of file diff --git a/spine-ts/spine-phaser/example/multi-scene-test.html b/spine-ts/spine-phaser/example/multi-scene-test.html new file mode 100644 index 000000000..7c1f74c13 --- /dev/null +++ b/spine-ts/spine-phaser/example/multi-scene-test.html @@ -0,0 +1,65 @@ + + + + + + + + + Spine Phaser Example + + +

Multi-scene test

+ + + \ No newline at end of file diff --git a/spine-ts/spine-phaser/example/visibility-test.html b/spine-ts/spine-phaser/example/visibility-test.html new file mode 100644 index 000000000..463b3bd3b --- /dev/null +++ b/spine-ts/spine-phaser/example/visibility-test.html @@ -0,0 +1,50 @@ + + + + + + + + + Spine Phaser Example + + +

Basic example

+ + + \ No newline at end of file diff --git a/spine-ts/spine-phaser/src/SpineGameObject.ts b/spine-ts/spine-phaser/src/SpineGameObject.ts index 93dbca46d..512d07006 100644 --- a/spine-ts/spine-phaser/src/SpineGameObject.ts +++ b/spine-ts/spine-phaser/src/SpineGameObject.ts @@ -2,42 +2,117 @@ import { SPINE_GAME_OBJECT_TYPE } from "./keys"; import { SpinePlugin } from "./SpinePlugin"; import { ComputedSizeMixin, DepthMixin, FlipMixin, ScrollFactorMixin, TransformMixin, VisibleMixin } from "./mixins"; import { AnimationState, AnimationStateData, MathUtils, Skeleton } from "@esotericsoftware/spine-core"; -import { Matrix4, Vector3 } from "@esotericsoftware/spine-webgl"; class BaseSpineGameObject extends Phaser.GameObjects.GameObject { - constructor (scene: Phaser.Scene, type: string) { + constructor(scene: Phaser.Scene, type: string) { super(scene, type); } } -interface SpineContainer { +export interface SpineGameObjectBoundsProvider { + calculateBounds(gameObject: SpineGameObject): { x: number, y: number, width: number, height: number }; +} +export class SetupPoseBoundsProvider implements SpineGameObjectBoundsProvider { + calculateBounds(gameObject: SpineGameObject) { + if (!gameObject.skeleton) return { x: 0, y: 0, width: 0, height: 0 }; + gameObject.skeleton.setToSetupPose(); + gameObject.skeleton.updateWorldTransform(); + return gameObject.skeleton.getBoundsRect(); + } +} + +export class SkinsAndAnimationBoundsProvider implements SpineGameObjectBoundsProvider { + constructor(private animation: string, private skins: string[] = []) { + + } + + calculateBounds(gameObject: SpineGameObject): { x: number; y: number; width: number; height: number; } { + if (!gameObject.skeleton) return { x: 0, y: 0, width: 0, height: 0 }; + // FIXME + gameObject.skeleton.setToSetupPose(); + gameObject.skeleton.updateWorldTransform(); + return gameObject.skeleton.getBoundsRect(); + } } export class SpineGameObject extends ComputedSizeMixin(DepthMixin(FlipMixin(ScrollFactorMixin(TransformMixin(VisibleMixin(BaseSpineGameObject)))))) { blendMode = -1; skeleton: Skeleton | null = null; + animationStateData: AnimationStateData | null = null; animationState: AnimationState | null = null; private premultipliedAlpha = false; + private _displayOriginX = 0; + private _displayOriginY = 0; + private _scaleX = 1; + private _scaleY = 1; - constructor (scene: Phaser.Scene, private plugin: SpinePlugin, x: number, y: number, dataKey: string, atlasKey: string) { + constructor(scene: Phaser.Scene, private plugin: SpinePlugin, x: number, y: number, dataKey: string, atlasKey: string, public boundsProvider: SpineGameObjectBoundsProvider = new SetupPoseBoundsProvider()) { super(scene, SPINE_GAME_OBJECT_TYPE); - this.setPosition(x, y); + this.setPosition(x, y); x this.setSkeleton(dataKey, atlasKey); } - setSkeleton (dataKey: string, atlasKey: string) { + setSkeleton(dataKey: string, atlasKey: string) { if (dataKey && atlasKey) { this.premultipliedAlpha = this.plugin.isAtlasPremultiplied(atlasKey); this.skeleton = this.plugin.createSkeleton(dataKey, atlasKey); - this.animationState = new AnimationState(new AnimationStateData(this.skeleton.data)); + this.animationStateData = new AnimationStateData(this.skeleton.data); + this.animationState = new AnimationState(this.animationStateData); + this.updateSize(); } else { this.skeleton = null; + this.animationStateData = null; this.animationState = null; } } - preUpdate (time: number, delta: number) { + public get displayOriginX() { + return this._displayOriginX; + } + + public set displayOriginX(value: number) { + this._displayOriginX = value; + } + + public get displayOriginY() { + return this._displayOriginY; + } + + public set displayOriginY(value: number) { + this._displayOriginY = value; + } + + public get scaleX() { + return this._scaleX; + } + + public set scaleX(value: number) { + this._scaleX = value; + this.updateSize(); + } + + public get scaleY() { + return this._scaleX; + } + + public set scaleY(value: number) { + this._scaleY = value; + this.updateSize(); + } + + updateSize() { + if (!this.skeleton) return; + let bounds = this.boundsProvider.calculateBounds(this); + // For some reason the TS compiler and the ComputedSize mixin don't work well together... + let self = this as any; + self.width = bounds.width; + self.height = bounds.height; + this.displayOriginX = -bounds.x; + this.displayOriginY = -bounds.y; + } + + preUpdate(time: number, delta: number) { if (!this.skeleton || !this.animationState) return; this.animationState.update(delta / 1000); @@ -45,18 +120,22 @@ export class SpineGameObject extends ComputedSizeMixin(DepthMixin(FlipMixin(Scro this.skeleton.updateWorldTransform(); } - preDestroy () { + preDestroy() { this.skeleton = null; this.animationState = null; // FIXME tear down any event emitters } - willRender (camera: Phaser.Cameras.Scene2D.Camera) { - // FIXME - return true; + willRender(camera: Phaser.Cameras.Scene2D.Camera) { + if (!this.visible) return false; + + var GameObjectRenderMask = 0xf; + var result = (!this.skeleton || !(GameObjectRenderMask !== this.renderFlags || (this.cameraFilter !== 0 && (this.cameraFilter & camera.id)))); + + return result; } - renderWebGL (renderer: Phaser.Renderer.WebGL.WebGLRenderer, src: SpineGameObject, camera: Phaser.Cameras.Scene2D.Camera, parentMatrix: Phaser.GameObjects.Components.TransformMatrix) { + renderWebGL(renderer: Phaser.Renderer.WebGL.WebGLRenderer, src: SpineGameObject, camera: Phaser.Cameras.Scene2D.Camera, parentMatrix: Phaser.GameObjects.Components.TransformMatrix) { if (!this.skeleton || !this.animationState || !this.plugin.webGLRenderer) return; let sceneRenderer = this.plugin.webGLRenderer; @@ -80,11 +159,10 @@ export class SpineGameObject extends ComputedSizeMixin(DepthMixin(FlipMixin(Scro if (!renderer.nextTypeMatch) { sceneRenderer.end(); renderer.pipelines.rebind(); - console.log("Draw calls: " + sceneRenderer.batcher.getDrawCalls()); } } - renderCanvas (renderer: Phaser.Renderer.Canvas.CanvasRenderer, src: SpineGameObject, camera: Phaser.Cameras.Scene2D.Camera, parentMatrix: Phaser.GameObjects.Components.TransformMatrix) { + renderCanvas(renderer: Phaser.Renderer.Canvas.CanvasRenderer, src: SpineGameObject, camera: Phaser.Cameras.Scene2D.Camera, parentMatrix: Phaser.GameObjects.Components.TransformMatrix) { if (!this.skeleton || !this.animationState || !this.plugin.canvasRenderer) return; let context = renderer.currentContext;