/
SmoothSkeletonAnimator.as
178 lines (153 loc) · 4.64 KB
/
SmoothSkeletonAnimator.as
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package away3d.animators
{
import away3d.animators.skeleton.Skeleton;
import away3d.animators.data.AnimationSequenceBase;
import away3d.animators.data.SkeletonAnimationSequence;
import away3d.animators.nodes.SkeletonNaryLERPNode;
import away3d.animators.nodes.SkeletonTimelineClipNode;
import away3d.animators.nodes.SkeletonTreeNode;
import away3d.arcane;
use namespace arcane;
/**
* AnimationSequenceController provides a controller for single clip-based animation sequences (fe: md5, md5anim).
*/
public class SmoothSkeletonAnimator extends SkeletonAnimator
{
private var _clips : Array;
private var _activeClipIndex : int = -1;
private var _fadeOutClips : Vector.<int>;
private var _fadeOutSpeeds : Vector.<Number>;
private var _lerpNode : SkeletonNaryLERPNode;
private var _crossFadeTime : Number;
private var _mainWeight : Number = 1;
/**
* Creates a new AnimationSequenceController object.
*/
public function SmoothSkeletonAnimator(skeletonAnimationSet:SkeletonAnimationSet, skeleton : Skeleton, forceCPU : Boolean = false)
{
super(skeletonAnimationSet, skeleton, forceCPU);
_clips = [];
_fadeOutClips = new Vector.<int>();
_fadeOutSpeeds = new Vector.<Number>();
}
override protected function createBlendTree() : SkeletonTreeNode
{
_lerpNode = new SkeletonNaryLERPNode();
return _lerpNode;
}
/**
* Plays a sequence with a given name. If the sequence is not found, it may not be loaded yet, and it will retry every frame.
* @param sequenceName The name of the clip to be played.
*/
public function play(sequenceName : String, crossFadeTime : Number = 0) : void
{
_crossFadeTime = crossFadeTime;
var clip : SkeletonTimelineClipNode = _clips[sequenceName];
if (!clip)
throw new Error("Clip not found!");
if (clip.duration == 0)
throw new Error("Invalid clip: duration is 0!");
if (crossFadeTime == 0)
setActiveClipDirect(clip);
else
setActiveClipWithFadeOut(clip);
start();
}
private function setActiveClipDirect(clip : SkeletonTimelineClipNode) : void
{
clearFadeOuts();
clip.reset();
_activeClipIndex = _lerpNode.getInputIndex(clip);
}
private function clearFadeOuts() : void
{
var len : uint = _fadeOutClips.length;
var weights : Vector.<Number> = _lerpNode.blendWeights;
for (var i : uint = 0; i < len; ++i)
weights[_fadeOutClips[i]] = 0;
if (_activeClipIndex != -1)
weights[_activeClipIndex] = 0;
_fadeOutClips.length = 0;
_fadeOutSpeeds.length = 0;
}
private function setActiveClipWithFadeOut(clip : SkeletonTimelineClipNode) : void
{
addActiveClipToFadeOuts();
clip.reset();
_activeClipIndex = _lerpNode.getInputIndex(clip);
removeActiveClipFromFadeOuts();
}
private function addActiveClipToFadeOuts() : void
{
if (_activeClipIndex != -1) {
_fadeOutClips.push(_activeClipIndex);
_fadeOutSpeeds.push(_mainWeight / (_crossFadeTime * 1000));
}
}
private function removeActiveClipFromFadeOuts() : void
{
var i : int = _fadeOutClips.indexOf(_activeClipIndex);
if (i != -1) {
_fadeOutClips.splice(i, 1);
_fadeOutSpeeds.splice(i, 1);
}
}
public function hasSequence(sequenceName:String):Boolean
{
if(_clips[sequenceName] == null) return false;
return true;
}
/**
* Adds a sequence to the controller.
*/
public function addSequence(sequence : SkeletonAnimationSequence) : void
{
var node : SkeletonTimelineClipNode = new SkeletonTimelineClipNode();
_clips[sequence.name] = node;
node.clip = sequence;
_lerpNode.addInput(node);
}
/**
* @inheritDoc
* @private
*/
override protected function updateAnimation(realDT : Number, scaledDT : Number) : void
{
updateWeights(realDT);
_lerpNode.time += scaledDT / _lerpNode.duration;
super.updateAnimation(realDT, scaledDT);
}
private function updateWeights(dt : Number) : void
{
var weight : Number;
var len : uint = _fadeOutClips.length;
var weights : Vector.<Number> = _lerpNode.blendWeights;
var total : Number = 0;
var speed : Number;
var index : uint;
for (var i : uint = 0; i < len;) {
index = _fadeOutClips[i];
speed = _fadeOutSpeeds[i] * dt;
weight = weights[index] - speed;
if (weight <= 0) {
weight = 0;
_fadeOutClips.splice(i, 1);
_fadeOutSpeeds.splice(i, 1);
--len;
}
else ++i;
weights[index] = weight;
total += weight;
}
weights[_activeClipIndex] = _mainWeight = 1 - total;
_lerpNode.updateWeights(weights);
}
/**
* Retrieves a sequence with a given name.
*/
public function getSequence(sequenceName : String) : AnimationSequenceBase
{
return _clips[sequenceName].clip;
}
}
}