import { Graphic, GraphicOptions } from './Graphic';
import { ExcaliburGraphicsContext } from './Context/ExcaliburGraphicsContext';
import { GetSpriteOptions, SpriteSheet } from './SpriteSheet';
import { EventEmitter } from '../EventEmitter';
export interface HasTick {
    /**
     *
     * @param elapsed The amount of real world time in milliseconds that has elapsed that must be updated in the animation
     * @param idempotencyToken Optional idempotencyToken prevents a ticking animation from updating twice per frame
     */
    tick(elapsed: number, idempotencyToken?: number): void;
}
export declare enum AnimationDirection {
    /**
     * Animation is playing forwards
     */
    Forward = "forward",
    /**
     * Animation is playing backwards
     */
    Backward = "backward"
}
export declare enum AnimationStrategy {
    /**
     * Animation ends without displaying anything
     */
    End = "end",
    /**
     * Animation loops to the first frame after the last frame
     */
    Loop = "loop",
    /**
     * Animation plays to the last frame, then backwards to the first frame, then repeats
     */
    PingPong = "pingpong",
    /**
     * Animation ends stopping on the last frame
     */
    Freeze = "freeze"
}
/**
 * Frame of animation
 */
export interface Frame {
    /**
     * Optionally specify a graphic to show, no graphic shows an empty frame
     */
    graphic?: Graphic;
    /**
     * Optionally specify the number of ms the frame should be visible, overrides the animation duration (default 100 ms)
     */
    duration?: number;
}
export interface FrameEvent extends Frame {
    frameIndex: number;
}
/**
 * Animation options for building an animation via constructor.
 */
export interface AnimationOptions {
    /**
     * List of frames in the order you wish to play them
     */
    frames: Frame[];
    /**
     * Optionally set a positive speed multiplier on the animation.
     *
     * By default 1, meaning 1x speed. If set to 2, it will play the animation twice as fast.
     */
    speed?: number;
    /**
     * Optionally reverse the direction of play
     */
    reverse?: boolean;
    /**
     * Optionally specify a default frame duration in ms (Default is 100)
     */
    frameDuration?: number;
    /**
     * Optionally specify a total duration of the animation in ms to calculate each frame's duration
     */
    totalDuration?: number;
    /**
     * Optionally specify the {@apilink AnimationStrategy} for the Animation
     */
    strategy?: AnimationStrategy;
}
export type AnimationEvents = {
    frame: FrameEvent;
    loop: Animation;
    end: Animation;
};
export declare const AnimationEvents: {
    Frame: string;
    Loop: string;
    End: string;
};
export interface FromSpriteSheetOptions {
    /**
     * {@apilink SpriteSheet} to source the animation frames from
     */
    spriteSheet: SpriteSheet;
    /**
     * The list of (x, y) positions of sprites in the {@apilink SpriteSheet} of each frame, for example (0, 0)
     * is the the top left sprite, (0, 1) is the sprite directly below that, and so on.
     *
     * You may optionally specify a duration for the frame in milliseconds as well, this will override
     * the default duration.
     */
    frameCoordinates: {
        x: number;
        y: number;
        duration?: number;
        options?: GetSpriteOptions;
    }[];
    /**
     * Optionally specify a default duration for frames in milliseconds
     * @deprecated use `durationPerFrame`
     */
    durationPerFrameMs?: number;
    /**
     * Optionally specify a default duration for frames in milliseconds
     */
    durationPerFrame?: number;
    /**
     * Optionally set a positive speed multiplier on the animation.
     *
     * By default 1, meaning 1x speed. If set to 2, it will play the animation twice as fast.
     */
    speed?: number;
    /**
     * Optionally specify the animation strategy for this animation, by default animations loop {@apilink AnimationStrategy.Loop}
     */
    strategy?: AnimationStrategy;
    /**
     * Optionally specify the animation should be reversed
     */
    reverse?: boolean;
}
/**
 * Create an Animation given a list of {@apilink Frame | `frames`} in {@apilink AnimationOptions}
 *
 * To create an Animation from a {@apilink SpriteSheet}, use {@apilink Animation.fromSpriteSheet}
 */
