game_actor_animation_actor_animation.js

import PositionTrack from "./track/position_track.js";
import RotationTrack from "./track/rotation_track.js";
import ScaleTrack from "./track/scale_track.js";

/**
 * @module ActorAnimation
 * @fileoverview Contains ActorAnimation class.
 */

/**
 * @class ActorAnimation
 * Animates actor transformations.
 */
class ActorAnimation {
    /**
     * Create a new actor animation.
     * @param {ActorAnimationTrack[]} tracks List of tracks to add
     * @param {number} length Duration of animation
     * @param {boolean} play Whether to play on adding to actor (true by default)
     * @param {boolean} once Whether to delete after completion (true by default)
     * @param {boolean} loop Whether to loop after completion (false by default)
     * @constructor
     */
    constructor({
        tracks = [],
        length = 1,
        play = true,
        once = true,
        loop = false
    } = {}) {
        this._actor = null;

        this._tracks = [...tracks];

        this._current = 0;
        this._length = length;

        this._running = false;
        this._playOnAdd = play;

        this.once = once;
        this.loop = loop;

        this._done = false;
    }

    /**
     * Update all tracks in the animations.
     * @param {number} elapsed Time since last update cycle in seconds
     */
    update(elapsed) {
        if (this._actor === null)
            return;
        if (!this._running)
            return;

        this._current += elapsed;
        if (this._current >= this._length) {
            this._current = this._length;
            this._running = false;
            this._done = true;
        }

        const progress = this._current / this._length;

        for (const track of this._tracks)
            track.update(this._actor, progress);

        if (!this._running && this.loop) {
            this.running = true;
            this._current = 0;
            this._done = false;
        }
    }


    //
    // Getters
    //

    /**
     * Get the actor the animation is attached to.
     * @returns {Actor} Actor using animation
     */
    get actor() {
        return this._actor;
    }

    /**
     * Check if the animation has completed.
     * @returns {boolean} Whether animation has completed
     */
    get done() {
        return this._done;
    }

    /**
     * Check if the animation has any position tracks.
     * @returns {boolean} Whether animation has at least one position track
     */
    hasPosition() {
        for (const track of this._tracks)
            if (track instanceof PositionTrack)
                return true;

        return false;
    }

    /**
     * Check if the animation has any rotation tracks.
     * @returns {boolean} Whether animation has at least one rotation track
     */
    hasRotation() {
        for (const track of this._tracks)
            if (track instanceof RotationTrack)
                return true;

        return false;
    }

    /**
     * Check if the animation has any scale tracks.
     * @returns {boolean} Whether animation has at least one scale track
     */
    hasScale() {
        for (const track of this._tracks)
            if (track instanceof ScaleTrack)
                return true;

        return false;
    }


    //
    // Setters
    //

    /**
     * Set the actor for the animation.
     * @param {Actor} actor Actor to attach to
     */
    set actor(actor) {
        this._actor = actor;

        if (this._playOnAdd)
            this.play();
    }


    //
    // Controls
    //

    /**
     * Start the animation.
     * @param {number} progress Percentage to start playback at (0 - 1, 0 by default)
     */
    play(progress = 0) {
        this._current = this._length * progress;

        this._running = true;
    }

    /**
     * Stop playing the animation.
     */
    stop() {
        this._running = false;
    }
}

export default ActorAnimation;