mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-21 01:36:02 +08:00
[ts][pixi] clipping + alpha for pixi objects added to slots
This commit is contained in:
parent
4cdee3130b
commit
61e9be2dcc
@ -489,6 +489,7 @@ rm "$ROOT/spine-ts/spine-pixi/example/assets/"*
|
|||||||
cp -f ../raptor/export/raptor-pro.json "$ROOT/spine-ts/spine-pixi/example/assets/"
|
cp -f ../raptor/export/raptor-pro.json "$ROOT/spine-ts/spine-pixi/example/assets/"
|
||||||
cp -f ../raptor/export/raptor.atlas "$ROOT/spine-ts/spine-pixi/example/assets/"
|
cp -f ../raptor/export/raptor.atlas "$ROOT/spine-ts/spine-pixi/example/assets/"
|
||||||
cp -f ../raptor/export/raptor.png "$ROOT/spine-ts/spine-pixi/example/assets/"
|
cp -f ../raptor/export/raptor.png "$ROOT/spine-ts/spine-pixi/example/assets/"
|
||||||
|
cp -f ../raptor/images/raptor-jaw-tooth.png "$ROOT/spine-ts/spine-pixi/example/assets/"
|
||||||
|
|
||||||
cp -f ../spineboy/export/spineboy-pro.json "$ROOT/spine-ts/spine-pixi/example/assets/"
|
cp -f ../spineboy/export/spineboy-pro.json "$ROOT/spine-ts/spine-pixi/example/assets/"
|
||||||
cp -f ../spineboy/export/spineboy-pro.skel "$ROOT/spine-ts/spine-pixi/example/assets/"
|
cp -f ../spineboy/export/spineboy-pro.skel "$ROOT/spine-ts/spine-pixi/example/assets/"
|
||||||
|
|||||||
BIN
spine-ts/spine-pixi/example/assets/raptor-jaw-tooth.png
Normal file
BIN
spine-ts/spine-pixi/example/assets/raptor-jaw-tooth.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.0 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.4 KiB |
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
// Create the spine display object
|
// Create the spine display object
|
||||||
const spineboy = spine.Spine.from("spineboyData", "spineboyAtlas", {
|
const spineboy = spine.Spine.from("spineboyData", "spineboyAtlas", {
|
||||||
scale: 0.5,
|
scale: 0.25,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set the default mix time to use when transitioning
|
// Set the default mix time to use when transitioning
|
||||||
@ -46,79 +46,96 @@
|
|||||||
// Add the display object to the stage.
|
// Add the display object to the stage.
|
||||||
app.stage.addChild(spineboy);
|
app.stage.addChild(spineboy);
|
||||||
|
|
||||||
const logo1 = PIXI.Sprite.from('assets/spine_logo.png');
|
const tooth1 = PIXI.Sprite.from('assets/raptor-jaw-tooth.png');
|
||||||
const logo2 = PIXI.Sprite.from('assets/spine_logo.png');
|
const tooth2 = PIXI.Sprite.from('assets/raptor-jaw-tooth.png');
|
||||||
const logo3 = PIXI.Sprite.from('assets/spine_logo.png');
|
const text = new PIXI.Text('Text GUN');
|
||||||
const logo4 = PIXI.Sprite.from('assets/spine_logo.png');
|
|
||||||
const text = new PIXI.Text('Spine Text');
|
|
||||||
|
|
||||||
// putting logo1 on top of the gun
|
const toothContainer = new PIXI.Container();
|
||||||
spineboy.addSlotObject("gun", logo1);
|
toothContainer.addChild(tooth1);
|
||||||
|
toothContainer.name = "tooth";
|
||||||
|
text.name = "text";
|
||||||
|
|
||||||
// putting logo2 on top of the hand using slot directly and remove the attachment hand
|
// putting logo2 on top of the hand using slot directly and remove the attachment hand
|
||||||
let frontFist;
|
let frontFist;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
frontFist = spineboy.skeleton.findSlot("front-fist");
|
frontFist = spineboy.skeleton.findSlot("front-foot");
|
||||||
spineboy.addSlotObject(frontFist, logo2);
|
tooth1.x = -10;
|
||||||
|
tooth1.y = -70;
|
||||||
|
spineboy.addSlotObject(frontFist, toothContainer);
|
||||||
frontFist.setAttachment(null);
|
frontFist.setAttachment(null);
|
||||||
}, 2000)
|
}, 1000);
|
||||||
|
|
||||||
// scaling the bone, will scale the pixi object too
|
// scaling the bone, will scale the pixi object too
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
frontFist.bone.scaleX = .5
|
frontFist.bone.scaleX = .5;
|
||||||
frontFist.bone.scaleY = .5
|
frontFist.bone.scaleY = .5;
|
||||||
}, 3000)
|
}, 2000);
|
||||||
|
|
||||||
// adding a pixi text in a slot using slot index
|
// adding a pixi text in a slot using slot index
|
||||||
let mouth;
|
let mouth;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
mouth = spineboy.skeleton.findSlot("mouth");
|
spineboy.addSlotObject("gun", text);
|
||||||
spineboy.addSlotObject(mouth, text);
|
}, 4000);
|
||||||
}, 4000)
|
|
||||||
|
|
||||||
// adding one display object to an already "occupied" slot will remove the old one,
|
// adding one pixi object to an already "occupied" slot will remove the old one,
|
||||||
// and move the given one to the slot
|
// and move the given one to the slot
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
spineboy.addSlotObject(mouth, logo1);
|
spineboy.addSlotObject("gun", toothContainer);
|
||||||
}, 5000)
|
}, 5000);
|
||||||
|
|
||||||
// adding multiple DisplayObjects to a slot using a Container to control their offset, size, ...
|
// adding multiple DisplayObjects to a slot using a Container to control their offset, size, ...
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const container = new PIXI.Container();
|
toothContainer.addChild(tooth2);
|
||||||
container.addChild(logo3, logo4);
|
tooth2.x = 30;
|
||||||
logo3.y = 20;
|
tooth2.y = -70;
|
||||||
logo3.scale.set(.5);
|
tooth2.angle = 30;
|
||||||
logo4.scale.set(.5);
|
tooth2.tint = 0xFF5500;
|
||||||
logo4.tint = 0xFF5500;
|
}, 6000);
|
||||||
spineboy.addSlotObject("gun", container);
|
|
||||||
}, 6000)
|
|
||||||
|
|
||||||
// removing the container won't automatically destroy the displayObject contained, so take care of them
|
// removing the container won't automatically destroy the displayObject contained, so take care of them
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const container = new PIXI.Container();
|
|
||||||
spineboy.removeSlotObject("gun");
|
spineboy.removeSlotObject("gun");
|
||||||
logo3.destroy();
|
console.log(toothContainer.destroyed)
|
||||||
logo4.destroy();
|
console.log(tooth1.destroyed)
|
||||||
}, 7000)
|
console.log(tooth2.destroyed)
|
||||||
|
toothContainer.destroy();
|
||||||
|
tooth1.destroy();
|
||||||
|
console.log(toothContainer.destroyed)
|
||||||
|
console.log(tooth1.destroyed)
|
||||||
|
console.log(tooth2.destroyed)
|
||||||
|
}, 7000);
|
||||||
|
|
||||||
// removing a specific slot object, that is not in that slot do nothing
|
// removing a specific slot object, that is not in that slot do nothing
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const container = new PIXI.Container();
|
spineboy.addSlotObject("gun", tooth2);
|
||||||
spineboy.removeSlotObject(frontFist, text);
|
spineboy.removeSlotObject("gun", text);
|
||||||
text.destroy();
|
}, 8000);
|
||||||
}, 8000)
|
|
||||||
|
|
||||||
// removing a specific slot object
|
// removing a specific slot object
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const container = new PIXI.Container();
|
spineboy.removeSlotObject("gun", tooth2);
|
||||||
spineboy.removeSlotObject(frontFist, logo2);
|
tooth2.destroy();
|
||||||
logo2.destroy();
|
}, 9000);
|
||||||
}, 9000)
|
|
||||||
|
|
||||||
// resetting the slot with the original attachment
|
// resetting the slot with the original attachment
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
frontFist.setToSetupPose();
|
frontFist.setToSetupPose();
|
||||||
}, 10000)
|
frontFist.bone.setToSetupPose();
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
// showing an animation with clipping -> Pixi masks will be created
|
||||||
|
// for clipping attachments having slot objects
|
||||||
|
setTimeout(() => {
|
||||||
|
spineboy.state.setAnimation(0, "portal", true)
|
||||||
|
const tooth3 = PIXI.Sprite.from('assets/raptor-jaw-tooth.png');
|
||||||
|
tooth3.scale.set(2);
|
||||||
|
tooth3.x = -60;
|
||||||
|
tooth3.y = 120;
|
||||||
|
tooth3.angle = 180;
|
||||||
|
const foot1 = new PIXI.Container();
|
||||||
|
foot1.addChild(tooth3);
|
||||||
|
spineboy.addSlotObject("rear-foot", foot1);
|
||||||
|
}, 11000);
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@ -54,6 +54,7 @@ import type { IPointData } from "@pixi/core";
|
|||||||
import { Ticker } from "@pixi/core";
|
import { Ticker } from "@pixi/core";
|
||||||
import type { IDestroyOptions, DisplayObject } from "@pixi/display";
|
import type { IDestroyOptions, DisplayObject } from "@pixi/display";
|
||||||
import { Container } from "@pixi/display";
|
import { Container } from "@pixi/display";
|
||||||
|
import { Graphics } from "@pixi/graphics";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options to configure a {@link Spine} game object.
|
* Options to configure a {@link Spine} game object.
|
||||||
@ -205,6 +206,13 @@ export class Spine extends Container {
|
|||||||
this.debug = undefined;
|
this.debug = undefined;
|
||||||
this.meshesCache.clear();
|
this.meshesCache.clear();
|
||||||
this.slotsObject.clear();
|
this.slotsObject.clear();
|
||||||
|
|
||||||
|
for (let maskKey in this.clippingSlotToPixiMasks) {
|
||||||
|
const mask = this.clippingSlotToPixiMasks[maskKey];
|
||||||
|
mask.destroy();
|
||||||
|
delete this.clippingSlotToPixiMasks[maskKey];
|
||||||
|
}
|
||||||
|
|
||||||
super.destroy(options);
|
super.destroy(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +239,7 @@ export class Spine extends Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private slotsObject = new Map<Slot, DisplayObject>();
|
private slotsObject = new Map<Slot, Container>();
|
||||||
private getSlotFromRef (slotRef: number | string | Slot): Slot {
|
private getSlotFromRef (slotRef: number | string | Slot): Slot {
|
||||||
let slot: Slot | null;
|
let slot: Slot | null;
|
||||||
if (typeof slotRef === 'number') slot = this.skeleton.slots[slotRef];
|
if (typeof slotRef === 'number') slot = this.skeleton.slots[slotRef];
|
||||||
@ -243,54 +251,52 @@ export class Spine extends Container {
|
|||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Add a pixi DisplayObject as a child of the Spine object.
|
* Add a pixi Container as a child of the Spine object.
|
||||||
* The DisplayObject will be rendered coherently with the draw order of the slot.
|
* The Container will be rendered coherently with the draw order of the slot.
|
||||||
* If an attachment is active on the slot, the pixi DisplayObject will be rendered on top of it.
|
* If an attachment is active on the slot, the pixi Container will be rendered on top of it.
|
||||||
* If the DisplayObject is already attached to the given slot, nothing will happen.
|
* If the Container is already attached to the given slot, nothing will happen.
|
||||||
* If the DisplayObject is already attached to another slot, it will be removed from that slot
|
* If the Container is already attached to another slot, it will be removed from that slot
|
||||||
* before adding it to the given one.
|
* before adding it to the given one.
|
||||||
* If another DisplayObject is already attached to this slot, the old one will be removed from this
|
* If another Container is already attached to this slot, the old one will be removed from this
|
||||||
* slot before adding it to the current one.
|
* slot before adding it to the current one.
|
||||||
* @param slotRef - The slot index, or the slot name, or the Slot where the pixi object will be added to.
|
* @param slotRef - The slot index, or the slot name, or the Slot where the pixi object will be added to.
|
||||||
* @param pixiObject - The pixi DisplayObject to add.
|
* @param pixiObject - The pixi Container to add.
|
||||||
*/
|
*/
|
||||||
addSlotObject (slotRef: number | string | Slot, pixiObject: DisplayObject): void {
|
addSlotObject (slotRef: number | string | Slot, pixiObject: Container): void {
|
||||||
let slot = this.getSlotFromRef(slotRef);
|
let slot = this.getSlotFromRef(slotRef);
|
||||||
let oldPixiObject = this.slotsObject.get(slot);
|
let oldPixiObject = this.slotsObject.get(slot);
|
||||||
|
if (oldPixiObject === pixiObject) return;
|
||||||
|
|
||||||
// search if the pixiObject was already in another slotObject
|
// search if the pixiObject was already in another slotObject
|
||||||
if (!oldPixiObject) {
|
for (const [otherSlot, oldPixiObjectAnotherSlot] of this.slotsObject) {
|
||||||
for (const [slot, oldPixiObjectAnotherSlot] of this.slotsObject) {
|
if (otherSlot !== slot && oldPixiObjectAnotherSlot === pixiObject) {
|
||||||
if (oldPixiObjectAnotherSlot === pixiObject) {
|
this.removeSlotObject(otherSlot, pixiObject);
|
||||||
this.removeSlotObject(slot, pixiObject);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (oldPixiObject === pixiObject) return;
|
|
||||||
if (oldPixiObject) this.removeChild(oldPixiObject);
|
if (oldPixiObject) this.removeChild(oldPixiObject);
|
||||||
|
|
||||||
this.slotsObject.set(slot, pixiObject);
|
this.slotsObject.set(slot, pixiObject);
|
||||||
this.addChild(pixiObject);
|
this.addChild(pixiObject);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Return the DisplayObject connected to the given slot, if any.
|
* Return the Container connected to the given slot, if any.
|
||||||
* Otherwise return undefined
|
* Otherwise return undefined
|
||||||
* @param pixiObject - The slot index, or the slot name, or the Slot to get the DisplayObject from.
|
* @param pixiObject - The slot index, or the slot name, or the Slot to get the Container from.
|
||||||
* @returns a DisplayObject if any, undefined otherwise.
|
* @returns a Container if any, undefined otherwise.
|
||||||
*/
|
*/
|
||||||
getSlotObject (slotRef: number | string | Slot): DisplayObject | undefined {
|
getSlotObject (slotRef: number | string | Slot): Container | undefined {
|
||||||
return this.slotsObject.get(this.getSlotFromRef(slotRef));
|
return this.slotsObject.get(this.getSlotFromRef(slotRef));
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Remove a slot object from the given slot.
|
* Remove a slot object from the given slot.
|
||||||
* If `pixiObject` is passed and attached to the given slot, remove it from the slot.
|
* If `pixiObject` is passed and attached to the given slot, remove it from the slot.
|
||||||
* If `pixiObject` is not passed and the given slot has an attached DisplayObject, remove it from the slot.
|
* If `pixiObject` is not passed and the given slot has an attached Container, remove it from the slot.
|
||||||
* @param slotRef - The slot index, or the slot name, or the Slot where the pixi object will be remove from.
|
* @param slotRef - The slot index, or the slot name, or the Slot where the pixi object will be remove from.
|
||||||
* @param pixiObject - Optional, The pixi DisplayObject to remove.
|
* @param pixiObject - Optional, The pixi Container to remove.
|
||||||
*/
|
*/
|
||||||
removeSlotObject (slotRef: number | string | Slot, pixiObject?: DisplayObject): void {
|
removeSlotObject (slotRef: number | string | Slot, pixiObject?: Container): void {
|
||||||
let slot = this.getSlotFromRef(slotRef);
|
let slot = this.getSlotFromRef(slotRef);
|
||||||
let slotObject = this.slotsObject.get(slot);
|
let slotObject = this.slotsObject.get(slot);
|
||||||
if (!slotObject) return;
|
if (!slotObject) return;
|
||||||
@ -303,11 +309,45 @@ export class Spine extends Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private verticesCache: NumberArrayLike = Utils.newFloatArray(1024);
|
private verticesCache: NumberArrayLike = Utils.newFloatArray(1024);
|
||||||
|
private clippingSlotToPixiMasks: Record<string, Graphics> = {};
|
||||||
|
private pixiMaskCleanup (slot: Slot) {
|
||||||
|
let mask = this.clippingSlotToPixiMasks[slot.data.name];
|
||||||
|
if (mask) {
|
||||||
|
delete this.clippingSlotToPixiMasks[slot.data.name];
|
||||||
|
mask.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private updatePixiObject (pixiObject: Container, slot: Slot, zIndex: number) {
|
||||||
|
pixiObject.setTransform(slot.bone.worldX, slot.bone.worldY, slot.bone.getWorldScaleX(), slot.bone.getWorldScaleX(), slot.bone.getWorldRotationX() * MathUtils.degRad);
|
||||||
|
pixiObject.zIndex = zIndex + 1;
|
||||||
|
pixiObject.alpha = this.skeleton.color.a * slot.color.a;
|
||||||
|
}
|
||||||
|
private updateAndSetPixiMask (pixiMaskSource: PixiMaskSource | null, pixiObject: Container) {
|
||||||
|
if (Spine.clipper.isClipping() && pixiMaskSource) {
|
||||||
|
let mask = this.clippingSlotToPixiMasks[pixiMaskSource.slot.data.name] as Graphics;
|
||||||
|
if (!mask) {
|
||||||
|
mask = new Graphics();
|
||||||
|
this.clippingSlotToPixiMasks[pixiMaskSource.slot.data.name] = mask;
|
||||||
|
this.addChild(mask);
|
||||||
|
}
|
||||||
|
if (!pixiMaskSource.computed) {
|
||||||
|
pixiMaskSource.computed = true;
|
||||||
|
const clippingAttachment = pixiMaskSource.slot.attachment as ClippingAttachment;
|
||||||
|
const world = Array.from(clippingAttachment.vertices);
|
||||||
|
clippingAttachment.computeWorldVertices(pixiMaskSource.slot, 0, clippingAttachment.worldVerticesLength, world, 0, 2);
|
||||||
|
mask.clear().lineStyle(0).beginFill(0x000000).drawPolygon(world);
|
||||||
|
}
|
||||||
|
pixiObject.mask = mask;
|
||||||
|
} else if (pixiObject.mask) {
|
||||||
|
pixiObject.mask = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
private renderMeshes (): void {
|
private renderMeshes (): void {
|
||||||
this.resetMeshes();
|
this.resetMeshes();
|
||||||
|
|
||||||
let triangles: Array<number> | null = null;
|
let triangles: Array<number> | null = null;
|
||||||
let uvs: NumberArrayLike | null = null;
|
let uvs: NumberArrayLike | null = null;
|
||||||
|
let pixiMaskSource: PixiMaskSource | null = null;
|
||||||
const drawOrder = this.skeleton.drawOrder;
|
const drawOrder = this.skeleton.drawOrder;
|
||||||
|
|
||||||
for (let i = 0, n = drawOrder.length, slotObjectsCounter = 0; i < n; i++) {
|
for (let i = 0, n = drawOrder.length, slotObjectsCounter = 0; i < n; i++) {
|
||||||
@ -317,15 +357,16 @@ export class Spine extends Container {
|
|||||||
let pixiObject = this.slotsObject.get(slot);
|
let pixiObject = this.slotsObject.get(slot);
|
||||||
let zIndex = i + slotObjectsCounter;
|
let zIndex = i + slotObjectsCounter;
|
||||||
if (pixiObject) {
|
if (pixiObject) {
|
||||||
pixiObject.setTransform(slot.bone.worldX, slot.bone.worldY, slot.bone.getWorldScaleX(), slot.bone.getWorldScaleX(), slot.bone.getWorldRotationX() * MathUtils.degRad);
|
this.updatePixiObject(pixiObject, slot, zIndex + 1);
|
||||||
pixiObject.zIndex = zIndex + 1;
|
|
||||||
slotObjectsCounter++;
|
slotObjectsCounter++;
|
||||||
|
this.updateAndSetPixiMask(pixiMaskSource, pixiObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
const useDarkColor = slot.darkColor != null;
|
const useDarkColor = slot.darkColor != null;
|
||||||
const vertexSize = Spine.clipper.isClipping() ? 2 : useDarkColor ? Spine.DARK_VERTEX_SIZE : Spine.VERTEX_SIZE;
|
const vertexSize = Spine.clipper.isClipping() ? 2 : useDarkColor ? Spine.DARK_VERTEX_SIZE : Spine.VERTEX_SIZE;
|
||||||
if (!slot.bone.active) {
|
if (!slot.bone.active) {
|
||||||
Spine.clipper.clipEndWithSlot(slot);
|
Spine.clipper.clipEndWithSlot(slot);
|
||||||
|
this.pixiMaskCleanup(slot);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const attachment = slot.getAttachment();
|
const attachment = slot.getAttachment();
|
||||||
@ -353,9 +394,11 @@ export class Spine extends Container {
|
|||||||
texture = <SpineTexture>mesh.region?.texture;
|
texture = <SpineTexture>mesh.region?.texture;
|
||||||
} else if (attachment instanceof ClippingAttachment) {
|
} else if (attachment instanceof ClippingAttachment) {
|
||||||
Spine.clipper.clipStart(slot, attachment);
|
Spine.clipper.clipStart(slot, attachment);
|
||||||
|
pixiMaskSource = { slot, computed: false };
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
Spine.clipper.clipEndWithSlot(slot);
|
Spine.clipper.clipEndWithSlot(slot);
|
||||||
|
this.pixiMaskCleanup(slot);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (texture != null) {
|
if (texture != null) {
|
||||||
@ -423,6 +466,7 @@ export class Spine extends Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Spine.clipper.clipEndWithSlot(slot);
|
Spine.clipper.clipEndWithSlot(slot);
|
||||||
|
this.pixiMaskCleanup(slot);
|
||||||
}
|
}
|
||||||
Spine.clipper.clipEnd();
|
Spine.clipper.clipEnd();
|
||||||
}
|
}
|
||||||
@ -542,6 +586,11 @@ export class Spine extends Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PixiMaskSource = {
|
||||||
|
slot: Slot,
|
||||||
|
computed: boolean, // prevent to reculaculate vertices for a mask clipping multiple pixi objects
|
||||||
|
}
|
||||||
|
|
||||||
Skeleton.yDown = true;
|
Skeleton.yDown = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user