UNPKG

dragonbones-runtime

Version:

the tools to build dragonbones file for diffrent framework

1,242 lines (1,138 loc) 54.3 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 animation state is generated when the animation data is played. * @see dragonBones.Animation * @see dragonBones.AnimationData * @version DragonBones 3.0 * @language en_US */ /** * - 动画状态由播放动画数据时产生。 * @see dragonBones.Animation * @see dragonBones.AnimationData * @version DragonBones 3.0 * @language zh_CN */ export class AnimationState extends BaseObject { public static toString(): string { return "[class dragonBones.AnimationState]"; } /** * @private */ public actionEnabled: boolean; /** * @private */ public additiveBlending: boolean; /** * - Whether the animation state has control over the display object properties of the slots. * Sometimes blend a animation state does not want it to control the display object properties of the slots, * especially if other animation state are controlling the display object properties of the slots. * @default true * @version DragonBones 5.0 * @language en_US */ /** * - 动画状态是否对插槽的显示对象属性有控制权。 * 有时混合一个动画状态并不希望其控制插槽的显示对象属性, * 尤其是其他动画状态正在控制这些插槽的显示对象属性时。 * @default true * @version DragonBones 5.0 * @language zh_CN */ public displayControl: boolean; /** * - Whether to reset the objects without animation to the armature pose when the animation state is start to play. * This property should usually be set to false when blend multiple animation states. * @default true * @version DragonBones 5.1 * @language en_US */ /** * - 开始播放动画状态时是否将没有动画的对象重置为骨架初始值。 * 通常在混合多个动画状态时应该将该属性设置为 false。 * @default true * @version DragonBones 5.1 * @language zh_CN */ public resetToPose: boolean; /** * - The play times. [0: Loop play, [1~N]: Play N times] * @version DragonBones 3.0 * @language en_US */ /** * - 播放次数。 [0: 无限循环播放, [1~N]: 循环播放 N 次] * @version DragonBones 3.0 * @language zh_CN */ public playTimes: number; /** * - The blend layer. * High layer animation state will get the blend weight first. * When the blend weight is assigned more than 1, the remaining animation states will no longer get the weight assigned. * @readonly * @version DragonBones 5.0 * @language en_US */ /** * - 混合图层。 * 图层高的动画状态会优先获取混合权重。 * 当混合权重分配超过 1 时,剩余的动画状态将不再获得权重分配。 * @readonly * @version DragonBones 5.0 * @language zh_CN */ public layer: number; /** * - The play speed. * The value is an overlay relationship with {@link dragonBones.Animation#timeScale}. * [(-N~0): Reverse play, 0: Stop play, (0~1): Slow play, 1: Normal play, (1~N): Fast play] * @default 1.0 * @version DragonBones 3.0 * @language en_US */ /** * - 播放速度。 * 该值与 {@link dragonBones.Animation#timeScale} 是叠加关系。 * [(-N~0): 倒转播放, 0: 停止播放, (0~1): 慢速播放, 1: 正常播放, (1~N): 快速播放] * @default 1.0 * @version DragonBones 3.0 * @language zh_CN */ public timeScale: number; /** * - The blend weight. * @default 1.0 * @version DragonBones 5.0 * @language en_US */ /** * - 混合权重。 * @default 1.0 * @version DragonBones 5.0 * @language zh_CN */ public weight: number; /** * - The auto fade out time when the animation state play completed. * [-1: Do not fade out automatically, [0~N]: The fade out time] (In seconds) * @default -1.0 * @version DragonBones 5.0 * @language en_US */ /** * - 动画状态播放完成后的自动淡出时间。 * [-1: 不自动淡出, [0~N]: 淡出时间] (以秒为单位) * @default -1.0 * @version DragonBones 5.0 * @language zh_CN */ public autoFadeOutTime: number; /** * @private */ public fadeTotalTime: number; /** * - The name of the animation state. (Can be different from the name of the animation data) * @readonly * @version DragonBones 5.0 * @language en_US */ /** * - 动画状态名称。 (可以不同于动画数据) * @readonly * @version DragonBones 5.0 * @language zh_CN */ public name: string; /** * - The blend group name of the animation state. * This property is typically used to specify the substitution of multiple animation states blend. * @readonly * @version DragonBones 5.0 * @language en_US */ /** * - 混合组名称。 * 该属性通常用来指定多个动画状态混合时的相互替换关系。 * @readonly * @version DragonBones 5.0 * @language zh_CN */ public group: string; private _timelineDirty: number; /** * - xx: Play Enabled, Fade Play Enabled * @internal * @private */ public _playheadState: number; /** * -1: Fade in, 0: Fade complete, 1: Fade out; * @internal * @private */ public _fadeState: number; /** * -1: Fade start, 0: Fading, 1: Fade complete; * @internal * @private */ public _subFadeState: number; /** * @internal * @private */ public _position: number; /** * @internal * @private */ public _duration: number; private _fadeTime: number; private _time: number; /** * @internal * @private */ public _fadeProgress: number; /** * @internal * @private */ public _weightResult: number; /** * @internal * @private */ public readonly _blendState: BlendState = new BlendState(); private readonly _boneMask: Array<string> = []; private readonly _boneTimelines: Array<BoneTimelineState> = []; private readonly _surfaceTimelines: Array<SurfaceTimelineState> = []; private readonly _slotTimelines: Array<SlotTimelineState> = []; private readonly _constraintTimelines: Array<ConstraintTimelineState> = []; private readonly _animationTimelines: Array<AnimationTimelineState> = []; private readonly _poseTimelines: Array<TimelineState> = []; private readonly _bonePoses: Map<BonePose> = {}; /** * @internal * @private */ public _animationData: AnimationData; private _armature: Armature; /** * @internal * @private */ public _actionTimeline: ActionTimelineState = null as any; // Initial value. private _zOrderTimeline: ZOrderTimelineState | null = null; // Initial value. /** * @internal * @private */ public _parent: AnimationState = null as any; // Initial value. /** * @private */ protected _onClear(): void { for (const timeline of this._boneTimelines) { timeline.returnToPool(); } for (const timeline of this._surfaceTimelines) { timeline.returnToPool(); } for (const timeline of this._slotTimelines) { timeline.returnToPool(); } for (const timeline of this._constraintTimelines) { timeline.returnToPool(); } for (const timeline of this._animationTimelines) { timeline.returnToPool(); } for (let k in this._bonePoses) { this._bonePoses[k].returnToPool(); delete this._bonePoses[k]; } if (this._actionTimeline !== null) { this._actionTimeline.returnToPool(); } if (this._zOrderTimeline !== null) { this._zOrderTimeline.returnToPool(); } this.actionEnabled = false; this.additiveBlending = false; this.displayControl = false; this.resetToPose = false; this.playTimes = 1; this.layer = 0; this.timeScale = 1.0; this.weight = 1.0; this.autoFadeOutTime = 0.0; this.fadeTotalTime = 0.0; this.name = ""; this.group = ""; this._timelineDirty = 2; this._playheadState = 0; this._fadeState = -1; this._subFadeState = -1; this._position = 0.0; this._duration = 0.0; this._fadeTime = 0.0; this._time = 0.0; this._fadeProgress = 0.0; this._weightResult = 0.0; this._blendState.clear(); this._boneMask.length = 0; this._boneTimelines.length = 0; this._surfaceTimelines.length = 0; this._slotTimelines.length = 0; this._constraintTimelines.length = 0; this._animationTimelines.length = 0; this._poseTimelines.length = 0; // this._bonePoses.clear(); this._animationData = null as any; // this._armature = null as any; // this._actionTimeline = null as any; // this._zOrderTimeline = null; this._parent = null as any; // } private _updateTimelines(): void { { // Update constraint timelines. for (const constraint of this._armature._constraints) { const timelineDatas = this._animationData.getConstraintTimelines(constraint.name); if (timelineDatas !== null) { for (const timelineData of timelineDatas) { switch (timelineData.type) { case TimelineType.IKConstraint: { const timeline = BaseObject.borrowObject(IKConstraintTimelineState); timeline.constraint = constraint; timeline.init(this._armature, this, timelineData); this._constraintTimelines.push(timeline); break; } default: break; } } } else if (this.resetToPose) { // Pose timeline. const timeline = BaseObject.borrowObject(IKConstraintTimelineState); timeline.constraint = constraint; timeline.init(this._armature, this, null); this._constraintTimelines.push(timeline); this._poseTimelines.push(timeline); } } } { // Update animation timelines. for (const animationState of this._armature.animation.getStates()) { if (animationState._parent !== this) { continue; } const timelineDatas = this._animationData.getAnimationTimelines(animationState.name); if (timelineDatas === null) { continue; } for (const timelineData of timelineDatas) { switch (timelineData.type) { case TimelineType.AnimationTime: { const timeline = BaseObject.borrowObject(AnimationTimelineState); timeline.animationState = animationState; timeline.init(this._armature, this, timelineData); this._animationTimelines.push(timeline); break; } default: break; } } } } } private _updateBoneAndSlotTimelines(): void { { // Update bone and surface timelines. const boneTimelines: Map<Array<BoneTimelineState>> = {}; for (const timeline of this._boneTimelines) { // Create bone timelines map. const timelineName = timeline.bone.name; if (!(timelineName in boneTimelines)) { boneTimelines[timelineName] = []; } boneTimelines[timelineName].push(timeline); } for (const bone of this._armature.getBones()) { const timelineName = bone.name; if (!this.containsBoneMask(timelineName)) { continue; } if (timelineName in boneTimelines) { // Remove bone timeline from map. delete boneTimelines[timelineName]; } else if (bone._boneData.type === BoneType.Bone) { // Create new bone timeline. const timelineDatas = this._animationData.getBoneTimelines(timelineName); const bonePose = timelineName in this._bonePoses ? this._bonePoses[timelineName] : (this._bonePoses[timelineName] = BaseObject.borrowObject(BonePose)); if (timelineDatas !== null) { for (const timelineData of timelineDatas) { switch (timelineData.type) { case TimelineType.BoneAll: { const timeline = BaseObject.borrowObject(BoneAllTimelineState); timeline.bone = bone; timeline.bonePose = bonePose; timeline.init(this._armature, this, timelineData); this._boneTimelines.push(timeline); break; } case TimelineType.BoneTranslate: { const timeline = BaseObject.borrowObject(BoneTranslateTimelineState); timeline.bone = bone; timeline.bonePose = bonePose; timeline.init(this._armature, this, timelineData); this._boneTimelines.push(timeline); break; } case TimelineType.BoneRotate: { const timeline = BaseObject.borrowObject(BoneRotateTimelineState); timeline.bone = bone; timeline.bonePose = bonePose; timeline.init(this._armature, this, timelineData); this._boneTimelines.push(timeline); break; } case TimelineType.BoneScale: { const timeline = BaseObject.borrowObject(BoneScaleTimelineState); timeline.bone = bone; timeline.bonePose = bonePose; timeline.init(this._armature, this, timelineData); this._boneTimelines.push(timeline); break; } default: break; } } } else if (this.resetToPose) { // Pose timeline. const timeline = BaseObject.borrowObject(BoneAllTimelineState); timeline.bone = bone; timeline.bonePose = bonePose; timeline.init(this._armature, this, null); this._boneTimelines.push(timeline); this._poseTimelines.push(timeline); } } else if (bone._boneData.type === BoneType.Surface) { const timelineDatas = this._animationData.getSurfaceTimelines(timelineName); if (timelineDatas !== null) { for (const timelineData of timelineDatas) { switch (timelineData.type) { case TimelineType.Surface: { const timeline = BaseObject.borrowObject(SurfaceTimelineState); timeline.surface = bone as Surface; timeline.init(this._armature, this, timelineData); this._surfaceTimelines.push(timeline); break; } default: break; } } } else if (this.resetToPose) { // Pose timeline. const timeline = BaseObject.borrowObject(SurfaceTimelineState); timeline.surface = bone as Surface; timeline.init(this._armature, this, null); this._surfaceTimelines.push(timeline); this._poseTimelines.push(timeline); } } } for (let k in boneTimelines) { // Remove bone timelines. for (const timeline of boneTimelines[k]) { this._boneTimelines.splice(this._boneTimelines.indexOf(timeline), 1); timeline.returnToPool(); } } } { // Update slot timelines. const slotTimelines: Map<Array<SlotTimelineState>> = {}; const ffdFlags: Array<number> = []; for (const timeline of this._slotTimelines) { // Create slot timelines map. const timelineName = timeline.slot.name; if (!(timelineName in slotTimelines)) { slotTimelines[timelineName] = []; } slotTimelines[timelineName].push(timeline); } for (const slot of this._armature.getSlots()) { const boneName = slot.parent.name; if (!this.containsBoneMask(boneName)) { continue; } const timelineName = slot.name; const timelineDatas = this._animationData.getSlotTimelines(timelineName); if (timelineName in slotTimelines) { // Remove slot timeline from map. delete slotTimelines[timelineName]; } else { // Create new slot timeline. let displayIndexFlag = false; let colorFlag = false; ffdFlags.length = 0; if (timelineDatas !== null) { for (const timelineData of timelineDatas) { switch (timelineData.type) { case TimelineType.SlotDisplay: { const timeline = BaseObject.borrowObject(SlotDislayTimelineState); timeline.slot = slot; timeline.init(this._armature, this, timelineData); this._slotTimelines.push(timeline); displayIndexFlag = true; break; } case TimelineType.SlotColor: { const timeline = BaseObject.borrowObject(SlotColorTimelineState); timeline.slot = slot; timeline.init(this._armature, this, timelineData); this._slotTimelines.push(timeline); colorFlag = true; break; } case TimelineType.SlotFFD: { const timeline = BaseObject.borrowObject(SlotFFDTimelineState); timeline.slot = slot; timeline.init(this._armature, this, timelineData); this._slotTimelines.push(timeline); ffdFlags.push(timeline.meshOffset); break; } default: break; } } } if (this.resetToPose) { // Pose timeline. if (!displayIndexFlag) { const timeline = BaseObject.borrowObject(SlotDislayTimelineState); timeline.slot = slot; timeline.init(this._armature, this, null); this._slotTimelines.push(timeline); this._poseTimelines.push(timeline); } if (!colorFlag) { const timeline = BaseObject.borrowObject(SlotColorTimelineState); timeline.slot = slot; timeline.init(this._armature, this, null); this._slotTimelines.push(timeline); this._poseTimelines.push(timeline); } if (slot.rawDisplayDatas !== null) { for (const displayData of slot.rawDisplayDatas) { if (displayData !== null && displayData.type === DisplayType.Mesh) { const meshOffset = (displayData as MeshDisplayData).offset; if (ffdFlags.indexOf(meshOffset) < 0) { const timeline = BaseObject.borrowObject(SlotFFDTimelineState); timeline.meshOffset = meshOffset; // timeline.slot = slot; timeline.init(this._armature, this, null); this._slotTimelines.push(timeline); this._poseTimelines.push(timeline); } } } } } } } for (let k in slotTimelines) { // Remove slot timelines. for (const timeline of slotTimelines[k]) { this._slotTimelines.splice(this._slotTimelines.indexOf(timeline), 1); timeline.returnToPool(); } } } } private _advanceFadeTime(passedTime: number): void { const isFadeOut = this._fadeState > 0; if (this._subFadeState < 0) { // Fade start event. this._subFadeState = 0; const eventType = isFadeOut ? EventObject.FADE_OUT : EventObject.FADE_IN; if (this._armature.eventDispatcher.hasDBEventListener(eventType)) { const eventObject = BaseObject.borrowObject(EventObject); eventObject.type = eventType; eventObject.armature = this._armature; eventObject.animationState = this; this._armature._dragonBones.bufferEvent(eventObject); } } if (passedTime < 0.0) { passedTime = -passedTime; } this._fadeTime += passedTime; if (this._fadeTime >= this.fadeTotalTime) { // Fade complete. this._subFadeState = 1; this._fadeProgress = isFadeOut ? 0.0 : 1.0; } else if (this._fadeTime > 0.0) { // Fading. this._fadeProgress = isFadeOut ? (1.0 - this._fadeTime / this.fadeTotalTime) : (this._fadeTime / this.fadeTotalTime); } else { // Before fade. this._fadeProgress = isFadeOut ? 1.0 : 0.0; } if (this._subFadeState > 0) { // Fade complete event. if (!isFadeOut) { this._playheadState |= 1; // x1 this._fadeState = 0; } const eventType = isFadeOut ? EventObject.FADE_OUT_COMPLETE : EventObject.FADE_IN_COMPLETE; if (this._armature.eventDispatcher.hasDBEventListener(eventType)) { const eventObject = BaseObject.borrowObject(EventObject); eventObject.type = eventType; eventObject.armature = this._armature; eventObject.animationState = this; this._armature._dragonBones.bufferEvent(eventObject); } } } /** * @internal * @private */ public init(armature: Armature, animationData: AnimationData, animationConfig: AnimationConfig): void { if (this._armature !== null) { return; } this._armature = armature; this._animationData = animationData; // this.resetToPose = animationConfig.resetToPose; this.additiveBlending = animationConfig.additiveBlending; this.displayControl = animationConfig.displayControl; this.actionEnabled = animationConfig.actionEnabled; this.layer = animationConfig.layer; this.playTimes = animationConfig.playTimes; this.timeScale = animationConfig.timeScale; this.fadeTotalTime = animationConfig.fadeInTime; this.autoFadeOutTime = animationConfig.autoFadeOutTime; this.weight = animationConfig.weight; this.name = animationConfig.name.length > 0 ? animationConfig.name : animationConfig.animation; this.group = animationConfig.group; if (animationConfig.pauseFadeIn) { this._playheadState = 2; // 10 } else { this._playheadState = 3; // 11 } if (animationConfig.duration < 0.0) { this._position = 0.0; this._duration = this._animationData.duration; if (animationConfig.position !== 0.0) { if (this.timeScale >= 0.0) { this._time = animationConfig.position; } else { this._time = animationConfig.position - this._duration; } } else { this._time = 0.0; } } else { this._position = animationConfig.position; this._duration = animationConfig.duration; this._time = 0.0; } if (this.timeScale < 0.0 && this._time === 0.0) { this._time = -0.000001; // Turn to end. } if (this.fadeTotalTime <= 0.0) { this._fadeProgress = 0.999999; // Make different. } if (animationConfig.boneMask.length > 0) { this._boneMask.length = animationConfig.boneMask.length; for (let i = 0, l = this._boneMask.length; i < l; ++i) { this._boneMask[i] = animationConfig.boneMask[i]; } } this._actionTimeline = BaseObject.borrowObject(ActionTimelineState); this._actionTimeline.init(this._armature, this, this._animationData.actionTimeline); this._actionTimeline.currentTime = this._time; if (this._actionTimeline.currentTime < 0.0) { this._actionTimeline.currentTime = this._duration - this._actionTimeline.currentTime; } if (this._animationData.zOrderTimeline !== null) { this._zOrderTimeline = BaseObject.borrowObject(ZOrderTimelineState); this._zOrderTimeline.init(this._armature, this, this._animationData.zOrderTimeline); } } /** * @internal * @private */ public advanceTime(passedTime: number, cacheFrameRate: number): void { this._blendState.dirty = false; // Update fade time. if (this._fadeState !== 0 || this._subFadeState !== 0) { this._advanceFadeTime(passedTime); } // Update time. if (this._playheadState === 3) { // 11 if (this.timeScale !== 1.0) { passedTime *= this.timeScale; } this._time += passedTime; } // Update timeline. if (this._timelineDirty !== 0) { if (this._timelineDirty === 2) { this._updateTimelines(); } this._timelineDirty = 0; this._updateBoneAndSlotTimelines(); } if (this.weight === 0.0) { return; } const isCacheEnabled = this._fadeState === 0 && cacheFrameRate > 0.0; let isUpdateTimeline = true; let isUpdateBoneTimeline = true; let time = this._time; this._weightResult = this.weight * this._fadeProgress; if (this._parent !== null) { this._weightResult *= this._parent._weightResult / this._parent._fadeProgress; } if (this._actionTimeline.playState <= 0) { this._actionTimeline.update(time); // Update main timeline. } if (isCacheEnabled) { // Cache time internval. const internval = cacheFrameRate * 2.0; this._actionTimeline.currentTime = Math.floor(this._actionTimeline.currentTime * internval) / internval; } if (this._zOrderTimeline !== null && this._zOrderTimeline.playState <= 0) { // Update zOrder timeline. this._zOrderTimeline.update(time); } if (isCacheEnabled) { // Update cache. const cacheFrameIndex = Math.floor(this._actionTimeline.currentTime * cacheFrameRate); // uint if (this._armature._cacheFrameIndex === cacheFrameIndex) { // Same cache. isUpdateTimeline = false; isUpdateBoneTimeline = false; } else { this._armature._cacheFrameIndex = cacheFrameIndex; if (this._animationData.cachedFrames[cacheFrameIndex]) { // Cached. isUpdateBoneTimeline = false; } else { // Cache. this._animationData.cachedFrames[cacheFrameIndex] = true; } } } if (isUpdateTimeline) { if (isUpdateBoneTimeline) { // Update bone timelines. for (let i = 0, l = this._boneTimelines.length; i < l; ++i) { const timeline = this._boneTimelines[i]; if (timeline.playState <= 0) { timeline.update(time); } if (i === l - 1 || timeline.bone !== this._boneTimelines[i + 1].bone) { const state = timeline.bone._blendState.update(this._weightResult, this.layer); if (state !== 0) { timeline.blend(state); } } } } for (let i = 0, l = this._surfaceTimelines.length; i < l; ++i) { const timeline = this._surfaceTimelines[i]; const state = timeline.surface._blendState.update(this._weightResult, this.layer); if (timeline.playState <= 0) { timeline.update(time); } if (state !== 0) { timeline.blend(state); } } if (this.displayControl) { for (let i = 0, l = this._slotTimelines.length; i < l; ++i) { const timeline = this._slotTimelines[i]; const displayController = timeline.slot.displayController; if ( displayController === null || displayController === this.name || displayController === this.group ) { if (timeline.playState <= 0) { timeline.update(time); } } } } for (let i = 0, l = this._constraintTimelines.length; i < l; ++i) { const timeline = this._constraintTimelines[i]; if (timeline.playState <= 0) { timeline.update(time); } } for (let i = 0, l = this._animationTimelines.length; i < l; ++i) { const timeline = this._animationTimelines[i]; const state = timeline.animationState._blendState.update(this._weightResult, this.layer); if (timeline.playState <= 0) { timeline.update(time); } if (state !== 0) { timeline.blend(state); } } } if (this._fadeState === 0) { if (this._subFadeState > 0) { this._subFadeState = 0; if (this._poseTimelines.length > 0) { // Remove pose timelines. for (const timeline of this._poseTimelines) { if (timeline instanceof BoneTimelineState) { this._boneTimelines.splice(this._boneTimelines.indexOf(timeline), 1); } else if (timeline instanceof SurfaceTimelineState) { this._surfaceTimelines.splice(this._surfaceTimelines.indexOf(timeline), 1); } else if (timeline instanceof SlotTimelineState) { this._slotTimelines.splice(this._slotTimelines.indexOf(timeline), 1); } else if (timeline instanceof ConstraintTimelineState) { this._constraintTimelines.splice(this._constraintTimelines.indexOf(timeline), 1); } timeline.returnToPool(); } this._poseTimelines.length = 0; } } if (this._actionTimeline.playState > 0) { if (this.autoFadeOutTime >= 0.0) { // Auto fade out. this.fadeOut(this.autoFadeOutTime); } } } } /** * - Continue play. * @version DragonBones 3.0 * @language en_US */ /** * - 继续播放。 * @version DragonBones 3.0 * @language zh_CN */ public play(): void { this._playheadState = 3; // 11 } /** * - Stop play. * @version DragonBones 3.0 * @language en_US */ /** * - 暂停播放。 * @version DragonBones 3.0 * @language zh_CN */ public stop(): void { this._playheadState &= 1; // 0x } /** * - Fade out the animation state. * @param fadeOutTime - The fade out time. (In seconds) * @param pausePlayhead - Whether to pause the animation playing when fade out. * @version DragonBones 3.0 * @language en_US */ /** * - 淡出动画状态。 * @param fadeOutTime - 淡出时间。 (以秒为单位) * @param pausePlayhead - 淡出时是否暂停播放。 * @version DragonBones 3.0 * @language zh_CN */ public fadeOut(fadeOutTime: number, pausePlayhead: boolean = true): void { if (fadeOutTime < 0.0) { fadeOutTime = 0.0; } if (pausePlayhead) { this._playheadState &= 2; // x0 } if (this._fadeState > 0) { if (fadeOutTime > this.fadeTotalTime - this._fadeTime) { // If the animation is already in fade out, the new fade out will be ignored. return; } } else { this._fadeState = 1; this._subFadeState = -1; if (fadeOutTime <= 0.0 || this._fadeProgress <= 0.0) { this._fadeProgress = 0.000001; // Modify fade progress to different value. } for (const timeline of this._boneTimelines) { timeline.fadeOut(); } for (const timeline of this._surfaceTimelines) { timeline.fadeOut(); } for (const timeline of this._slotTimelines) { timeline.fadeOut(); } for (const timeline of this._constraintTimelines) { timeline.fadeOut(); } for (const timeline of this._animationTimelines) { timeline.animationState.fadeOut(fadeOutTime, pausePlayhead); timeline.fadeOut(); } } this.displayControl = false; // this.fadeTotalTime = this._fadeProgress > 0.000001 ? fadeOutTime / this._fadeProgress : 0.0; this._fadeTime = this.fadeTotalTime * (1.0 - this._fadeProgress); } /** * - Check if a specific bone mask is included. * @param name - The bone name. * @version DragonBones 3.0 * @language en_US */ /** * - 检查是否包含特定骨骼遮罩。 * @param name - 骨骼名称。 * @version DragonBones 3.0 * @language zh_CN */ public containsBoneMask(name: string): boolean { return this._boneMask.length === 0 || this._boneMask.indexOf(name) >= 0; } /** * - Add a specific bone mask. * @param name - The bone name. * @param recursive - Whether or not to add a mask to the bone's sub-bone. * @version DragonBones 3.0 * @language en_US */ /** * - 添加特定的骨骼遮罩。 * @param name - 骨骼名称。 * @param recursive - 是否为该骨骼的子骨骼添加遮罩。 * @version DragonBones 3.0 * @language zh_CN */ public addBoneMask(name: string, recursive: boolean = true): void { const currentBone = this._armature.getBone(name); if (currentBone === null) { return; } if (this._boneMask.indexOf(name) < 0) { // Add mixing this._boneMask.push(name); } if (recursive) { // Add recursive mixing. for (const bone of this._armature.getBones()) { if (this._boneMask.indexOf(bone.name) < 0 && currentBone.contains(bone)) { this._boneMask.push(bone.name); } } } this._timelineDirty = 1; } /** * - Remove the mask of a specific bone. * @param name - The bone name. * @param recursive - Whether to remove the bone's sub-bone mask. * @version DragonBones 3.0 * @language en_US */ /** * - 删除特定骨骼的遮罩。 * @param name - 骨骼名称。 * @param recursive - 是否删除该骨骼的子骨骼遮罩。 * @version DragonBones 3.0 * @language zh_CN */ public removeBoneMask(name: string, recursive: boolean = true): void { const index = this._boneMask.indexOf(name); if (index >= 0) { // Remove mixing. this._boneMask.splice(index, 1); } if (recursive) { const currentBone = this._armature.getBone(name); if (currentBone !== null) { const bones = this._armature.getBones(); if (this._boneMask.length > 0) { // Remove recursive mixing. for (const bone of bones) { const index = this._boneMask.indexOf(bone.name); if (index >= 0 && currentBone.contains(bone)) { this._boneMask.splice(index, 1); } } } else { // Add unrecursive mixing. for (const bone of bones) { if (bone === currentBone) { continue; } if (!currentBone.contains(bone)) { this._boneMask.push(bone.name); } } } } } this._timelineDirty = 1; } /** * - Remove all bone masks. * @version DragonBones 3.0 * @language en_US */ /** * - 删除所有骨骼遮罩。 * @version DragonBones 3.0 * @language zh_CN */ public removeAllBoneMask(): void { this._boneMask.length = 0; this._timelineDirty = 1; } /** * - Whether the animation state is fading in. * @version DragonBones 5.1 * @language en_US */ /** * - 是否正在淡入。 * @version DragonBones 5.1 * @language zh_CN */ public get isFadeIn(): boolean { return this._fadeState < 0; } /** * - Whether the animation state is fading out. * @version DragonBones 5.1 * @language en_US */ /** * - 是否正在淡出。 * @version DragonBones 5.1 * @language zh_CN */ public get isFadeOut(): boolean { return this._fadeState > 0; } /** * - Whether the animation state is fade completed. * @version DragonBones 5.1 * @language en_US */ /** * - 是否淡入或淡出完毕。 * @version DragonBones 5.1 * @language zh_CN */ public get isFadeComplete(): boolean { return this._fadeState === 0; } /** * - Whether the animation state is playing. * @version DragonBones 3.0 * @language en_US */ /** * - 是否正在播放。 * @version DragonBones 3.0 * @language zh_CN */ public get isPlaying(): boolean { return (this._playheadState & 2) !== 0 && this._actionTimeline.playState <= 0; } /** * - Whether the animation state is play completed. * @version DragonBones 3.0 * @language en_US */ /** * - 是否播放完毕。 * @version DragonBones 3.0 * @language zh_CN */ public get isCompleted(): boolean { return this._actionTimeline.playState > 0; } /** * - The times has been played. * @version DragonBones 3.0 * @language en_US */ /** * - 已经循环播放的次数。 * @version DragonBones 3.0 * @language zh_CN */ public get currentPlayTimes(): number { return this._actionTimeline.currentPlayTimes; } /** * - The total time. (In seconds) * @version DragonBones 3.0 * @language en_US */ /** * - 总播放时间。 (以秒为单位) * @version DragonBones 3.0 * @language zh_CN */ public get totalTime(): number { return this._duration; } /** * - The time is currently playing. (In seconds) * @version DragonBones 3.0 * @language en_US */ /** * - 当前播放的时间。 (以秒为单位) * @version DragonBones 3.0 * @language zh_CN */ public get currentTime(): number { return this._actionTimeline.currentTime; } public set currentTime(value: number) { const currentPlayTimes = this._actionTimeline.currentPlayTimes - (this._actionTimeline.playState > 0 ? 1 : 0); if (value < 0 || this._duration < value) { value = (value % this._duration) + currentPlayTimes * this._duration; if (value < 0) { value += this._duration; } } if (this.playTimes > 0 && currentPlayTimes === this.playTimes - 1 && value === this._duration) { value = this._duration - 0.000001; } if (this._time ===