app.js

import Space from "./game/space/space.js";
import EventHandler from "./event/event_handler.js";

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

/**
 * @class
 * Main application. Everything else in the overall application
 * is a child of this object.
 */
class App {
    /**
     * Construct a new App.
     * @param {string} canvasID The ID of the canvas to draw on
     * @constructor
     */
    constructor(canvasID) {
        this.canvasID = canvasID;
        /// The canvas to draw on
        this.canvas = document.getElementById(canvasID);
        /// The 2D canvas context to draw on
        this.ctx = this.canvas.getContext("2d");

        // Set the canvas' size to the page's size
        if ($$.flags.fillScreen) {
            this.canvas.width = window.innerWidth;
            this.canvas.height = window.innerHeight;
        }

        $$.width = this.canvas.offsetWidth;
        $$.height = this.canvas.offsetHeight;

        this.canvas.width = $$.width;
        this.canvas.height = $$.height;

        /// The client for communication with a server
        this.client = null;

        /// The current space
        this._space = null;

        /// The last time that update() was called
        this.lastTime = 0;

        this._events = new EventHandler();
    }

    /**
     * Initialize the App and its child components.
     */
    init() {
        addEventListener("resize", (event) => {
            if ($$.flags.fillScreen) {
                this.canvas.offsetWidth = window.innerWidth;
                this.canvas.offsetHeight = window.innerHeight;
            }

            $$.width = this.canvas.offsetWidth;
            $$.height = this.canvas.offsetHeight;

            this.canvas.getContext("2d").imageSmoothingEnabled = false;
        });

        document.getElementById(this.canvasID).addEventListener("contextmenu", (e) => {
            e.preventDefault();
        });

        $$.cookies.init();

        this._space = new Space(this);
        $$.spaces.add("default", this._space);
    }

    /**
     * Start up the application.
     */
    start() {
        this.init();

        requestAnimationFrame(this.loop.bind(this));
    }

    /**
     * Perform the update loop and call update().
     * @param {number} timeStamp The current time
     */
    loop(timeStamp) {
        let elapsed = timeStamp - this.lastTime;
        this.lastTime = timeStamp;

        if (document.hasFocus() || !$$.flags.pauseOnBlur) {
            if ($$.flags.timeScale > 0)
                this.update(elapsed / 1000 * $$.flags.timeScale);
            this.draw();
        }

        requestAnimationFrame(this.loop.bind(this));
    }

    /**
     * Update the App and its children.
     * @param {number} elapsed Time since last update
     */
    update(elapsed) {
        $$.tasks.update(elapsed);

        if (this._space !== null)
            this._space.update(elapsed);
    }

    /**
     * Draw the App and its children.
     */
    draw() {
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.width);
        this.ctx.imageSmoothingEnabled = false;
        if (this._space != null)
            this._space.draw(this.ctx);
    }


    //
    // Getters
    //

    /**
     * Get the app's event handler.
     * @returns {EventHandler} Event handler
     */
    get events() {
        return this._events;
    }

    /**
     * Get the currently running space.
     * @returns {Space|null} Current space
     */
    get space() {
        return this._space;
    }


    //
    // Setters
    //

    /**
     * Set the currently running space.
     * @param {string|Space} space Space to run
     */
    set space(space) {
        if (typeof space === "string")
            this._space = $$.spaces.get(space);
        else if (space instanceof Space)
            this._space = space;
    }
}

export default App;