export declare class Animation extends Graphic implements HasTick {
    private static _LOGGER;
    events: EventEmitter<AnimationEvents>;
    frames: Frame[];
    strategy: AnimationStrategy;
    frameDuration: number;
    private _idempotencyToken;
    private _firstTick;
    private _currentFrame;
    private _timeLeftInFrame;
    private _pingPongDirection;
    private _done;
    private _playing;
    private _speed;
    constructor(options: GraphicOptions & AnimationOptions);
    clone(): Animation;
    get width(): number;
    get height(): number;
    /**
     * Create an Animation from a {@apilink SpriteSheet}, a list of indices into the sprite sheet, a duration per frame
     * and optional {@apilink AnimationStrategy}
     *
     * Example:
     * ```typescript
     * const spriteSheet = SpriteSheet.fromImageSource({...});
     *
     * const anim = Animation.fromSpriteSheet(spriteSheet, range(0, 5), 200, AnimationStrategy.Loop);
     * ```
     * @param spriteSheet ex.SpriteSheet
     * @param spriteSheetIndex 0 based index from left to right, top down (row major order) of the ex.SpriteSheet
     * @param durationPerFrame duration per frame in milliseconds
     * @param strategy Optional strategy, default AnimationStrategy.Loop
     */
    static fromSpriteSheet(spriteSheet: SpriteSheet, spriteSheetIndex: number[], durationPerFrame: number, strategy?: AnimationStrategy): Animation;
    /**
     * Create an {@apilink Animation} from a {@apilink SpriteSheet} given a list of coordinates
     *
     * Example:
     * ```typescript
     * const spriteSheet = SpriteSheet.fromImageSource({...});
     *
     * const anim = Animation.fromSpriteSheetCoordinates({
     *  spriteSheet,
     *  frameCoordinates: [
     *    {x: 0, y: 5, duration: 100, options { flipHorizontal: true }},
     *    {x: 1, y: 5, duration: 200},
     *    {x: 2, y: 5},
     *    {x: 3, y: 5}
     *  ],
     *  strategy: AnimationStrategy.PingPong
     * });
     * ```
     * @param options
     * @returns Animation
     */
    static fromSpriteSheetCoordinates(options: FromSpriteSheetOptions): Animation;
    /**
     * Current animation speed
     *
     * 1 meaning normal 1x speed.
     * 2 meaning 2x speed and so on.
     */
    get speed(): number;
    /**
     * Current animation speed
     *
     * 1 meaning normal 1x speed.
     * 2 meaning 2x speed and so on.
     */
    set speed(val: number);
    /**
     * Returns the current Frame of the animation
     *
     * Use {@apilink Animation.currentFrameIndex} to get the frame number and
     * {@apilink Animation.goToFrame} to set the current frame index
     */
    get currentFrame(): Frame | null;
    /**
     * Returns the current frame index of the animation
     *
     * Use {@apilink Animation.currentFrame} to grab the current {@apilink Frame} object
     */
    get currentFrameIndex(): number;
    /**
     * Returns the amount of time in milliseconds left in the current frame
     */
    get currentFrameTimeLeft(): number;
    /**
     * Returns `true` if the animation is playing
     */
    get isPlaying(): boolean;
    private _reversed;
    get isReversed(): boolean;
    /**
     * Reverses the play direction of the Animation, this preserves the current frame
     */
    reverse(): void;
    /**
     * Returns the current play direction of the animation
     */
    get direction(): AnimationDirection;
    /**
     * Plays or resumes the animation from the current frame
     */
    play(): void;
    /**
     * Pauses the animation on the current frame
     */
    pause(): void;
    /**
     * Reset the animation back to the beginning, including if the animation were done
     */
    reset(): void;
    /**
     * Returns `true` if the animation can end
     */
    get canFinish(): boolean;
    /**
     * Returns `true` if the animation is done, for looping type animations
     * `ex.AnimationStrategy.PingPong` and `ex.AnimationStrategy.Loop` this will always return `false`
     *
     * See the `ex.Animation.canFinish()` method to know if an animation type can end
     */
    get done(): boolean;
    /**
     * Jump the animation immediately to a specific frame if it exists
     *
     * Optionally specify an override for the duration of the frame, useful for
     * keeping multiple animations in sync with one another.
     * @param frameNumber
     * @param duration
     */
    goToFrame(frameNumber: number, duration?: number): void;
    private _nextFrame;
    /**
     * Called internally by Excalibur to update the state of the animation potential update the current frame
     * @param elapsed Milliseconds elapsed
     * @param idempotencyToken Prevents double ticking in a frame by passing a unique token to the frame
     */
    tick(elapsed: number, idempotencyToken?: number): void;
    protected _drawImage(ctx: ExcaliburGraphicsContext, x: number, y: number): void;
}
