/**
* 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.
*/
using System;
using System.Collections.Generic;
namespace DragonBones
{
///
/// - The animation state is generated when the animation data is played.
///
///
///
/// DragonBones 3.0
/// en_US
///
/// - 动画状态由播放动画数据时产生。
///
///
///
/// DragonBones 3.0
/// zh_CN
public class AnimationState : BaseObject
{
///
public bool actionEnabled;
///
public bool additiveBlending;
///
/// - 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.
///
/// true
/// DragonBones 5.0
/// en_US
///
/// - 动画状态是否对插槽的显示对象属性有控制权。
/// 有时混合一个动画状态并不希望其控制插槽的显示对象属性,
/// 尤其是其他动画状态正在控制这些插槽的显示对象属性时。
///
/// true
/// DragonBones 5.0
/// zh_CN
public bool displayControl;
///
/// - 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.
///
/// true
/// DragonBones 5.1
/// en_US
///
/// - 开始播放动画状态时是否将没有动画的对象重置为骨架初始值。
/// 通常在混合多个动画状态时应该将该属性设置为 false。
///
/// true
/// DragonBones 5.1
/// zh_CN
public bool resetToPose;
///
/// - The play times. [0: Loop play, [1~N]: Play N times]
///
/// DragonBones 3.0
/// en_US
///
/// - 播放次数。 [0: 无限循环播放, [1~N]: 循环播放 N 次]
///
/// DragonBones 3.0
/// zh_CN
public int playTimes;
///
/// - 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.
///
///
/// DragonBones 5.0
/// en_US
///
/// - 混合图层。
/// 图层高的动画状态会优先获取混合权重。
/// 当混合权重分配超过 1 时,剩余的动画状态将不再获得权重分配。
///
///
/// DragonBones 5.0
/// zh_CN
public int layer;
///
/// - 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]
///
/// 1.0
/// DragonBones 3.0
/// en_US
///
/// - 播放速度。
/// 该值与 {@link dragonBones.Animation#timeScale} 是叠加关系。
/// [(-N~0): 倒转播放, 0: 停止播放, (0~1): 慢速播放, 1: 正常播放, (1~N): 快速播放]
///
/// 1.0
/// DragonBones 3.0
/// zh_CN
public float timeScale;
///
/// - The blend weight.
///
/// 1.0
/// DragonBones 5.0
/// en_US
///
/// - 混合权重。
///
/// 1.0
/// DragonBones 5.0
/// zh_CN
public float weight;
///
/// - 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)
///
/// -1.0
/// DragonBones 5.0
/// en_US
///
/// - 动画状态播放完成后的自动淡出时间。
/// [-1: 不自动淡出, [0~N]: 淡出时间] (以秒为单位)
///
/// -1.0
/// DragonBones 5.0
/// zh_CN
public float autoFadeOutTime;
///
public float fadeTotalTime;
///
/// - The name of the animation state. (Can be different from the name of the animation data)
///
///
/// DragonBones 5.0
/// en_US
///
/// - 动画状态名称。 (可以不同于动画数据)
///
///
/// DragonBones 5.0
/// zh_CN
public string name;
///
/// - The blend group name of the animation state.
/// This property is typically used to specify the substitution of multiple animation states blend.
///
///
/// DragonBones 5.0
/// en_US
///
/// - 混合组名称。
/// 该属性通常用来指定多个动画状态混合时的相互替换关系。
///
///
/// DragonBones 5.0
/// zh_CN
public string group;
private int _timelineDirty;
///
/// - xx: Play Enabled, Fade Play Enabled
///
///
///
internal int _playheadState;
///
/// -1: Fade in, 0: Fade complete, 1: Fade out;
///
///
///
internal int _fadeState;
///
/// -1: Fade start, 0: Fading, 1: Fade complete;
///
///
///
internal int _subFadeState;
///
///
internal float _position;
///
///
internal float _duration;
private float _fadeTime;
private float _time;
///
///
internal float _fadeProgress;
///
///
private float _weightResult;
///
///
internal readonly BlendState _blendState = new BlendState();
private readonly List _boneMask = new List();
private readonly List _boneTimelines = new List();
private readonly List _slotTimelines = new List();
private readonly List _constraintTimelines = new List();
private readonly List _poseTimelines = new List();
private readonly Dictionary _bonePoses = new Dictionary();
///
///
public AnimationData _animationData;
private Armature _armature;
///
///
internal ActionTimelineState _actionTimeline = null; // Initial value.
private ZOrderTimelineState _zOrderTimeline = null; // Initial value.
///
///
public AnimationState _parent = null; // Initial value.
///
protected override void _OnClear()
{
foreach (var timeline in this._boneTimelines)
{
timeline.ReturnToPool();
}
foreach (var timeline in this._slotTimelines)
{
timeline.ReturnToPool();
}
foreach (var timeline in this._constraintTimelines)
{
timeline.ReturnToPool();
}
foreach(var timeline in this._poseTimelines)
{
timeline.ReturnToPool();
}
foreach (var bonePose in this._bonePoses.Values)
{
bonePose.ReturnToPool();
}
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.0f;
this.weight = 1.0f;
this.autoFadeOutTime = 0.0f;
this.fadeTotalTime = 0.0f;
this.name = string.Empty;
this.group = string.Empty;
this._timelineDirty = 2;
this._playheadState = 0;
this._fadeState = -1;
this._subFadeState = -1;
this._position = 0.0f;
this._duration = 0.0f;
this._fadeTime = 0.0f;
this._time = 0.0f;
this._fadeProgress = 0.0f;
this._weightResult = 0.0f;
this._blendState.Clear();
this._boneMask.Clear();
this._boneTimelines.Clear();
this._slotTimelines.Clear();
this._constraintTimelines.Clear();
this._poseTimelines.Clear();
this._bonePoses.Clear();
this._animationData = null; //
this._armature = null; //
this._actionTimeline = null; //
this._zOrderTimeline = null;
this._parent = null;
}
private void _UpdateTimelines()
{
{ // Update constraint timelines.
foreach (var constraint in this._armature._constraints)
{
var timelineDatas = this._animationData.GetConstraintTimelines(constraint.name);
if (timelineDatas != null)
{
foreach (var timelineData in timelineDatas)
{
switch (timelineData.type)
{
case TimelineType.IKConstraint:
{
var timeline = BaseObject.BorrowObject();
timeline.constraint = constraint;
timeline.Init(this._armature, this, timelineData);
this._constraintTimelines.Add(timeline);
break;
}
default:
break;
}
}
}
else if (this.resetToPose)
{ // Pose timeline.
var timeline = BaseObject.BorrowObject();
timeline.constraint = constraint;
timeline.Init(this._armature, this, null);
this._constraintTimelines.Add(timeline);
this._poseTimelines.Add(timeline);
}
}
}
}
private void _UpdateBoneAndSlotTimelines()
{
{ // Update bone timelines.
Dictionary> boneTimelines = new Dictionary>();
foreach (var timeline in this._boneTimelines)
{
// Create bone timelines map.
var timelineName = timeline.bone.name;
if (!(boneTimelines.ContainsKey(timelineName)))
{
boneTimelines[timelineName] = new List();
}
boneTimelines[timelineName].Add(timeline);
}
foreach (var bone in this._armature.GetBones())
{
var timelineName = bone.name;
if (!this.ContainsBoneMask(timelineName))
{
continue;
}
var timelineDatas = this._animationData.GetBoneTimelines(timelineName);
if (boneTimelines.ContainsKey(timelineName))
{
// Remove bone timeline from map.
boneTimelines.Remove(timelineName);
}
else
{
// Create new bone timeline.
var bonePose = this._bonePoses.ContainsKey(timelineName) ? this._bonePoses[timelineName] : (this._bonePoses[timelineName] = BaseObject.BorrowObject());
if (timelineDatas != null)
{
foreach (var timelineData in timelineDatas)
{
switch (timelineData.type)
{
case TimelineType.BoneAll:
{
var timeline = BaseObject.BorrowObject();
timeline.bone = bone;
timeline.bonePose = bonePose;
timeline.Init(this._armature, this, timelineData);
this._boneTimelines.Add(timeline);
break;
}
case TimelineType.BoneTranslate:
{
var timeline = BaseObject.BorrowObject();
timeline.bone = bone;
timeline.bonePose = bonePose;
timeline.Init(this._armature, this, timelineData);
this._boneTimelines.Add(timeline);
break;
}
case TimelineType.BoneRotate:
{
var timeline = BaseObject.BorrowObject();
timeline.bone = bone;
timeline.bonePose = bonePose;
timeline.Init(this._armature, this, timelineData);
this._boneTimelines.Add(timeline);
break;
}
case TimelineType.BoneScale:
{
var timeline = BaseObject.BorrowObject();
timeline.bone = bone;
timeline.bonePose = bonePose;
timeline.Init(this._armature, this, timelineData);
this._boneTimelines.Add(timeline);
break;
}
default:
break;
}
}
}
else if (this.resetToPose)
{ // Pose timeline.
var timeline = BaseObject.BorrowObject();
timeline.bone = bone;
timeline.bonePose = bonePose;
timeline.Init(this._armature, this, null);
this._boneTimelines.Add(timeline);
this._poseTimelines.Add(timeline);
}
}
}
foreach (var timelines in boneTimelines.Values)
{
// Remove bone timelines.
foreach (var timeline in timelines)
{
this._boneTimelines.Remove(timeline);
timeline.ReturnToPool();
}
}
}
{ // Update slot timelines.
Dictionary> slotTimelines = new Dictionary>();
List ffdFlags = new List();
foreach (var timeline in this._slotTimelines)
{
// Create slot timelines map.
var timelineName = timeline.slot.name;
if (!(slotTimelines.ContainsKey(timelineName)))
{
slotTimelines[timelineName] = new List();
}
slotTimelines[timelineName].Add(timeline);
}
foreach (var slot in this._armature.GetSlots())
{
var boneName = slot.parent.name;
if (!this.ContainsBoneMask(boneName))
{
continue;
}
var timelineName = slot.name;
var timelineDatas = this._animationData.GetSlotTimelines(timelineName);
if (slotTimelines.ContainsKey(timelineName))
{
// Remove slot timeline from map.
slotTimelines.Remove(timelineName);
}
else
{
// Create new slot timeline.
var displayIndexFlag = false;
var colorFlag = false;
ffdFlags.Clear();
if (timelineDatas != null)
{
foreach (var timelineData in timelineDatas)
{
switch (timelineData.type)
{
case TimelineType.SlotDisplay:
{
var timeline = BaseObject.BorrowObject();
timeline.slot = slot;
timeline.Init(this._armature, this, timelineData);
this._slotTimelines.Add(timeline);
displayIndexFlag = true;
break;
}
case TimelineType.SlotColor:
{
var timeline = BaseObject.BorrowObject();
timeline.slot = slot;
timeline.Init(this._armature, this, timelineData);
this._slotTimelines.Add(timeline);
colorFlag = true;
break;
}
case TimelineType.SlotDeform:
{
var timeline = BaseObject.BorrowObject();
timeline.slot = slot;
timeline.Init(this._armature, this, timelineData);
this._slotTimelines.Add(timeline);
ffdFlags.Add((int)timeline.vertexOffset);
break;
}
default:
break;
}
}
}
if (this.resetToPose)
{
// Pose timeline.
if (!displayIndexFlag)
{
var timeline = BaseObject.BorrowObject();
timeline.slot = slot;
timeline.Init(this._armature, this, null);
this._slotTimelines.Add(timeline);
this._poseTimelines.Add(timeline);
}
if (!colorFlag)
{
var timeline = BaseObject.BorrowObject();
timeline.slot = slot;
timeline.Init(this._armature, this, null);
this._slotTimelines.Add(timeline);
this._poseTimelines.Add(timeline);
}
if (slot.rawDisplayDatas != null)
{
foreach (var displayData in slot.rawDisplayDatas)
{
if (displayData != null && displayData.type == DisplayType.Mesh)
{
var meshOffset = (displayData as MeshDisplayData).vertices.offset;
if (!ffdFlags.Contains(meshOffset))
{
var timeline = BaseObject.BorrowObject();
timeline.vertexOffset = meshOffset; //
timeline.slot = slot;
timeline.Init(this._armature, this, null);
this._slotTimelines.Add(timeline);
this._poseTimelines.Add(timeline);
}
}
}
}
}
}
}
foreach (var timelines in slotTimelines.Values)
{
// Remove slot timelines.
foreach (var timeline in timelines)
{
this._slotTimelines.Remove(timeline);
timeline.ReturnToPool();
}
}
}
// {
// // Update constraint timelines.
// Dictionary> constraintTimelines = new Dictionary>();
// foreach (var timeline in this._constraintTimelines)
// { // Create constraint timelines map.
// var timelineName = timeline.constraint.name;
// if (!(constraintTimelines.ContainsKey(timelineName)))
// {
// constraintTimelines[timelineName] = new List();
// }
// constraintTimelines[timelineName].Add(timeline);
// }
// foreach (var constraint in this._armature._constraints)
// {
// var timelineName = constraint.name;
// var timelineDatas = this._animationData.GetConstraintTimelines(timelineName);
// if (constraintTimelines.ContainsKey(timelineName))
// {
// // Remove constraint timeline from map.
// constraintTimelines.Remove(timelineName);
// }
// else
// {
// // Create new constraint timeline.
// if (timelineDatas != null)
// {
// foreach (var timelineData in timelineDatas)
// {
// switch (timelineData.type)
// {
// case TimelineType.IKConstraint:
// {
// var timeline = BaseObject.BorrowObject();
// timeline.constraint = constraint;
// timeline.Init(this._armature, this, timelineData);
// this._constraintTimelines.Add(timeline);
// break;
// }
// default:
// break;
// }
// }
// }
// else if (this.resetToPose)
// {
// // Pose timeline.
// var timeline = BaseObject.BorrowObject();
// timeline.constraint = constraint;
// timeline.Init(this._armature, this, null);
// this._constraintTimelines.Add(timeline);
// this._poseTimelines.Add(timeline);
// }
// }
// }
// foreach (var timelines in constraintTimelines.Values)
// { // Remove constraint timelines.
// foreach (var timeline in timelines)
// {
// this._constraintTimelines.Remove(timeline);
// timeline.ReturnToPool();
// }
// }
// }
}
private void _AdvanceFadeTime(float passedTime)
{
var isFadeOut = this._fadeState > 0;
if (this._subFadeState < 0)
{
// Fade start event.
this._subFadeState = 0;
var eventType = isFadeOut ? EventObject.FADE_OUT : EventObject.FADE_IN;
if (this._armature.eventDispatcher.HasDBEventListener(eventType))
{
var eventObject = BaseObject.BorrowObject();
eventObject.type = eventType;
eventObject.armature = this._armature;
eventObject.animationState = this;
this._armature._dragonBones.BufferEvent(eventObject);
}
}
if (passedTime < 0.0f)
{
passedTime = -passedTime;
}
this._fadeTime += passedTime;
if (this._fadeTime >= this.fadeTotalTime)
{
// Fade complete.
this._subFadeState = 1;
this._fadeProgress = isFadeOut ? 0.0f : 1.0f;
}
else if (this._fadeTime > 0.0f)
{
// Fading.
this._fadeProgress = isFadeOut ? (1.0f - this._fadeTime / this.fadeTotalTime) : (this._fadeTime / this.fadeTotalTime);
}
else
{
// Before fade.
this._fadeProgress = isFadeOut ? 1.0f : 0.0f;
}
if (this._subFadeState > 0)
{
// Fade complete event.
if (!isFadeOut)
{
this._playheadState |= 1; // x1
this._fadeState = 0;
}
var eventType = isFadeOut ? EventObject.FADE_OUT_COMPLETE : EventObject.FADE_IN_COMPLETE;
if (this._armature.eventDispatcher.HasDBEventListener(eventType))
{
var eventObject = BaseObject.BorrowObject();
eventObject.type = eventType;
eventObject.armature = this._armature;
eventObject.animationState = this;
this._armature._dragonBones.BufferEvent(eventObject);
}
}
}
///
///
internal void Init(Armature armature, AnimationData animationData, AnimationConfig animationConfig)
{
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.0f)
{
this._position = 0.0f;
this._duration = this._animationData.duration;
if (animationConfig.position != 0.0f)
{
if (this.timeScale >= 0.0f)
{
this._time = animationConfig.position;
}
else
{
this._time = animationConfig.position - this._duration;
}
}
else
{
this._time = 0.0f;
}
}
else
{
this._position = animationConfig.position;
this._duration = animationConfig.duration;
this._time = 0.0f;
}
if (this.timeScale < 0.0f && this._time == 0.0f)
{
this._time = -0.000001f; // Turn to end.
}
if (this.fadeTotalTime <= 0.0f)
{
this._fadeProgress = 0.999999f; // Make different.
}
if (animationConfig.boneMask.Count > 0)
{
this._boneMask.ResizeList(animationConfig.boneMask.Count);
for (int i = 0, l = this._boneMask.Count; i < l; ++i)
{
this._boneMask[i] = animationConfig.boneMask[i];
}
}
this._actionTimeline = BaseObject.BorrowObject();
this._actionTimeline.Init(this._armature, this, this._animationData.actionTimeline);
this._actionTimeline.currentTime = this._time;
if (this._actionTimeline.currentTime < 0.0f)
{
this._actionTimeline.currentTime = this._duration - this._actionTimeline.currentTime;
}
if (this._animationData.zOrderTimeline != null)
{
this._zOrderTimeline = BaseObject.BorrowObject();
this._zOrderTimeline.Init(this._armature, this, this._animationData.zOrderTimeline);
}
}
///
///
internal void AdvanceTime(float passedTime, float cacheFrameRate)
{
this._blendState.dirty = true;
// Update fade time.
if (this._fadeState != 0 || this._subFadeState != 0)
{
this._AdvanceFadeTime(passedTime);
}
// Update time.
if (this._playheadState == 3)
{
// 11
if (this.timeScale != 1.0f)
{
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.0f)
{
return;
}
var isCacheEnabled = this._fadeState == 0 && cacheFrameRate > 0.0f;
var isUpdateTimeline = true;
var isUpdateBoneTimeline = true;
var 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)
{
// Update main timeline.
this._actionTimeline.Update(time);
}
if (isCacheEnabled)
{
// Cache time internval.
var internval = cacheFrameRate * 2.0f;
this._actionTimeline.currentTime = (float)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.
var cacheFrameIndex = (int)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)
{
for (int i = 0, l = this._boneTimelines.Count; i < l; ++i)
{
var timeline = this._boneTimelines[i];
if (timeline.playState <= 0)
{
timeline.Update(time);
}
if (i == l - 1 || timeline.bone != this._boneTimelines[i + 1].bone)
{
var state = timeline.bone._blendState.Update(this._weightResult, this.layer);
if (state != 0)
{
timeline.Blend(state);
}
}
}
}
if (this.displayControl)
{
for (int i = 0, l = this._slotTimelines.Count; i < l; ++i)
{
var timeline = this._slotTimelines[i];
var displayController = timeline.slot.displayController;
if (
displayController == null ||
displayController == this.name ||
displayController == this.group
)
{
if (timeline.playState <= 0)
{
timeline.Update(time);
}
}
}
}
for (int i = 0, l = this._constraintTimelines.Count; i < l; ++i)
{
var timeline = this._constraintTimelines[i];
if (timeline.playState <= 0)
{
timeline.Update(time);
}
}
}
if (this._fadeState == 0)
{
if (this._subFadeState > 0)
{
this._subFadeState = 0;
if (this._poseTimelines.Count > 0)
{
foreach (var timeline in this._poseTimelines)
{
if (timeline is BoneTimelineState)
{
this._boneTimelines.Remove(timeline as BoneTimelineState);
}
else if (timeline is SlotTimelineState)
{
this._slotTimelines.Remove(timeline as SlotTimelineState);
}
else if (timeline is ConstraintTimelineState)
{
this._constraintTimelines.Remove(timeline as ConstraintTimelineState);
}
timeline.ReturnToPool();
}
this._poseTimelines.Clear();
}
}
if (this._actionTimeline.playState > 0)
{
if (this.autoFadeOutTime >= 0.0f)
{
// Auto fade out.
this.FadeOut(this.autoFadeOutTime);
}
}
}
}
///
/// - Continue play.
///
/// DragonBones 3.0
/// en_US
///
/// - 继续播放。
///
/// DragonBones 3.0
/// zh_CN
public void Play()
{
this._playheadState = 3; // 11
}
///
/// - Stop play.
///
/// DragonBones 3.0
/// en_US
///
/// - 暂停播放。
///
/// DragonBones 3.0
/// zh_CN
public void Stop()
{
this._playheadState &= 1; // 0x
}
///
/// - Fade out the animation state.
///
/// - The fade out time. (In seconds)
/// - Whether to pause the animation playing when fade out.
/// DragonBones 3.0
/// en_US
///
/// - 淡出动画状态。
///
/// - 淡出时间。 (以秒为单位)
/// - 淡出时是否暂停播放。
/// DragonBones 3.0
/// zh_CN
public void FadeOut(float fadeOutTime, bool pausePlayhead = true)
{
if (fadeOutTime < 0.0f)
{
fadeOutTime = 0.0f;
}
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.0f || this._fadeProgress <= 0.0f)
{
this._fadeProgress = 0.000001f; // Modify fade progress to different value.
}
foreach (var timeline in this._boneTimelines)
{
timeline.FadeOut();
}
foreach (var timeline in this._slotTimelines)
{
timeline.FadeOut();
}
foreach (var timeline in this._constraintTimelines)
{
timeline.FadeOut();
}
}
this.displayControl = false; //
this.fadeTotalTime = this._fadeProgress > 0.000001f ? fadeOutTime / this._fadeProgress : 0.0f;
this._fadeTime = this.fadeTotalTime * (1.0f - this._fadeProgress);
}
///
/// - Check if a specific bone mask is included.
///
/// - The bone name.
/// DragonBones 3.0
/// en_US
///
/// - 检查是否包含特定骨骼遮罩。
///
/// - 骨骼名称。
/// DragonBones 3.0
/// zh_CN
public bool ContainsBoneMask(string boneName)
{
return this._boneMask.Count == 0 || this._boneMask.IndexOf(boneName) >= 0;
}
///
/// - Add a specific bone mask.
///
/// - The bone name.
/// - Whether or not to add a mask to the bone's sub-bone.
/// DragonBones 3.0
/// en_US
///
/// - 添加特定的骨骼遮罩。
///
/// - 骨骼名称。
/// - 是否为该骨骼的子骨骼添加遮罩。
/// DragonBones 3.0
/// zh_CN
public void AddBoneMask(string boneName, bool recursive = true)
{
var currentBone = this._armature.GetBone(boneName);
if (currentBone == null)
{
return;
}
if (this._boneMask.IndexOf(boneName) < 0)
{
// Add mixing
this._boneMask.Add(boneName);
}
if (recursive)
{
// Add recursive mixing.
foreach (var bone in this._armature.GetBones())
{
if (this._boneMask.IndexOf(bone.name) < 0 && currentBone.Contains(bone))
{
this._boneMask.Add(bone.name);
}
}
}
this._timelineDirty = 1;
}
///
/// - Remove the mask of a specific bone.
///
/// - The bone name.
/// - Whether to remove the bone's sub-bone mask.
/// DragonBones 3.0
/// en_US
///
/// - 删除特定骨骼的遮罩。
///
/// - 骨骼名称。
/// - 是否删除该骨骼的子骨骼遮罩。
/// DragonBones 3.0
/// zh_CN
public void RemoveBoneMask(string boneName, bool recursive = true)
{
if (this._boneMask.Contains(boneName))
{
this._boneMask.Remove(boneName);
}
if (recursive)
{
var currentBone = this._armature.GetBone(boneName);
if (currentBone != null)
{
var bones = this._armature.GetBones();
if (this._boneMask.Count > 0)
{
// Remove recursive mixing.
foreach (var bone in bones)
{
if (this._boneMask.Contains(bone.name) && currentBone.Contains(bone))
{
this._boneMask.Remove(bone.name);
}
}
}
else
{
// Add unrecursive mixing.
foreach (var bone in bones)
{
if (bone == currentBone)
{
continue;
}
if (!currentBone.Contains(bone))
{
this._boneMask.Add(bone.name);
}
}
}
}
}
this._timelineDirty = 1;
}
///
/// - Remove all bone masks.
///
/// DragonBones 3.0
/// en_US
///
/// - 删除所有骨骼遮罩。
///
/// DragonBones 3.0
/// zh_CN
public void RemoveAllBoneMask()
{
this._boneMask.Clear();
this._timelineDirty = 1;
}
///
/// - Whether the animation state is fading in.
///
/// DragonBones 5.1
/// en_US
///
/// - 是否正在淡入。
///
/// DragonBones 5.1
/// zh_CN
public bool isFadeIn
{
get { return this._fadeState < 0; }
}
///
/// - Whether the animation state is fading out.
///
/// DragonBones 5.1
/// en_US
///
/// - 是否正在淡出。
///
/// DragonBones 5.1
/// zh_CN
public bool isFadeOut
{
get { return this._fadeState > 0; }
}
///
/// - Whether the animation state is fade completed.
///
/// DragonBones 5.1
/// en_US
///
/// - 是否淡入或淡出完毕。
///
/// DragonBones 5.1
/// zh_CN
public bool isFadeComplete
{
get { return this._fadeState == 0; }
}
///
/// - Whether the animation state is playing.
///
/// DragonBones 3.0
/// en_US
///
/// - 是否正在播放。
///
/// DragonBones 3.0
/// zh_CN
public bool isPlaying
{
get { return (this._playheadState & 2) != 0 && this._actionTimeline.playState <= 0; }
}
///
/// - Whether the animation state is play completed.
///
/// DragonBones 3.0
/// en_US
///
/// - 是否播放完毕。
///
/// DragonBones 3.0
/// zh_CN
public bool isCompleted
{
get { return this._actionTimeline.playState > 0; }
}
///
/// - The times has been played.
///
/// DragonBones 3.0
/// en_US
///
/// - 已经循环播放的次数。
///
/// DragonBones 3.0
/// zh_CN
public int currentPlayTimes
{
get { return this._actionTimeline.currentPlayTimes; }
}
///
/// - The total time. (In seconds)
///
/// DragonBones 3.0
/// en_US
///
/// - 总播放时间。 (以秒为单位)
///
/// DragonBones 3.0
/// zh_CN
public float totalTime
{
get { return this._duration; }
}
///
/// - The time is currently playing. (In seconds)
///
/// DragonBones 3.0
/// en_US
///
/// - 当前播放的时间。 (以秒为单位)
///
/// DragonBones 3.0
/// zh_CN
public float currentTime
{
get { return this._actionTimeline.currentTime; }
set
{
var currentPlayTimes = this._actionTimeline.currentPlayTimes - (this._actionTimeline.playState > 0 ? 1 : 0);
if (value < 0.0f || this._duration < value)
{
value = (value % this._duration) + currentPlayTimes * this._duration;
if (value < 0.0f)
{
value += this._duration;
}
}
if (this.playTimes > 0 && currentPlayTimes == this.playTimes - 1 && value == this._duration)
{
value = this._duration - 0.000001f;
}
if (this._time == value)
{
return;
}
this._time = value;
this._actionTimeline.SetCurrentTime(this._time);
if (this._zOrderTimeline != null)
{
this._zOrderTimeline.playState = -1;
}
foreach (var timeline in this._boneTimelines)
{
timeline.playState = -1;
}
foreach (var timeline in this._slotTimelines)
{
timeline.playState = -1;
}
}
}
}
///
///
internal class BonePose : BaseObject
{
public readonly TransformDB current = new TransformDB();
public readonly TransformDB delta = new TransformDB();
public readonly TransformDB result = new TransformDB();
protected override void _OnClear()
{
this.current.Identity();
this.delta.Identity();
this.result.Identity();
}
}
///
///
internal class BlendState
{
public bool dirty;
public int layer;
public float leftWeight;
public float layerWeight;
public float blendWeight;
///
/// -1: First blending, 0: No blending, 1: Blending.
///
public int Update(float weight, int p_layer)
{
if (this.dirty)
{
if (this.leftWeight > 0.0f)
{
if (this.layer != p_layer)
{
if (this.layerWeight >= this.leftWeight)
{
this.leftWeight = 0.0f;
return 0;
}
else
{
this.layer = p_layer;
this.leftWeight -= this.layerWeight;
this.layerWeight = 0.0f;
}
}
}
else
{
return 0;
}
weight *= this.leftWeight;
this.layerWeight += weight;
this.blendWeight = weight;
return 2;
}
this.dirty = true;
this.layer = p_layer;
this.layerWeight = weight;
this.leftWeight = 1.0f;
this.blendWeight = weight;
return 1;
}
public void Clear()
{
this.dirty = false;
this.layer = 0;
this.leftWeight = 0.0f;
this.layerWeight = 0.0f;
this.blendWeight = 0.0f;
}
}
}