@awayjs/graphics
Version:
AwayJS graphics classes
166 lines (134 loc) • 4.51 kB
text/typescript
import { AnimationStateEvent } from '../../events/AnimationStateEvent';
import { AnimationClipNodeBase } from '../nodes/AnimationClipNodeBase';
import { AnimatorBase } from '../AnimatorBase';
import { AnimationStateBase } from './AnimationStateBase';
/**
*
*/
export class AnimationClipState extends AnimationStateBase {
private _animationClipNode: AnimationClipNodeBase;
private _animationStatePlaybackComplete: AnimationStateEvent;
public _pBlendWeight: number;
public _pCurrentFrame: number;
public _pNextFrame: number;
public _pOldFrame: number;
public _pTimeDir: number;
public _pFramesDirty: boolean = true;
/**
* Returns a fractional value between 0 and 1 representing the blending ratio of the current playhead position
* between the current frame (0) and next frame (1) of the animation.
*
* @see #currentFrame
* @see #nextFrame
*/
public get blendWeight(): number {
if (this._pFramesDirty)
this._pUpdateFrames();
return this._pBlendWeight;
}
/**
* Returns the current frame of animation in the clip based on the internal playhead position.
*/
public get currentFrame(): number {
if (this._pFramesDirty)
this._pUpdateFrames();
return this._pCurrentFrame;
}
/**
* Returns the next frame of animation in the clip based on the internal playhead position.
*/
public get nextFrame(): number {
if (this._pFramesDirty)
this._pUpdateFrames();
return this._pNextFrame;
}
constructor(animator: AnimatorBase, animationClipNode: AnimationClipNodeBase) {
super(animator, animationClipNode);
this._animationClipNode = animationClipNode;
}
/**
* @inheritDoc
*/
public update(time: number): void {
if (!this._animationClipNode.looping) {
if (time > this._pStartTime + this._animationClipNode.totalDuration)
time = this._pStartTime + this._animationClipNode.totalDuration; else if (time < this._pStartTime)
time = this._pStartTime;
}
if (this._pTime == time - this._pStartTime)
return;
this._pUpdateTime(time);
}
/**
* @inheritDoc
*/
public phase(value: number): void {
const time: number = value * this._animationClipNode.totalDuration + this._pStartTime;
if (this._pTime == time - this._pStartTime)
return;
this._pUpdateTime(time);
}
/**
* @inheritDoc
*/
public _pUpdateTime(time: number): void {
this._pFramesDirty = true;
this._pTimeDir = (time - this._pStartTime > this._pTime) ? 1 : -1;
super._pUpdateTime(time);
}
/**
* Updates the nodes internal playhead to determine the current and next animation frame, and the blendWeight between the two.
*
* @see #currentFrame
* @see #nextFrame
* @see #blendWeight
*/
public _pUpdateFrames(): void {
this._pFramesDirty = false;
const looping: boolean = this._animationClipNode.looping;
const totalDuration: number = this._animationClipNode.totalDuration;
const lastFrame: number = this._animationClipNode.lastFrame;
let time: number = this._pTime;
//trace("time", time, totalDuration)
if (looping && (time >= totalDuration || time < 0)) {
time %= totalDuration;
if (time < 0)
time += totalDuration;
}
if (!looping && time >= totalDuration) {
this.notifyPlaybackComplete();
this._pCurrentFrame = lastFrame;
this._pNextFrame = lastFrame;
this._pBlendWeight = 0;
} else if (!looping && time <= 0) {
this._pCurrentFrame = 0;
this._pNextFrame = 0;
this._pBlendWeight = 0;
} else if (this._animationClipNode.fixedFrameRate) {
const t: number = time / totalDuration * lastFrame;
this._pCurrentFrame = Math.floor(t);
this._pBlendWeight = t - this._pCurrentFrame;
this._pNextFrame = this._pCurrentFrame + 1;
} else {
this._pCurrentFrame = 0;
this._pNextFrame = 0;
let dur: number = 0, frameTime: number;
const durations: Array<number> = this._animationClipNode.durations;
do {
frameTime = dur;
dur += durations[this._pNextFrame];
this._pCurrentFrame = this._pNextFrame++;
} while (time > dur);
if (this._pCurrentFrame == lastFrame) {
this._pCurrentFrame = 0;
this._pNextFrame = 1;
}
this._pBlendWeight = (time - frameTime) / durations[this._pCurrentFrame];
}
}
private notifyPlaybackComplete(): void {
if (this._animationStatePlaybackComplete == null)
this._animationStatePlaybackComplete = new AnimationStateEvent(AnimationStateEvent.PLAYBACK_COMPLETE, this._pAnimator, this, this._animationClipNode);
this._animationClipNode.dispatchEvent(this._animationStatePlaybackComplete);
}
}