API Docs for: v0.1.0
Show:

File: src\game\Game.js

var StateManager = require('./StateManager'),
    EventEmitter = require('../utils/EventEmitter'),
    Cache = require('../utils/Cache'),
    Clock = require('../utils/Clock'),
    SpritePool = require('../utils/SpritePool'),
    Loader = require('../loader/Loader'),
    InputManager = require('../input/InputManager'),
    AudioManager = require('../audio/AudioManager'),
    Vector = require('../math/Vector'),
    utils = require('../utils/utils'),
    support = require('../utils/support'),
    inherit = require('../utils/inherit'),
    PIXI = require('../vendor/pixi'),
    C = require('../constants');

/**
 * Main game object, controls the entire instance of the game
 *
 * @class Game
 * @extends Object
 * @uses EventEmitter
 * @constructor
 * @param container {DOMElement|String} The container for the new canvas we will create for the game, or the ID of one
 * @param settings {Object} All the settings for the game instance
 * @param settings.width {Number} The width of the viewport
 * @param settings.height {Number} The height of the viewport
 * @param [settings.renderer=RENDERER.AUTO] {String} The renderer to use either RENDERER.AUTO, RENDERER.CANVAS, or RENDERER.WEBGL
 * @param [settings.transparent=false] {Boolean} Should the render element have a transparent background
 * @param [settings.background='#FFF'] {Number} The background color of the stage
 * @param [settings.antialias=true] {Boolean} Anti-alias graphics (in WebGL this helps with edges, in Canvas2D it retains pixel-art quality)
 * @param [settings.canvas] {DOMElement} The canvas to render into, if not specified one is created
 */
var Game = function(container, settings) {
    EventEmitter.call(this);

    //setup settings defaults
    settings = settings || {};
    settings.width = settings.width || 800;
    settings.height = settings.height || 600;
    settings.renderer = settings.renderer || C.RENDERER.AUTO;
    settings.transparent = settings.transparent || false;
    settings.background = settings.background || '#FFF';
    settings.antialias = settings.antialias !== undefined ? settings.antialias : true;
    settings.canvas = settings.canvas || null; //passing null to renderer, lets the renderer make one

    /**
     * The domElement that we are putting our rendering canvas into (the container)
     *
     * @property container
     * @type DOMELement
     * @readOnly
     */
    this.container = typeof container === 'string' ? document.getElementById(container) : container;

    if(!this.container)
        this.container = document.body;

    /**
     * The width of the render viewport
     *
     * @property width
     * @type Number
     * @default 800
     */
    this.width = settings.width;

    /**
     * The height of the render viewport
     *
     * @property height
     * @type Number
     * @default 600
     */
    this.height = settings.height;

    /**
     * The method used to render values to the screen (either webgl, or canvas)
     *
     * @property renderMethod
     * @type String
     * @default RENDERER.AUTO
     */
    this.renderMethod = settings.renderer;

    /**
     * Whether the canvas has a transparent background or not
     *
     * @property transparent
     * @type Boolean
     * @default false
     */
    this.transparent = settings.transparent;

    /**
     * The background of the stage
     *
     * @property background
     * @type Boolean
     * @default false
     */
    this.background = settings.background;

    /**
     * Anti-alias graphics (in WebGL this helps with edges, in Canvas2D it retains pixel-art quality)
     *
     * @property antialias
     * @type Boolean
     * @default true
     */
    this.antialias = settings.antialias;

    /**
     * The canvas to render into
     *
     * @property canvas
     * @type HTMLCanvasElement
     */
    this.canvas = settings.canvas;

    /**
     * Raw rendering engine, the underlying PIXI renderer that draws for us
     *
     * @property renderer
     * @type PIXI.WebGLRenderer|PIXI.CanvasRenderer
     * @readOnly
     */
    this.renderer = this._createRenderer();

    /**
     * Raw PIXI.stage instance, the root of all things in the scene graph
     *
     * @property stage
     * @type PIXI.Stage
     * @readOnly
     */
    this.stage = new PIXI.Stage(this.background);

    /**
     * Clock instance for internal timing
     *
     * @property clock
     * @type Clock
     * @readOnly
     */
    this.clock = new Clock();

    /**
     * The audio manager for this game instance, used to play and control
     * all the audio in a game.
     *
     * @property audio
     * @type AudioManager
     * @readOnly
     */
    this.audio = new AudioManager(this);

    /**
     * The loader for this game instance, used to preload assets into the cache
     *
     * @property loader
     * @type Loader
     * @readOnly
     */
    this.load = new Loader(this);

    /**
     * Cache instance for storing/retrieving assets
     *
     * @property cache
     * @type Cache
     * @readOnly
     */
    this.cache = new Cache(this);

    /**
     * The input instance for this game
     *
     * @property input
     * @type InputManager
     * @readOnly
     */
    this.input = new InputManager(this);

    /**
     * The sprite pool to use to create registered entities
     *
     * @property spritepool
     * @type SpritePool
     * @readOnly
     */
    this.spritepool = new SpritePool(this);

    /**
     * The state manager, to switch between game states
     *
     * @property state
     * @type StateManager
     * @readOnly
     */
    this.state = new StateManager(this);

    /**
     * The offset for the viewport in the document
     *
     * @property offset
     * @type Vector
     * @readOnly
     */
    this.offset = new Vector();

    /**
     * Holds timing data for the previous loop
     *
     * @property timings
     * @type Object
     * @readOnly
     */
    this.timings = {};

    //pixi does some prevent default on mousedown, so we need to
    //make sure mousedown will focus the canvas or keyboard events break
    var view = this.canvas;
    if(!view.getAttribute('tabindex'))
        view.setAttribute('tabindex','1');

    view.focus();
    view.addEventListener('click', function() {
        view.focus();
    }, false);

    /**
     * Fired each frame after everything has updated, but just before rendering
     *
     * @event tick
     * @param dt {Number} The number of seconds passed since the last tick call (delta time)
     */
};

