mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-22 10:16:01 +08:00
[phaser] Mixins for SpineGameObject
This commit is contained in:
parent
f163f60187
commit
f3c4be2f90
11
spine-ts/package-lock.json
generated
11
spine-ts/package-lock.json
generated
@ -7301,14 +7301,6 @@
|
|||||||
"path": "^0.12.7"
|
"path": "^0.12.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/phaser3-project-template": {
|
|
||||||
"version": "1.0.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/phaser3-project-template/-/phaser3-project-template-1.0.9.tgz",
|
|
||||||
"integrity": "sha512-HUfQHE7Eg2kymO58ojGyIZGWlL7FY145Hdp1j0NAVkYrMJhZ2A3Ha40oe74OIwXx09pLYMRZJA/AepgmlPJcdA==",
|
|
||||||
"dependencies": {
|
|
||||||
"phaser": "^3.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/posix-character-classes": {
|
"node_modules/posix-character-classes": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
|
||||||
@ -8428,8 +8420,7 @@
|
|||||||
"license": "LicenseRef-LICENSE",
|
"license": "LicenseRef-LICENSE",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@esotericsoftware/spine-core": "^4.2.10",
|
"@esotericsoftware/spine-core": "^4.2.10",
|
||||||
"phaser": "^3.55.2",
|
"phaser": "^3.55.2"
|
||||||
"phaser3-project-template": "^1.0.9"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"spine-player": {
|
"spine-player": {
|
||||||
|
|||||||
@ -27,6 +27,6 @@ function preload () {
|
|||||||
|
|
||||||
function create () {
|
function create () {
|
||||||
let plugin = this.spine;
|
let plugin = this.spine;
|
||||||
let numbers = plugin.getNumbers(10);
|
var boy = this.add.spine(400, 600, 'raptor');
|
||||||
this.add.text(10, 10, numbers, { font: '16px Courier', fill: '#00ff00' });
|
this.add.text(10, 10, "Spine", { font: '16px Courier', fill: '#00ff00' });
|
||||||
}
|
}
|
||||||
@ -31,7 +31,6 @@
|
|||||||
"homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
|
"homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@esotericsoftware/spine-core": "^4.2.10",
|
"@esotericsoftware/spine-core": "^4.2.10",
|
||||||
"phaser": "^3.55.2",
|
"phaser": "^3.55.2"
|
||||||
"phaser3-project-template": "^1.0.9"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,29 @@
|
|||||||
|
import { SPINE_GAME_OBJECT_TYPE } from "./keys";
|
||||||
|
import { SpinePlugin } from "./SpinePlugin";
|
||||||
|
import { ComputedSizeMixin, DepthMixin, FlipMixin, ScrollFactorMixin, TransformMixin, VisibleMixin } from "./mixins";
|
||||||
|
|
||||||
|
class BaseSpineGameObject extends Phaser.GameObjects.GameObject {
|
||||||
|
constructor(scene: Phaser.Scene, type: string) {
|
||||||
|
super(scene, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SpineContainer {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SpineGameObject extends ComputedSizeMixin(DepthMixin(FlipMixin(ScrollFactorMixin(TransformMixin(VisibleMixin(BaseSpineGameObject)))))) {
|
||||||
|
blendMode = -1;
|
||||||
|
|
||||||
|
constructor(scene: Phaser.Scene, plugin: SpinePlugin, x: number, y: number, key: string) {
|
||||||
|
super(scene, SPINE_GAME_OBJECT_TYPE);
|
||||||
|
this.setPosition(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
preUpdate(time: number, delta: number) {
|
||||||
|
}
|
||||||
|
|
||||||
|
renderWebGL(renderer: Phaser.Renderer.WebGL.WebGLRenderer, src: SpineGameObject, camera: Phaser.Cameras.Scene2D.Camera, parentMatrix: Phaser.GameObjects.Components.TransformMatrix, container: SpineContainer) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -28,9 +28,10 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { SPINE_ATLAS_CACHE_KEY, SPINE_FILE_TYPE, SPINE_TEXTURE_CACHE_KEY } from "./keys";
|
import { SPINE_ATLAS_CACHE_KEY, SPINE_CONTAINER_TYPE, SPINE_FILE_TYPE, SPINE_GAME_OBJECT_TYPE, SPINE_TEXTURE_CACHE_KEY } from "./keys";
|
||||||
import { SceneRenderer, SkeletonDebugRenderer, SkeletonRenderer } from "@esotericsoftware/spine-webgl"
|
import { SceneRenderer, SkeletonDebugRenderer, SkeletonRenderer } from "@esotericsoftware/spine-webgl"
|
||||||
import { SpineFile } from "./SpineFile";
|
import { SpineFile } from "./SpineFile";
|
||||||
|
import { SpineGameObject } from "./SpineGameObject";
|
||||||
|
|
||||||
export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
|
export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
|
||||||
game: Phaser.Game;
|
game: Phaser.Game;
|
||||||
@ -42,8 +43,6 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
|
|||||||
gl: WebGLRenderingContext | null;
|
gl: WebGLRenderingContext | null;
|
||||||
phaserRenderer: Phaser.Renderer.Canvas.CanvasRenderer | Phaser.Renderer.WebGL.WebGLRenderer | null;
|
phaserRenderer: Phaser.Renderer.Canvas.CanvasRenderer | Phaser.Renderer.WebGL.WebGLRenderer | null;
|
||||||
sceneRenderer: SceneRenderer | null;
|
sceneRenderer: SceneRenderer | null;
|
||||||
skeletonRenderer: SkeletonRenderer | null;
|
|
||||||
skeletonDebugRenderer: SkeletonDebugRenderer | null;
|
|
||||||
|
|
||||||
constructor(scene: Phaser.Scene, pluginManager: Phaser.Plugins.PluginManager, pluginKey: string) {
|
constructor(scene: Phaser.Scene, pluginManager: Phaser.Plugins.PluginManager, pluginKey: string) {
|
||||||
super(scene, pluginManager, pluginKey);
|
super(scene, pluginManager, pluginKey);
|
||||||
@ -56,8 +55,6 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
|
|||||||
this.gl = this.isWebGL ? (this.game.renderer as Phaser.Renderer.WebGL.WebGLRenderer).gl : null;
|
this.gl = this.isWebGL ? (this.game.renderer as Phaser.Renderer.WebGL.WebGLRenderer).gl : null;
|
||||||
this.phaserRenderer = this.game.renderer;
|
this.phaserRenderer = this.game.renderer;
|
||||||
this.sceneRenderer = null;
|
this.sceneRenderer = null;
|
||||||
this.skeletonRenderer = null;
|
|
||||||
this.skeletonDebugRenderer = null;
|
|
||||||
|
|
||||||
if (!this.phaserRenderer) {
|
if (!this.phaserRenderer) {
|
||||||
this.phaserRenderer = {
|
this.phaserRenderer = {
|
||||||
@ -70,29 +67,96 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
|
|||||||
} as unknown as Phaser.Renderer.Canvas.CanvasRenderer;
|
} as unknown as Phaser.Renderer.Canvas.CanvasRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
let fileCallback = function (this: any, key: string | Phaser.Types.Loader.FileTypes.JSONFileConfig | Phaser.Types.Loader.FileTypes.JSONFileConfig[],
|
let fileCallback = function (this: any, key: string,
|
||||||
jsonURL: string,
|
jsonURL: string,
|
||||||
atlasURL: string | string[],
|
atlasURL: string,
|
||||||
premultipliedAlpha: boolean,
|
premultipliedAlpha: boolean,
|
||||||
jsonXhrSettings: Phaser.Types.Loader.XHRSettingsObject,
|
jsonXhrSettings: Phaser.Types.Loader.XHRSettingsObject,
|
||||||
atlasXhrSettings: Phaser.Types.Loader.XHRSettingsObject) {
|
atlasXhrSettings: Phaser.Types.Loader.XHRSettingsObject) {
|
||||||
let file = new SpineFile(this as any, key, jsonURL, atlasURL, premultipliedAlpha, jsonXhrSettings, atlasXhrSettings);
|
let file = new SpineFile(this as any, key, jsonURL, atlasURL, premultipliedAlpha, jsonXhrSettings, atlasXhrSettings);
|
||||||
this.addFile(file.files);
|
this.addFile(file.files);
|
||||||
return this;
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
pluginManager.registerFileType(SPINE_FILE_TYPE, fileCallback, scene);
|
|
||||||
|
|
||||||
|
let self = this;
|
||||||
|
let addSpineGameObject = function (this: Phaser.GameObjects.GameObjectFactory, x: number, y: number, key: string) {
|
||||||
|
let gameObject = new SpineGameObject(scene, self, x, y, key);
|
||||||
|
this.displayList.add(gameObject);
|
||||||
|
this.updateList.add(gameObject);
|
||||||
|
};
|
||||||
|
|
||||||
|
let makeSpineGameObject = function (this: Phaser.GameObjects.GameObjectFactory, config: any, addToScene: boolean) {
|
||||||
|
let key = config.key ? config.key : null;
|
||||||
|
let gameObject = new SpineGameObject(this.scene, self, 0, 0, key);
|
||||||
|
if (addToScene !== undefined) {
|
||||||
|
config.add = addToScene;
|
||||||
|
}
|
||||||
|
Phaser.GameObjects.BuildGameObject(this.scene, gameObject, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginManager.registerFileType(SPINE_FILE_TYPE, fileCallback, scene);
|
||||||
|
pluginManager.registerGameObject(SPINE_GAME_OBJECT_TYPE, addSpineGameObject, makeSpineGameObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
boot() {
|
boot() {
|
||||||
// FIXME
|
if (this.isWebGL) {
|
||||||
|
// Monkeypatch the Spine setBlendMode functions, or batching is destroyed!
|
||||||
|
let setBlendMode = function (this: any, srcBlend: any, dstBlend: any) {
|
||||||
|
if (srcBlend !== this.srcBlend || dstBlend !== this.dstBlend) {
|
||||||
|
let gl = this.context.gl;
|
||||||
|
this.srcBlend = srcBlend;
|
||||||
|
this.dstBlend = dstBlend;
|
||||||
|
if (this.isDrawing) {
|
||||||
|
this.flush();
|
||||||
|
gl.blendFunc(this.srcBlend, this.dstBlend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var sceneRenderer = this.sceneRenderer;
|
||||||
|
if (!sceneRenderer) {
|
||||||
|
sceneRenderer = new SceneRenderer((this.phaserRenderer! as Phaser.Renderer.WebGL.WebGLRenderer).canvas, this.gl!, true);
|
||||||
|
sceneRenderer.batcher.setBlendMode = setBlendMode;
|
||||||
|
(sceneRenderer as any).shapes.setBlendMode = setBlendMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sceneRenderer = sceneRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
var eventEmitter = this.systems.events;
|
||||||
|
eventEmitter.once('shutdown', this.shutdown, this);
|
||||||
|
eventEmitter.once('destroy', this.destroy, this);
|
||||||
|
this.game.events.once('destroy', this.gameDestroy, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
getNumbers(count: number) {
|
onResize() {
|
||||||
let numbers = [];
|
var phaserRenderer = this.phaserRenderer;
|
||||||
for (let i = 0; i < count; i++)
|
var sceneRenderer = this.sceneRenderer;
|
||||||
numbers.push(i);
|
|
||||||
return numbers;
|
if (phaserRenderer && sceneRenderer) {
|
||||||
|
var viewportWidth = phaserRenderer.width;
|
||||||
|
var viewportHeight = phaserRenderer.height;
|
||||||
|
sceneRenderer.camera.position.x = viewportWidth / 2;
|
||||||
|
sceneRenderer.camera.position.y = viewportHeight / 2;
|
||||||
|
sceneRenderer.camera.setViewport(viewportWidth, viewportHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shutdown() {
|
||||||
|
this.systems.events.off("shutdown", this.shutdown, this);
|
||||||
|
if (this.isWebGL) {
|
||||||
|
this.game.scale.off(Phaser.Scale.Events.RESIZE, this.onResize, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
gameDestroy() {
|
||||||
|
this.pluginManager.removeGameObject(SPINE_GAME_OBJECT_TYPE, true, true);
|
||||||
|
this.pluginManager.removeGameObject(SPINE_CONTAINER_TYPE, true, true);
|
||||||
|
if (this.sceneRenderer) this.sceneRenderer.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
export * from "./require-shim"
|
export * from "./require-shim"
|
||||||
import { SpinePlugin } from "./SpinePlugin";
|
|
||||||
{
|
|
||||||
let w = window as any;
|
|
||||||
w["spine.SpinePlugin"] = SpinePlugin;
|
|
||||||
}
|
|
||||||
export * from "./SpinePlugin"
|
export * from "./SpinePlugin"
|
||||||
export * from "./SpineFile"
|
export * from "./SpineFile"
|
||||||
|
export * from "./mixins"
|
||||||
export * from "@esotericsoftware/spine-core";
|
export * from "@esotericsoftware/spine-core";
|
||||||
export * from "@esotericsoftware/spine-canvas";
|
export * from "@esotericsoftware/spine-canvas";
|
||||||
|
import { SpinePlugin } from "./SpinePlugin";
|
||||||
|
(window as any).spine = { SpinePlugin: SpinePlugin };
|
||||||
|
|||||||
90
spine-ts/spine-phaser/src/mixins.ts
Normal file
90
spine-ts/spine-phaser/src/mixins.ts
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2021-present AgogPixel
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Adapted from https://github.com/agogpixel/phaser3-ts-utils/tree/main
|
||||||
|
|
||||||
|
let components = (Phaser.GameObjects.Components as any);
|
||||||
|
export const ComputedSize = components.ComputedSize;
|
||||||
|
export const Depth = components.ComputedSize;
|
||||||
|
export const Flip = components.Flip;
|
||||||
|
export const ScrollFactor = components.ScrollFactor;
|
||||||
|
export const Transform = components.Transform;
|
||||||
|
export const Visible = components.Visible;
|
||||||
|
|
||||||
|
export interface Type<
|
||||||
|
T,
|
||||||
|
P extends any[] = any[]
|
||||||
|
> extends Function {
|
||||||
|
new(...args: P): T;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Mixin<GameObjectComponent, GameObjectConstraint extends Phaser.GameObjects.GameObject> = <
|
||||||
|
GameObjectType extends Type<GameObjectConstraint>
|
||||||
|
>(
|
||||||
|
BaseGameObject: GameObjectType
|
||||||
|
) => GameObjectType & Type<GameObjectComponent>;
|
||||||
|
|
||||||
|
export function createMixin<
|
||||||
|
GameObjectComponent,
|
||||||
|
GameObjectConstraint extends Phaser.GameObjects.GameObject = Phaser.GameObjects.GameObject
|
||||||
|
>(
|
||||||
|
...component: GameObjectComponent[]
|
||||||
|
): Mixin<GameObjectComponent, GameObjectConstraint> {
|
||||||
|
return (BaseGameObject) => {
|
||||||
|
applyMixins(BaseGameObject, component);
|
||||||
|
return BaseGameObject as any;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyMixins(derivedCtor: any, constructors: any[]) {
|
||||||
|
constructors.forEach((baseCtor) => {
|
||||||
|
Object.getOwnPropertyNames(baseCtor.prototype || baseCtor).forEach((name) => {
|
||||||
|
Object.defineProperty(
|
||||||
|
derivedCtor.prototype,
|
||||||
|
name,
|
||||||
|
Object.getOwnPropertyDescriptor(baseCtor.prototype || baseCtor, name) ||
|
||||||
|
Object.create(null)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
type ComputedSizeMixin = Mixin<Phaser.GameObjects.Components.Transform, Phaser.GameObjects.GameObject>;
|
||||||
|
export const ComputedSizeMixin: ComputedSizeMixin = createMixin<Phaser.GameObjects.Components.ComputedSize>(ComputedSize);
|
||||||
|
|
||||||
|
type DepthMixin = Mixin<Phaser.GameObjects.Components.Depth, Phaser.GameObjects.GameObject>;
|
||||||
|
export const DepthMixin: DepthMixin = createMixin<Phaser.GameObjects.Components.Depth>(Depth);
|
||||||
|
|
||||||
|
type FlipMixin = Mixin<Phaser.GameObjects.Components.Flip, Phaser.GameObjects.GameObject>;
|
||||||
|
export const FlipMixin: FlipMixin = createMixin<Phaser.GameObjects.Components.Flip>(Depth);
|
||||||
|
|
||||||
|
type ScrollFactorMixin = Mixin<Phaser.GameObjects.Components.ScrollFactor, Phaser.GameObjects.GameObject>;
|
||||||
|
export const ScrollFactorMixin: ScrollFactorMixin = createMixin<Phaser.GameObjects.Components.ScrollFactor>(Depth);
|
||||||
|
|
||||||
|
type TransformMixin = Mixin<Phaser.GameObjects.Components.Transform, Phaser.GameObjects.GameObject>;
|
||||||
|
export const TransformMixin: TransformMixin = createMixin<Phaser.GameObjects.Components.Transform>(Transform);
|
||||||
|
|
||||||
|
type VisibleMixin = Mixin<Phaser.GameObjects.Components.Visible, Phaser.GameObjects.GameObject>;
|
||||||
|
export const VisibleMixin: VisibleMixin = createMixin<Phaser.GameObjects.Components.Visible>(Depth);
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user