import { Texture } from "@pixi/core" ; import { Ticker , UPDATE_PRIORITY } from "@pixi/ticker" ; export interface IFrameObject { texture : Texture ; time : number ; } export interface ITextureAnimationTarget { texture : Texture ; animState : AnimationState ; } export class AnimationState { texture : Texture ; _textures : Array < Texture > = null ; _durations : Array < number > = null ; _autoUpdate : boolean ; animationSpeed = 1 ; _target : ITextureAnimationTarget ; loop = true ; onComplete ? : ( ) => void ; onFrameChange ? : ( currentFrame : number ) => void ; onLoop ? : ( ) => void ; _currentTime = 0 ; playing = false ; constructor ( textures , autoUpdate ? ) { this . texture = textures [ 0 ] instanceof Texture ? textures [ 0 ] as Texture : ( textures [ 0 ] as IFrameObject ) . texture ; this . textures = textures as Array < Texture > ; this . _autoUpdate = autoUpdate !== false ; } /**
     * Stops the AnimatedSprite
     *
     */ stop ( ) { if ( ! this . playing ) { return ; } this . playing = false ; if ( this . _autoUpdate ) { Ticker . shared . remove ( this . update , this ) ; } } /**
     * Plays the AnimatedSprite
     *
     */ play ( ) { if ( this . playing ) { return ; } this . playing = true ; if ( this . _autoUpdate ) { Ticker . shared . add ( this . update , this , UPDATE_PRIORITY . HIGH ) ; } } param { number } frameNumber gotoAndStop ( frameNumber ) { this . stop ( ) ; const previousFrame = this . currentFrame ; this . _currentTime = frameNumber ; if ( previousFrame !== this . currentFrame ) { this . updateTexture ( ) ; } } param { number } frameNumber gotoAndPlay ( frameNumber ) { const previousFrame = this . currentFrame ; this . _currentTime = frameNumber ; if ( previousFrame !== this . currentFrame ) { this . updateTexture ( ) ; } this . play ( ) ; } private param { number } deltaTime update ( deltaTime ) { const elapsed = this . animationSpeed * deltaTime ; const previousFrame = this . currentFrame ; if ( this . _durations !== null ) { let lag = this . _currentTime % 1 * this . _durations [ this . currentFrame ] ; lag += elapsed / 60 * 1000 ; while ( lag < 0 ) { this . _currentTime -- ; lag += this . _durations [ this . currentFrame ] ; } let sign = this . animationSpeed * deltaTime ; if ( sign < 0 ) sign = - 1 ; else if ( sign > 0 ) sign = 1 ; this . _currentTime = Math . floor ( this . _currentTime ) ; while ( lag >= this . _durations [ this . currentFrame ] ) { lag -= this . _durations [ this . currentFrame ] * sign ; this . _currentTime += sign ; } this . _currentTime += lag / this . _durations [ this . currentFrame ] ; } else { this . _currentTime += elapsed ; } if ( this . _currentTime < 0 && ! this . loop ) { this . gotoAndStop ( 0 ) ; if ( this . onComplete ) { this . onComplete ( ) ; } } else if ( this . _currentTime >= this . _textures . length && ! this . loop ) { this . gotoAndStop ( this . _textures . length - 1 ) ; if ( this . onComplete ) { this . onComplete ( ) ; } } else if ( previousFrame !== this . currentFrame ) { if ( this . loop && this . onLoop ) { if ( this . animationSpeed > 0 && this . currentFrame < previousFrame ) { this . onLoop ( ) ; } else if ( this . animationSpeed < 0 && this . currentFrame > previousFrame ) { this . onLoop ( ) ; } } this . updateTexture ( ) ; } } private updateTexture ( ) { this . texture = this . _textures [ this . currentFrame ] ; if ( this . _target ) { this . _target . texture = this . texture ; } if ( this . onFrameChange ) { this . onFrameChange ( this . currentFrame ) ; } } bind ( target ) { this . _target = target ; target . animState = this ; } static param { string [ ] } frames return { AnimatedSprite } static fromFrames ( frames ) { const textures = [ ] ; for ( let i = 0 ; i < frames . length ; ++ i ) { textures . push ( Texture . from ( frames [ i ] ) ) ; } return new AnimationState ( textures ) ; } static param { string [ ] } images return { AnimatedSprite } static fromImages ( images ) { const textures = [ ] ; for ( let i = 0 ; i < images . length ; ++ i ) { textures . push ( Texture . from ( images [ i ] ) ) ; } return new AnimationState ( textures ) ; } readonly member default get totalFrames ( ) { return this . _textures . length ; } member get textures ( ) : Texture [ ] | IFrameObject [ ] { return this . _textures ; } set textures ( value ) { if ( value [ 0 ] instanceof Texture ) { this . _textures = value as Texture [ ] ; this . _durations = null ; } else { this . _textures = [ ] ; this . _durations = [ ] ; for ( let i = 0 ; i < value . length ; i ++ ) { const val = ( value as any ) [ i ] ; this . _textures . push ( val . texture ) ; this . _durations . push ( val . time ) ; } } this . gotoAndStop ( 0 ) ; this . updateTexture ( ) ; } get currentFrame ( ) { let currentFrame = Math . floor ( this . _currentTime ) % this . _textures . length ; if ( currentFrame < 0 ) { currentFrame += this . _textures . length ; } return currentFrame ; } }