inherit(Game, Object, {
    /**
     * Creates the underlying renderer based on browser support. It will also set's `game.renderMethod` for a user
     * to be able to check.
     *
     * @method _createRenderer
     * @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} The renderer to use
     * @private
     */
    _createRenderer: function() {
        var method = this.renderMethod,
            render = null;

        //no support
        if(!support.webgl && !support.canvas) {
            throw new Error('Neither WebGL nor Canvas is supported by this browser!');
        }
        else if((method === C.RENDERER.WEBGL || method === C.RENDERER.AUTO) && support.webgl) {
            method = C.RENDERER.WEBGL;
            render = new PIXI.WebGLRenderer(this.width, this.height, this.canvas, this.transparent, this.antialias);
        }
        else if((method === C.RENDERER.CANVAS || method === C.RENDERER.AUTO) && support.canvas) {
            method = C.RENDERER.CANVAS;
            render = new PIXI.CanvasRenderer(this.width, this.height, this.canvas, this.transparent);
        }
        else {
            throw new Error('Your render method ("' + method + '") is not supported by this browser!');
        }

        //append the renderer view only if the user didn't pass their own
        if(!this.canvas) {
            this.container.appendChild(render.view);
            this.canvas = render.view;
        }

        this.offset = utils.getOffset(this.canvas);
        this.renderMethod = method;

        return render;
    },
    /**
     * Allows you to resize the game area.
     *
     * @method resize
     * @param width {Number} Width to resize to
     * @param height {Number} Height to resize to
     * @return {Game} Returns itself.
     * @chainable
     */
    resize: function(w, h) {
        this.renderer.resize(w, h);
        this.width = w;
        this.height = h;

        for(var i = 0, il = this.stage.children.length; i < il; ++i) {
            var o = this.stage.children[i];

            if(o.resize)
                o.resize(w, h);
        }

        return this;
    },
    /**
     * Requests that the browser go into fullscreen mode.
     *
     * @method requestFullscreen
     * @return {Game} Returns itself.
     * @chainable
     */
    requestFullscreen: function() {
        var elem = this.renderer.view;

        if(elem.requestFullscreen) {
            elem.requestFullscreen();
        } else if(elem.mozRequestFullScreen) {
            elem.mozRequestFullScreen();
        } else if(elem.webkitRequestFullscreen) {
            elem.webkitRequestFullscreen();
        }

        return this;
    },
    /**
     * Begins the render loop.
     *
     * @method render
     * @return {Game} Returns itself.
     * @chainable
     */
    render: function() {
        this.clock.start();
        this._tick();

        return this;
    },
    /**
     * The looping render tick.
     *
     * @method _tick
     * @private
     */
    _tick: function() {
        this.timings.tickStart = this.clock.now();

        //start render loop
        window.requestAnimFrame(this._tick.bind(this));

        var dt = this.clock.getDelta();

        this.timings.lastDelta = dt;

        //gather input from user
        this.timings.inputStart = this.clock.now();
        this.input.update(dt);
        this.timings.inputEnd = this.clock.now();

        //TODO: plugins
        //this.timings.pluginsStart = this.clock.now();
        //this.plugins.update(dt);
        //this.timings.pluginsEnd = this.clock.now();

        //update this game state
        this.timings.stateStart = this.clock.now();
        this.state.active.update(dt);
        this.timings.stateEnd = this.clock.now();

        this.timings.userFuncsStart = this.clock.now();
        this.emit('tick', dt);
        this.timings.userFuncsEnd = this.clock.now();

        //render scene
        this.timings.renderStart = this.clock.now();
        this.renderer.render(this.stage);
        this.timings.renderEnd = this.clock.now();

        this.timings.tickEnd = this.clock.now();
    }
});

/**
 * Alias for the active State's physics object. Instead of using
 * `game.state.active.physics`, you can use `game.physics`
 *
 * @property physics
 * @type Physics
 * @readOnly
 */
Object.defineProperty(Game.prototype, 'physics', {
    get: function() {
        return this.state.active.physics;
    }
});

/**
 * Alias for the active State's camera object. Instead of using
 * `game.state.active.camera`, you can use `game.camera`
 *
 * @property camera
 * @type Camera
 * @readOnly
 */
Object.defineProperty(Game.prototype, 'camera', {
    get: function() {
        return this.state.active.camera;
    }
});

/**
 * Alias for the active State's world object. Instead of using
 * `game.state.active.world`, you can use `game.world`
 *
 * @property world
 * @type World
 * @readOnly
 */
Object.defineProperty(Game.prototype, 'world', {
    get: function() {
        return this.state.active.world;
    }
});

module.exports = Game;