UNPKG

dragonbones-runtime

Version:

the tools to build dragonbones file for diffrent framework

610 lines (561 loc) 22 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 { /** * - Bone is one of the most important logical units in the armature animation system, * and is responsible for the realization of translate, rotation, scaling in the animations. * A armature can contain multiple bones. * @see dragonBones.BoneData * @see dragonBones.Armature * @see dragonBones.Slot * @version DragonBones 3.0 * @language en_US */ /** * - 骨骼在骨骼动画体系中是最重要的逻辑单元之一,负责动画中的平移、旋转、缩放的实现。 * 一个骨架中可以包含多个骨骼。 * @see dragonBones.BoneData * @see dragonBones.Armature * @see dragonBones.Slot * @version DragonBones 3.0 * @language zh_CN */ export class Bone extends TransformObject { public static toString(): string { return "[class dragonBones.Bone]"; } /** * - The offset mode. * @see #offset * @version DragonBones 5.5 * @language en_US */ /** * - 偏移模式。 * @see #offset * @version DragonBones 5.5 * @language zh_CN */ public offsetMode: OffsetMode; /** * @internal * @private */ public readonly animationPose: Transform = new Transform(); /** * @internal * @private */ public _transformDirty: boolean; /** * @internal * @private */ public _childrenTransformDirty: boolean; protected _localDirty: boolean; /** * @internal * @private */ public _hasConstraint: boolean; private _visible: boolean; protected _cachedFrameIndex: number; /** * @internal * @private */ public readonly _blendState: BlendState = new BlendState(); /** * @internal * @private */ public _boneData: BoneData; /** * @internal * @private */ public _cachedFrameIndices: Array<number> | null; /** * @inheritDoc */ protected _onClear(): void { super._onClear(); this.offsetMode = OffsetMode.Additive; this.animationPose.identity(); this._transformDirty = false; this._childrenTransformDirty = false; this._localDirty = true; this._hasConstraint = false; this._visible = true; this._cachedFrameIndex = -1; this._blendState.clear(); this._boneData = null as any; // this._cachedFrameIndices = null; } /** * @private */ protected _updateGlobalTransformMatrix(isCache: boolean): void { const boneData = this._boneData; const parent = this._parent; const flipX = this._armature.flipX; const flipY = this._armature.flipY === DragonBones.yDown; let inherit = parent !== null; let rotation = 0.0; const global = this.global; const globalTransformMatrix = this.globalTransformMatrix; if (this.offsetMode === OffsetMode.Additive) { if (this.origin !== null) { // global.copyFrom(this.origin).add(this.offset).add(this.animationPose); global.x = this.origin.x + this.offset.x + this.animationPose.x; global.y = this.origin.y + this.offset.y + this.animationPose.y; global.skew = this.origin.skew + this.offset.skew + this.animationPose.skew; global.rotation = this.origin.rotation + this.offset.rotation + this.animationPose.rotation; global.scaleX = this.origin.scaleX * this.offset.scaleX * this.animationPose.scaleX; global.scaleY = this.origin.scaleY * this.offset.scaleY * this.animationPose.scaleY; } else { global.copyFrom(this.offset).add(this.animationPose); } } else if (this.offsetMode === OffsetMode.None) { if (this.origin !== null) { global.copyFrom(this.origin).add(this.animationPose); } else { global.copyFrom(this.animationPose); } } else { inherit = false; global.copyFrom(this.offset); } if (inherit) { const parentMatrix = parent._boneData.type === BoneType.Bone ? parent.globalTransformMatrix : (parent as Surface)._getGlobalTransformMatrix(global.x, global.y); if (boneData.inheritScale) { if (!boneData.inheritRotation) { parent.updateGlobalTransform(); if (flipX && flipY) { rotation = global.rotation - (parent.global.rotation + Math.PI); } else if (flipX) { rotation = global.rotation + parent.global.rotation + Math.PI; } else if (flipY) { rotation = global.rotation + parent.global.rotation; } else { rotation = global.rotation - parent.global.rotation; } global.rotation = rotation; } global.toMatrix(globalTransformMatrix); globalTransformMatrix.concat(parentMatrix); if (boneData.inheritTranslation) { global.x = globalTransformMatrix.tx; global.y = globalTransformMatrix.ty; } else { globalTransformMatrix.tx = global.x; globalTransformMatrix.ty = global.y; } if (isCache) { global.fromMatrix(globalTransformMatrix); } else { this._globalDirty = true; } } else { if (boneData.inheritTranslation) { const x = global.x; const y = global.y; global.x = parentMatrix.a * x + parentMatrix.c * y + parentMatrix.tx; global.y = parentMatrix.b * x + parentMatrix.d * y + parentMatrix.ty; } else { if (flipX) { global.x = -global.x; } if (flipY) { global.y = -global.y; } } if (boneData.inheritRotation) { parent.updateGlobalTransform(); if (parent.global.scaleX < 0.0) { rotation = global.rotation + parent.global.rotation + Math.PI; } else { rotation = global.rotation + parent.global.rotation; } if (parentMatrix.a * parentMatrix.d - parentMatrix.b * parentMatrix.c < 0.0) { rotation -= global.rotation * 2.0; if (flipX !== flipY || boneData.inheritReflection) { global.skew += Math.PI; } } global.rotation = rotation; } else if (flipX || flipY) { if (flipX && flipY) { rotation = global.rotation + Math.PI; } else { if (flipX) { rotation = Math.PI - global.rotation; } else { rotation = -global.rotation; } global.skew += Math.PI; } global.rotation = rotation; } global.toMatrix(globalTransformMatrix); } } else { if (flipX || flipY) { if (flipX) { global.x = -global.x; } if (flipY) { global.y = -global.y; } if (flipX && flipY) { rotation = global.rotation + Math.PI; } else { if (flipX) { rotation = Math.PI - global.rotation; } else { rotation = -global.rotation; } global.skew += Math.PI; } global.rotation = rotation; } global.toMatrix(globalTransformMatrix); } } /** * @inheritDoc */ public _setArmature(value: Armature | null): void { if (this._armature === value) { return; } let oldSlots: Array<Slot> | null = null; let oldBones: Array<Bone> | null = null; if (this._armature !== null) { oldSlots = this.getSlots(); oldBones = this.getBones(); this._armature._removeBoneFromBoneList(this); } this._armature = value as any; // if (this._armature !== null) { this._armature._addBoneToBoneList(this); } if (oldSlots !== null) { for (const slot of oldSlots) { if (slot.parent === this) { slot._setArmature(this._armature); } } } if (oldBones !== null) { for (const bone of oldBones) { if (bone.parent === this) { bone._setArmature(this._armature); } } } } /** * @internal * @private */ public init(boneData: BoneData): void { if (this._boneData !== null) { return; } this._boneData = boneData; // this.origin = this._boneData.transform; } /** * @internal * @private */ public update(cacheFrameIndex: number): void { this._blendState.dirty = false; 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._hasConstraint) { // Update constraints. for (const constraint of this._armature._constraints) { if (constraint._root === this) { constraint.update(); } } } if ( this._transformDirty || (this._parent !== null && 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._hasConstraint) { // Update constraints. for (const constraint of this._armature._constraints) { if (constraint._root === this) { constraint.update(); } } } if (this._transformDirty || (this._parent !== null && this._parent._childrenTransformDirty)) { // Dirty. cacheFrameIndex = -1; this._transformDirty = true; this._cachedFrameIndex = -1; } } if (this._transformDirty) { this._transformDirty = false; this._childrenTransformDirty = true; // if (this._cachedFrameIndex < 0) { const isCache = cacheFrameIndex >= 0; if (this._localDirty) { 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); } // } else if (this._childrenTransformDirty) { this._childrenTransformDirty = false; } this._localDirty = true; } /** * @internal * @private */ public updateByConstraint(): void { if (this._localDirty) { this._localDirty = false; if (this._transformDirty || (this._parent !== null && this._parent._childrenTransformDirty)) { this._updateGlobalTransformMatrix(true); } this._transformDirty = true; } } /** * - Forces the bone to update the transform in the next frame. * When the bone is not animated or its animation state is finished, the bone will not continue to update, * and when the skeleton must be updated for some reason, the method needs to be called explicitly. * @example * <pre> * let bone = armature.getBone("arm"); * bone.offset.scaleX = 2.0; * bone.invalidUpdate(); * </pre> * @version DragonBones 3.0 * @language en_US */ /** * - 强制骨骼在下一帧更新变换。 * 当该骨骼没有动画状态或其动画状态播放完成时,骨骼将不在继续更新,而此时由于某些原因必须更新骨骼时,则需要显式调用该方法。 * @example * <pre> * let bone = armature.getBone("arm"); * bone.offset.scaleX = 2.0; * bone.invalidUpdate(); * </pre> * @version DragonBones 3.0 * @language zh_CN */ public invalidUpdate(): void { this._transformDirty = true; } /** * - Check whether the bone contains a specific bone or slot. * @see dragonBones.Bone * @see dragonBones.Slot * @version DragonBones 3.0 * @language en_US */ /** * - 检查该骨骼是否包含特定的骨骼或插槽。 * @see dragonBones.Bone * @see dragonBones.Slot * @version DragonBones 3.0 * @language zh_CN */ public contains(value: TransformObject): boolean { if (value === this) { return false; } let ancestor: TransformObject | null = value; while (ancestor !== this && ancestor !== null) { ancestor = ancestor.parent; } return ancestor === this; } /** * - The bone data. * @version DragonBones 4.5 * @language en_US */ /** * - 骨骼数据。 * @version DragonBones 4.5 * @language zh_CN */ public get boneData(): BoneData { return this._boneData; } /** * - The visible of all slots in the bone. * @default true * @see dragonBones.Slot#visible * @version DragonBones 3.0 * @language en_US */ /** * - 此骨骼所有插槽的可见。 * @default true * @see dragonBones.Slot#visible * @version DragonBones 3.0 * @language zh_CN */ public get visible(): boolean { return this._visible; } public set visible(value: boolean) { if (this._visible === value) { return; } this._visible = value; for (const slot of this._armature.getSlots()) { if (slot._parent === this) { slot._updateVisible(); } } } /** * - The bone name. * @version DragonBones 3.0 * @language en_US */ /** * - 骨骼名称。 * @version DragonBones 3.0 * @language zh_CN */ public get name(): string { return this._boneData.name; } /** * - Deprecated, please refer to {@link dragonBones.Armature#getBones()}. * @deprecated * @language en_US */ /** * - 已废弃,请参考 {@link dragonBones.Armature#getBones()}。 * @deprecated * @language zh_CN */ public getBones(): Array<Bone> { const bones = new Array<Bone>(); for (const bone of this._armature.getBones()) { if (bone.parent === this) { bones.push(bone); } } return bones; } /** * - Deprecated, please refer to {@link dragonBones.Armature#getSlots()}. * @deprecated * @language en_US */ /** * - 已废弃,请参考 {@link dragonBones.Armature#getSlots()}。 * @deprecated * @language zh_CN */ public getSlots(): Array<Slot> { const slots = new Array<Slot>(); for (const slot of this._armature.getSlots()) { if (slot.parent === this) { slots.push(slot); } } return slots; } /** * - Deprecated, please refer to {@link dragonBones.Armature#getSlot()}. * @deprecated * @language en_US */ /** * - 已废弃,请参考 {@link dragonBones.Armature#getSlot()}。 * @deprecated * @language zh_CN */ public get slot(): Slot | null { for (const slot of this._armature.getSlots()) { if (slot.parent === this) { return slot; } } return null; } } }