UNPKG

dragonbones-runtime

Version:

the tools to build dragonbones file for diffrent framework

1,297 lines (1,200 loc) 53.7 kB
/** * The MIT License (MIT) * * Copyright (c) 2012-2017 DragonBones team and other contributors * * 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. */ namespace dragonBones { /** * - The slot attached to the armature, controls the display status and properties of the display object. * A bone can contain multiple slots. * A slot can contain multiple display objects, displaying only one of the display objects at a time, * but you can toggle the display object into frame animation while the animation is playing. * The display object can be a normal texture, or it can be a display of a child armature, a grid display object, * and a custom other display object. * @see dragonBones.Armature * @see dragonBones.Bone * @see dragonBones.SlotData * @version DragonBones 3.0 * @language en_US */ /** * - 插槽附着在骨骼上,控制显示对象的显示状态和属性。 * 一个骨骼上可以包含多个插槽。 * 一个插槽中可以包含多个显示对象,同一时间只能显示其中的一个显示对象,但可以在动画播放的过程中切换显示对象实现帧动画。 * 显示对象可以是普通的图片纹理,也可以是子骨架的显示容器,网格显示对象,还可以是自定义的其他显示对象。 * @see dragonBones.Armature * @see dragonBones.Bone * @see dragonBones.SlotData * @version DragonBones 3.0 * @language zh_CN */ export abstract class Slot extends TransformObject { /** * - Displays the animated state or mixed group name controlled by the object, set to null to be controlled by all animation states. * @default null * @see dragonBones.AnimationState#displayControl * @see dragonBones.AnimationState#name * @see dragonBones.AnimationState#group * @version DragonBones 4.5 * @language en_US */ /** * - 显示对象受到控制的动画状态或混合组名称,设置为 null 则表示受所有的动画状态控制。 * @default null * @see dragonBones.AnimationState#displayControl * @see dragonBones.AnimationState#name * @see dragonBones.AnimationState#group * @version DragonBones 4.5 * @language zh_CN */ public displayController: string | null; /** * @private */ protected _displayDirty: boolean; /** * @private */ protected _zOrderDirty: boolean; /** * @private */ protected _visibleDirty: boolean; /** * @private */ protected _blendModeDirty: boolean; /** * @internal * @private */ public _colorDirty: boolean; /** * @internal * @private */ public _meshDirty: boolean; /** * @private */ protected _transformDirty: boolean; /** * @private */ protected _visible: boolean; /** * @private */ protected _blendMode: BlendMode; /** * @private */ protected _displayIndex: number; /** * @private */ protected _animationDisplayIndex: number; /** * @internal * @private */ public _zOrder: number; /** * @private */ protected _cachedFrameIndex: number; /** * @internal * @private */ public _pivotX: number; /** * @internal * @private */ public _pivotY: number; /** * @private */ protected readonly _localMatrix: Matrix = new Matrix(); /** * @internal * @private */ public readonly _colorTransform: ColorTransform = new ColorTransform(); /** * @internal * @private */ public readonly _deformVertices: Array<number> = []; /** * @private */ public readonly _displayDatas: Array<DisplayData | null> = []; /** * @private */ protected readonly _displayList: Array<any | Armature> = []; /** * @private */ protected readonly _meshBones: Array<Bone | null> = []; /** * @private */ protected readonly _meshSlots: Array<Slot | null> = []; /** * @internal * @private */ public _slotData: SlotData; /** * @private */ protected _rawDisplayDatas: Array<DisplayData | null> | null; /** * @private */ protected _displayData: DisplayData | null; /** * @private */ protected _textureData: TextureData | null; /** * @internal * @private */ public _meshData: MeshDisplayData | null; /** * @private */ protected _boundingBoxData: BoundingBoxData | null; /** * @private */ protected _rawDisplay: any = null; // Initial value. /** * @private */ protected _meshDisplay: any = null; // Initial value. /** * @private */ protected _display: any; /** * @private */ protected _childArmature: Armature | null; /** * @internal * @private */ public _cachedFrameIndices: Array<number> | null; /** * @inheritDoc */ protected _onClear(): void { super._onClear(); const disposeDisplayList: Array<any> = []; for (const eachDisplay of this._displayList) { if ( eachDisplay !== null && eachDisplay !== this._rawDisplay && eachDisplay !== this._meshDisplay && disposeDisplayList.indexOf(eachDisplay) < 0 ) { disposeDisplayList.push(eachDisplay); } } for (const eachDisplay of disposeDisplayList) { if (eachDisplay instanceof Armature) { eachDisplay.dispose(); } else { this._disposeDisplay(eachDisplay, false); } } if (this._meshDisplay !== null && this._meshDisplay !== this._rawDisplay) { // May be _meshDisplay and _rawDisplay is the same one. this._disposeDisplay(this._meshDisplay, false); } if (this._rawDisplay !== null) { this._disposeDisplay(this._rawDisplay, false); } this.displayController = null; this._displayDirty = false; this._zOrderDirty = false; this._blendModeDirty = false; this._colorDirty = false; this._meshDirty = false; this._transformDirty = false; this._visible = true; this._blendMode = BlendMode.Normal; this._displayIndex = -1; this._animationDisplayIndex = -1; this._zOrder = 0; this._cachedFrameIndex = -1; this._pivotX = 0.0; this._pivotY = 0.0; this._localMatrix.identity(); this._colorTransform.identity(); this._deformVertices.length = 0; this._displayList.length = 0; this._displayDatas.length = 0; this._meshBones.length = 0; this._meshSlots.length = 0; this._slotData = null as any; // this._rawDisplayDatas = null; this._displayData = null; this._textureData = null; this._meshData = null; this._boundingBoxData = null; this._rawDisplay = null; this._meshDisplay = null; this._display = null; this._childArmature = null; this._cachedFrameIndices = null; } /** * @private */ protected abstract _initDisplay(value: any, isRetain: boolean): void; /** * @private */ protected abstract _disposeDisplay(value: any, isRelease: boolean): void; /** * @private */ protected abstract _onUpdateDisplay(): void; /** * @private */ protected abstract _addDisplay(): void; /** * @private */ protected abstract _replaceDisplay(value: any): void; /** * @private */ protected abstract _removeDisplay(): void; /** * @private */ protected abstract _updateZOrder(): void; /** * @private */ public abstract _updateVisible(): void; /** * @private */ protected abstract _updateBlendMode(): void; /** * @private */ protected abstract _updateColor(): void; /** * @private */ protected abstract _updateFrame(): void; /** * @private */ protected abstract _updateMesh(): void; /** * @internal * @private */ public abstract _updateGlueMesh(): void; /** * @private */ protected abstract _updateTransform(): void; /** * @private */ protected abstract _identityTransform(): void; /** * @private */ protected _isMeshBonesUpdate(): boolean { for (const bone of this._meshBones) { if (bone !== null && bone._childrenTransformDirty) { return true; } } return false; } /** * Support default skin data. * @private */ protected _getDefaultRawDisplayData(displayIndex: number): DisplayData | null { const defaultSkin = this._armature._armatureData.defaultSkin; if (defaultSkin !== null) { const defaultRawDisplayDatas = defaultSkin.getDisplays(this._slotData.name); if (defaultRawDisplayDatas !== null) { return displayIndex < defaultRawDisplayDatas.length ? defaultRawDisplayDatas[displayIndex] : null; } } return null; } /** * @private */ protected _updateDisplayData(): void { const prevDisplayData = this._displayData; const prevTextureData = this._textureData; const prevMeshData = this._meshData; let rawDisplayData: DisplayData | null = null; if (this._displayIndex >= 0) { if (this._rawDisplayDatas !== null) { rawDisplayData = this._displayIndex < this._rawDisplayDatas.length ? this._rawDisplayDatas[this._displayIndex] : null; } if (rawDisplayData === null) { rawDisplayData = this._getDefaultRawDisplayData(this._displayIndex); } if (this._displayIndex < this._displayDatas.length) { this._displayData = this._displayDatas[this._displayIndex]; } } else { rawDisplayData = null; this._displayData = null; } // Update texture and mesh data. if (this._displayData !== null) { if (this._displayData.type === DisplayType.Image || this._displayData.type === DisplayType.Mesh) { if (this._displayData.type === DisplayType.Mesh) { this._textureData = (this._displayData as MeshDisplayData).texture; this._meshData = this._displayData as MeshDisplayData; } else if (rawDisplayData !== null && rawDisplayData.type === DisplayType.Mesh) { this._textureData = (this._displayData as MeshDisplayData).texture; this._meshData = rawDisplayData as MeshDisplayData; } else { this._textureData = (this._displayData as ImageDisplayData).texture; this._meshData = null; } } else { this._textureData = null; this._meshData = null; } } else { this._textureData = null; this._meshData = null; } // Update bounding box data. if (this._displayData !== null && this._displayData.type === DisplayType.BoundingBox) { this._boundingBoxData = (this._displayData as BoundingBoxDisplayData).boundingBox; } else if (rawDisplayData !== null && rawDisplayData.type === DisplayType.BoundingBox) { this._boundingBoxData = (rawDisplayData as BoundingBoxDisplayData).boundingBox; } else { this._boundingBoxData = null; } if (this._displayData !== prevDisplayData || this._textureData !== prevTextureData || this._meshData !== prevMeshData) { // Update pivot offset. if (this._meshData !== null) { this._pivotX = 0.0; this._pivotY = 0.0; } else if (this._textureData !== null) { const imageDisplayData = this._displayData as ImageDisplayData; const scale = this._textureData.parent.scale * this._armature._armatureData.scale; const frame = this._textureData.frame; this._pivotX = imageDisplayData.pivot.x; this._pivotY = imageDisplayData.pivot.y; const rect = frame !== null ? frame : this._textureData.region; let width = rect.width; let height = rect.height; if (this._textureData.rotated && frame === null) { width = rect.height; height = rect.width; } this._pivotX *= width * scale; this._pivotY *= height * scale; if (frame !== null) { this._pivotX += frame.x * scale; this._pivotY += frame.y * scale; } } else { this._pivotX = 0.0; this._pivotY = 0.0; } // Update replace pivot. if (this._displayData !== null && rawDisplayData !== null && this._displayData !== rawDisplayData && this._meshData === null) { rawDisplayData.transform.toMatrix(Slot._helpMatrix); Slot._helpMatrix.invert(); Slot._helpMatrix.transformPoint(0.0, 0.0, Slot._helpPoint); this._pivotX -= Slot._helpPoint.x; this._pivotY -= Slot._helpPoint.y; this._displayData.transform.toMatrix(Slot._helpMatrix); Slot._helpMatrix.invert(); Slot._helpMatrix.transformPoint(0.0, 0.0, Slot._helpPoint); this._pivotX += Slot._helpPoint.x; this._pivotY += Slot._helpPoint.y; } // Update original transform. if (rawDisplayData !== null) { // Compatible. this.origin = rawDisplayData.transform; } else if (this._displayData !== null) { // Compatible. this.origin = this._displayData.transform; } else { this.origin = null; } // Update mesh bones and deform vertices. if (this._meshData !== prevMeshData) { if (this._meshData !== null) { // && this._meshData === this._displayData // Update skined mesh. if (this._meshData.weight !== null) { this._deformVertices.length = this._meshData.weight.count * 2; this._meshBones.length = this._meshData.weight.bones.length; for (let i = 0, l = this._meshBones.length; i < l; ++i) { this._meshBones[i] = this._armature.getBone(this._meshData.weight.bones[i].name); } } else { const vertexCount = this._meshData.parent.parent.parent.intArray[this._meshData.offset + BinaryOffset.MeshVertexCount]; this._deformVertices.length = vertexCount * 2; this._meshBones.length = 0; } // Update glue mesh. const armatureGlueSlots = this._armature._glueSlots; if (this._meshData.glue !== null) { this._meshSlots.length = this._meshData.glue.meshes.length; for (let i = 0, l = this._meshSlots.length; i < l; ++i) { const mesh = this._meshData.glue.meshes[i]; if (mesh !== null) { let flag = false; for (const slot of this._armature.getSlots()) { for (const displayData of slot._displayDatas) { if ( displayData !== null && displayData.type === DisplayType.Mesh && (displayData as MeshDisplayData).offset === mesh.offset ) { flag = true; this._meshSlots[i] = slot; break; } } if (flag) { break; } } if (!flag) { this._meshSlots[i] = null; } } else { this._meshSlots[i] = null; } } if (armatureGlueSlots.indexOf(this) < 0) { armatureGlueSlots.push(this); } } else { const index = armatureGlueSlots.indexOf(this); if (index >= 0) { armatureGlueSlots.slice(index, 1); } } // Clear deform to zero. for (let i = 0, l = this._deformVertices.length; i < l; ++i) { this._deformVertices[i] = 0.0; } this._meshDirty = true; } else { this._deformVertices.length = 0; this._meshBones.length = 0; this._meshSlots.length = 0; } } else if (this._meshData !== null && this._textureData !== prevTextureData) { // Update mesh after update frame. this._meshDirty = true; } this._displayDirty = true; this._transformDirty = true; } } /** * @private */ protected _updateDisplay(): void { const prevDisplay = this._display !== null ? this._display : this._rawDisplay; const prevChildArmature = this._childArmature; // Update display and child armature. if (this._displayIndex >= 0 && this._displayIndex < this._displayList.length) { this._display = this._displayList[this._displayIndex]; if (this._display !== null && this._display instanceof Armature) { this._childArmature = this._display as Armature; this._display = this._childArmature.display; } else { this._childArmature = null; } } else { this._display = null; this._childArmature = null; } // Update display. const currentDisplay = this._display !== null ? this._display : this._rawDisplay; if (currentDisplay !== prevDisplay) { this._onUpdateDisplay(); this._replaceDisplay(prevDisplay); this._visibleDirty = true; this._blendModeDirty = true; this._colorDirty = true; } // Update frame. if (currentDisplay === this._rawDisplay || currentDisplay === this._meshDisplay) { this._updateFrame(); } // Update child armature. if (this._childArmature !== prevChildArmature) { if (prevChildArmature !== null) { prevChildArmature._parent = null; // Update child armature parent. prevChildArmature.clock = null; if (prevChildArmature.inheritAnimation) { prevChildArmature.animation.reset(); } } if (this._childArmature !== null) { this._childArmature._parent = this; // Update child armature parent. this._childArmature.clock = this._armature.clock; if (this._childArmature.inheritAnimation) { // Set child armature cache frameRate. if (this._childArmature.cacheFrameRate === 0) { const cacheFrameRate = this._armature.cacheFrameRate; if (cacheFrameRate !== 0) { this._childArmature.cacheFrameRate = cacheFrameRate; } } // Child armature action. let actions: Array<ActionData> | null = null; if (this._displayData !== null && this._displayData.type === DisplayType.Armature) { actions = (this._displayData as ArmatureDisplayData).actions; } else if (this._displayIndex >= 0 && this._rawDisplayDatas !== null) { let rawDisplayData = this._displayIndex < this._rawDisplayDatas.length ? this._rawDisplayDatas[this._displayIndex] : null; if (rawDisplayData === null) { rawDisplayData = this._getDefaultRawDisplayData(this._displayIndex); } if (rawDisplayData !== null && rawDisplayData.type === DisplayType.Armature) { actions = (rawDisplayData as ArmatureDisplayData).actions; } } if (actions !== null && actions.length > 0) { for (const action of actions) { this._childArmature._bufferAction(action, false); // Make sure default action at the beginning. } } else { this._childArmature.animation.play(); } } } } } /** * @private */ protected _updateGlobalTransformMatrix(isCache: boolean): void { const parentMatrix = this._parent._boneData.type === BoneType.Bone ? this._parent.globalTransformMatrix : (this._parent as Surface)._getGlobalTransformMatrix(this.global.x, this.global.y); this.globalTransformMatrix.copyFrom(this._localMatrix); this.globalTransformMatrix.concat(parentMatrix); if (isCache) { this.global.fromMatrix(this.globalTransformMatrix); } else { this._globalDirty = true; } } /** * @inheritDoc */ public _setArmature(value: Armature | null): void { if (this._armature === value) { return; } if (this._armature !== null) { this._armature._removeSlotFromSlotList(this); } this._armature = value as any; // this._onUpdateDisplay(); if (this._armature !== null) { this._armature._addSlotToSlotList(this); this._addDisplay(); } else { this._removeDisplay(); } } /** * @internal * @private */ public _setDisplayIndex(value: number, isAnimation: boolean = false): boolean { if (isAnimation) { if (this._animationDisplayIndex === value) { return false; } this._animationDisplayIndex = value; } if (this._displayIndex === value) { return false; } this._displayIndex = value; this._displayDirty = true; this._updateDisplayData(); return this._displayDirty; } /** * @internal * @private */ public _setZorder(value: number): boolean { if (this._zOrder === value) { //return false; } this._zOrder = value; this._zOrderDirty = true; return this._zOrderDirty; } /** * @internal * @private */ public _setColor(value: ColorTransform): boolean { this._colorTransform.copyFrom(value); this._colorDirty = true; return this._colorDirty; } /** * @internal * @private */ public _setDisplayList(value: Array<any> | null): boolean { if (value !== null && value.length > 0) { if (this._displayList.length !== value.length) { this._displayList.length = value.length; } for (let i = 0, l = value.length; i < l; ++i) { // Retain input render displays. const eachDisplay = value[i]; if ( eachDisplay !== null && eachDisplay !== this._rawDisplay && eachDisplay !== this._meshDisplay && !(eachDisplay instanceof Armature) && this._displayList.indexOf(eachDisplay) < 0 ) { this._initDisplay(eachDisplay, true); } this._displayList[i] = eachDisplay; } } else if (this._displayList.length > 0) { this._displayList.length = 0; } if (this._displayIndex >= 0 && this._displayIndex < this._displayList.length) { this._displayDirty = this._display !== this._displayList[this._displayIndex]; } else { this._displayDirty = this._display !== null; } this._updateDisplayData(); return this._displayDirty; } /** * @internal * @private */ public init(slotData: SlotData, displayDatas: Array<DisplayData | null> | null, rawDisplay: any, meshDisplay: any): void { if (this._slotData !== null) { return; } this._slotData = slotData; // this._visibleDirty = true; this._blendModeDirty = true; this._colorDirty = true; this._blendMode = this._slotData.blendMode; this._zOrder = this._slotData.zOrder; this._colorTransform.copyFrom(this._slotData.color); this._rawDisplay = rawDisplay; this._meshDisplay = meshDisplay; // this.rawDisplayDatas = displayDatas; // // this._initDisplay(this._rawDisplay, false); if (this._rawDisplay !== this._meshDisplay) { this._initDisplay(this._meshDisplay, false); } } /** * @internal * @private */ public update(cacheFrameIndex: number): void { if (this._displayDirty) { this._displayDirty = false; this._updateDisplay(); // TODO remove slot offset. if (this._transformDirty) { // Update local matrix. (Only updated when both display and transform are dirty.) if (this.origin !== null) { this.global.copyFrom(this.origin).add(this.offset).toMatrix(this._localMatrix); } else { this.global.copyFrom(this.offset).toMatrix(this._localMatrix); } } } if (this._zOrderDirty) { this._zOrderDirty = false; this._updateZOrder(); } if (cacheFrameIndex >= 0 && this._cachedFrameIndices !== null) { const cachedFrameIndex = this._cachedFrameIndices[cacheFrameIndex]; if (cachedFrameIndex >= 0 && this._cachedFrameIndex === cachedFrameIndex) { // Same cache. this._transformDirty = false; } else if (cachedFrameIndex >= 0) { // Has been Cached. this._transformDirty = true; this._cachedFrameIndex = cachedFrameIndex; } else if (this._transformDirty || this._parent._childrenTransformDirty) { // Dirty. this._transformDirty = true; this._cachedFrameIndex = -1; } else if (this._cachedFrameIndex >= 0) { // Same cache, but not set index yet. this._transformDirty = false; this._cachedFrameIndices[cacheFrameIndex] = this._cachedFrameIndex; } else { // Dirty. this._transformDirty = true; this._cachedFrameIndex = -1; } } else if (this._transformDirty || this._parent._childrenTransformDirty) { // Dirty. cacheFrameIndex = -1; this._transformDirty = true; this._cachedFrameIndex = -1; } if (this._display === null) { return; } if (this._visibleDirty) { this._visibleDirty = false; this._updateVisible(); } if (this._blendModeDirty) { this._blendModeDirty = false; this._updateBlendMode(); } if (this._colorDirty) { this._colorDirty = false; this._updateColor(); } if (this._meshData !== null && this._display === this._meshDisplay) { const isSkinned = this._meshData.weight !== null; const isSurface = this._parent._boneData.type !== BoneType.Bone; const isGule = this._meshData.glue !== null; if ( this._meshDirty || (isSkinned && this._isMeshBonesUpdate()) || (isSurface && this._parent._childrenTransformDirty) || (isGule && this._parent._childrenTransformDirty) // TODO ) { this._meshDirty = false; this._updateMesh(); } if (isSkinned || isSurface || isGule) { return; } } if (this._transformDirty) { this._transformDirty = false; if (this._cachedFrameIndex < 0) { const isCache = cacheFrameIndex >= 0; this._updateGlobalTransformMatrix(isCache); if (isCache && this._cachedFrameIndices !== null) { this._cachedFrameIndex = this._cachedFrameIndices[cacheFrameIndex] = this._armature._armatureData.setCacheFrame(this.globalTransformMatrix, this.global); } } else { this._armature._armatureData.getCacheFrame(this.globalTransformMatrix, this.global, this._cachedFrameIndex); } this._updateTransform(); } } /** * @private */ public updateTransformAndMatrix(): void { if (this._transformDirty) { this._transformDirty = false; this._updateGlobalTransformMatrix(false); } } /** * @private */ public replaceDisplayData(value: DisplayData | null, displayIndex: number = -1): void { if (displayIndex < 0) { if (this._displayIndex < 0) { displayIndex = 0; } else { displayIndex = this._displayIndex; } } if (this._displayDatas.length <= displayIndex) { this._displayDatas.length = displayIndex + 1; for (let i = 0, l = this._displayDatas.length; i < l; ++i) { // Clean undefined. if (!this._displayDatas[i]) { this._displayDatas[i] = null; } } } this._displayDatas[displayIndex] = value; } /** * - Check whether a specific point is inside a custom bounding box in the slot. * The coordinate system of the point is the inner coordinate system of the armature. * Custom bounding boxes need to be customized in Dragonbones Pro. * @param x - The horizontal coordinate of the point. * @param y - The vertical coordinate of the point. * @version DragonBones 5.0 * @language en_US */ /** * - 检查特定点是否在插槽的自定义边界框内。 * 点的坐标系为骨架内坐标系。 * 自定义边界框需要在 DragonBones Pro 中自定义。 * @param x - 点的水平坐标。 * @param y - 点的垂直坐标。 * @version DragonBones 5.0 * @language zh_CN */ public containsPoint(x: number, y: number): boolean { if (this._boundingBoxData === null) { return false; } this.updateTransformAndMatrix(); Slot._helpMatrix.copyFrom(this.globalTransformMatrix); Slot._helpMatrix.invert(); Slot._helpMatrix.transformPoint(x, y, Slot._helpPoint); return this._boundingBoxData.containsPoint(Slot._helpPoint.x, Slot._helpPoint.y); } /** * - Check whether a specific segment intersects a custom bounding box for the slot. * The coordinate system of the segment and intersection is the inner coordinate system of the armature. * Custom bounding boxes need to be customized in Dragonbones Pro. * @param xA - The horizontal coordinate of the beginning of the segment. * @param yA - The vertical coordinate of the beginning of the segment. * @param xB - The horizontal coordinate of the end point of the segment. * @param yB - The vertical coordinate of the end point of the segment. * @param intersectionPointA - The first intersection at which a line segment intersects the bounding box from the beginning to the end. (If not set, the intersection point will not calculated) * @param intersectionPointB - The first intersection at which a line segment intersects the bounding box from the end to the beginning. (If not set, the intersection point will not calculated) * @param normalRadians - The normal radians of the tangent of the intersection boundary box. [x: Normal radian of the first intersection tangent, y: Normal radian of the second intersection tangent] (If not set, the normal will not calculated) * @returns Intersection situation. [1: Disjoint and segments within the bounding box, 0: Disjoint, 1: Intersecting and having a nodal point and ending in the bounding box, 2: Intersecting and having a nodal point and starting at the bounding box, 3: Intersecting and having two intersections, N: Intersecting and having N intersections] * @version DragonBones 5.0 * @language en_US */ /** * - 检查特定线段是否与插槽的自定义边界框相交。 * 线段和交点的坐标系均为骨架内坐标系。 * 自定义边界框需要在 DragonBones Pro 中自定义。 * @param xA - 线段起点的水平坐标。 * @param yA - 线段起点的垂直坐标。 * @param xB - 线段终点的水平坐标。 * @param yB - 线段终点的垂直坐标。 * @param intersectionPointA - 线段从起点到终点与边界框相交的第一个交点。 (如果未设置,则不计算交点) * @param intersectionPointB - 线段从终点到起点与边界框相交的第一个交点。 (如果未设置,则不计算交点) * @param normalRadians - 交点边界框切线的法线弧度。 [x: 第一个交点切线的法线弧度, y: 第二个交点切线的法线弧度] (如果未设置,则不计算法线) * @returns 相交的情况。 [-1: 不相交且线段在包围盒内, 0: 不相交, 1: 相交且有一个交点且终点在包围盒内, 2: 相交且有一个交点且起点在包围盒内, 3: 相交且有两个交点, N: 相交且有 N 个交点] * @version DragonBones 5.0 * @language zh_CN */ public intersectsSegment( xA: number, yA: number, xB: number, yB: number, intersectionPointA: { x: number, y: number } | null = null, intersectionPointB: { x: number, y: number } | null = null, normalRadians: { x: number, y: number } | null = null ): number { if (this._boundingBoxData === null) { return 0; } this.updateTransformAndMatrix(); Slot._helpMatrix.copyFrom(this.globalTransformMatrix); Slot._helpMatrix.invert(); Slot._helpMatrix.transformPoint(xA, yA, Slot._helpPoint); xA = Slot._helpPoint.x; yA = Slot._helpPoint.y; Slot._helpMatrix.transformPoint(xB, yB, Slot._helpPoint); xB = Slot._helpPoint.x; yB = Slot._helpPoint.y; const intersectionCount = this._boundingBoxData.intersectsSegment(xA, yA, xB, yB, intersectionPointA, intersectionPointB, normalRadians); if (intersectionCount > 0) { if (intersectionCount === 1 || intersectionCount === 2) { if (intersectionPointA !== null) { this.globalTransformMatrix.transformPoint(intersectionPointA.x, intersectionPointA.y, intersectionPointA); if (intersectionPointB !== null) { intersectionPointB.x = intersectionPointA.x; intersectionPointB.y = intersectionPointA.y; } } else if (intersectionPointB !== null) { this.globalTransformMatrix.transformPoint(intersectionPointB.x, intersectionPointB.y, intersectionPointB); } } else { if (intersectionPointA !== null) { this.globalTransformMatrix.transformPoint(intersectionPointA.x, intersectionPointA.y, intersectionPointA); } if (intersectionPointB !== null) { this.globalTransformMatrix.transformPoint(intersectionPointB.x, intersectionPointB.y, intersectionPointB); } } if (normalRadians !== null) { this.globalTransformMatrix.transformPoint(Math.cos(normalRadians.x), Math.sin(normalRadians.x), Slot._helpPoint, true); normalRadians.x = Math.atan2(Slot._helpPoint.y, Slot._helpPoint.x); this.globalTransformMatrix.transformPoint(Math.cos(normalRadians.y), Math.sin(normalRadians.y), Slot._helpPoint, true); normalRadians.y = Math.atan2(Slot._helpPoint.y, Slot._helpPoint.x); } } return intersectionCount; } /** * - Forces the slot to update the state of the display object in the next frame. * @version DragonBones 4.5 * @language en_US */ /** * - 强制插槽在下一帧更新显示对象的状态。 * @version DragonBones 4.5 * @language zh_CN */ public invalidUpdate(): void { this._displayDirty = true; this._transformDirty = true; } /** * - The visible of slot's display object. * @default true * @version DragonBones 5.6 * @language en_US */ /** * - 插槽的显示对象的可见。 * @default true * @version DragonBones 5.6 * @language zh_CN */ public get visible(): boolean { return this._visible; } public set visible(value: boolean) { if (this._visible === value) { return; } this._visible = value; this._updateVisible(); } /** * - The index of the display object displayed in the display list. * @example * <pre> * let slot = armature.getSlot("weapon"); * slot.displayIndex = 3; * slot.displayController = "none"; * </pre> * @version DragonBones 4.5 * @language en_US */ /** * - 此时显示的显示对象在显示列表中的索引。 * @example * <pre> * let slot = armature.getSlot("weapon"); * slot.displayIndex = 3; * slot.displayController = "none"; * </pre> * @version DragonBones 4.5 * @language zh_CN */ public get displayIndex(): number { return this._displayIndex; } public set displayIndex(value: number) { if (this._setDisplayIndex(value)) { this.update(-1); } } /** * - The slot name. * @see dragonBones.SlotData#name * @version DragonBones 3.0 * @language en_US */ /** * - 插槽名称。 * @see dragonBones.SlotData#name * @version DragonBones 3.0 * @language zh_CN */ public get name(): string { return this._slotData.name; } /** * - Contains a display list of display objects or child armatures. * @version DragonBones 3.0 * @language en_US */ /** * - 包含显示对象或子骨架的显示列表。 * @version DragonBones 3.0 * @language zh_CN */ public get displayList(): Array<any> { return this._displayList.concat(); } public set displayList(value: Array<any>) { const backupDisplayList = this._displayList.concat(); // Copy. const disposeDisplayList = new Array<any>(); if (this._setDisplayList(value)) { this.update(-1); } // Release replaced displays. for (const eachDisplay of backupDisplayList) { if ( eachDisplay !== null && eachDisplay !== this._rawDisplay && eachDisplay !== this._meshDisplay && this._displayList.indexOf(eachDisplay) < 0 && disposeDisplayList.indexOf(eachDisplay) < 0 ) { disposeDisplayList.push(eachDisplay); } } for (const eachDisplay of disposeDisplayList) { if (eachDisplay instanceof Armature) { (eachDisplay as Armature).dispose(); } else { this._disposeDisplay(eachDisplay, true); } } } /** * - The slot data. * @see dragonBones.SlotData * @version DragonBones 4.5 * @language en_US */ /** * - 插槽数据。 * @see dragonBones.SlotData * @version DragonBones 4.5 * @language zh_CN */ public get slotData(): SlotData { return this._slotData; } /** * @private */ public get rawDisplayDatas(): Array<DisplayData | null> | null { return this._rawDisplayDatas; } public set rawDisplayDatas(value: Array<DisplayData | null> | null) { if (this._rawDisplayDatas === value) { return; } this._displayDirty = true; this._rawDisplayDatas = value; if (this._rawDisplayDatas !== null) { this._displayDatas.length = this._rawDisplayDatas.length; for (let i = 0, l = this._displayDatas.length; i < l; ++i) { let rawDisplayData = this._rawDisplayDatas[i]; if (rawDisplayData === null) { rawDisplayData = this._getDefaultRawDisplayData(i); } this._displayDatas[i] = rawDisplayData; } } else { this._displayDatas.length = 0; } } /** * - The custom bounding box data for the slot at current time. * @version DragonBones 5.0 * @language en_US */ /** * - 插槽此时的自定义包围盒数据。 * @version DragonBones 5.0 * @language zh_CN */ public get boundingBoxData(): BoundingBoxData | null { return this._boundingBoxData; } /** * @private */ public get rawDisplay(): any { return this._rawDisplay; } /** * @private */ public get meshDisplay(): any { return this._meshDisplay; } /** * - The display object that the slot displays at this time. * @example * <pre> * let slot = armature.getSlot("text"); * slot.display = new yourEngine.TextField(); * </pre> * @version DragonBones 3.0 * @language en_US */ /** * - 插槽此时显示的显示对象。 * @example * <pre> * let slot = armature.getSlot("text"); * slot.display = new yourEngine.TextField(); * </pre> * @version DragonBones 3.0 * @language zh_CN */ public get display(): any { return this._display; } public set display(value: any) { if (this._display === value) {