const core = require('engine/core'); const System = require('engine/system'); const Vector = require('engine/Vector'); const { removeItems } = require('engine/utils/array'); const WebGLRenderer = require('./core/renderers/webgl/WebGLRenderer'); const CanvasRenderer = require('./core/renderers/canvas/CanvasRenderer'); const { isWebGLSupported } = require('./core/utils'); const CONST = require('./const'); const Node = require('./Node'); const config = require('game/config'); // General asset middlewares (including texture support) const loader = require('engine/loader'); const { Resource } = loader; const blobMiddlewareFactory = require('engine/loader/middlewares/parsing/blob').blobMiddlewareFactory; const textureParser = require('./loaders/textureParser'); const spritesheetParser = require('./loaders/spritesheetParser'); const bitmapFontParser = require('./loaders/bitmapFontParser'); Resource.setExtensionXhrType('fnt', Resource.XHR_RESPONSE_TYPE.DOCUMENT); // - parse any blob into more usable objects (e.g. Image) loader.use(blobMiddlewareFactory()); // - parse any Image objects into textures loader.use(textureParser()); // - parse any spritesheet data into multiple textures loader.use(spritesheetParser()); // - parse any spritesheet data into multiple textures loader.use(bitmapFontParser()); // System let sharedRenderer = null; const Zero = Vector.create(0, 0); /** * Graphic system. */ class SystemGfx extends System { /** * @constructor */ constructor() { super(); /** * Name of this system. * @memberof SystemGfx# * @type {String} */ this.name = 'Gfx'; if (!sharedRenderer) { let options = { view: core.view, transparent: config.gfx.transparent, antialias: config.gfx.antialias, preserveDrawingBuffer: config.gfx.preserveDrawingBuffer, resolution: core.resolution, roundPixels: true, }; if (config.gfx.webgl && isWebGLSupported()) { sharedRenderer = new WebGLRenderer(config.width || 320, config.height || 200, options); } else { sharedRenderer = new CanvasRenderer(config.width || 320, config.height || 200, options); } // Setup default scale mode CONST.SCALE_MODES.DEFAULT = CONST.SCALE_MODES[config.gfx.scaleMode.toUpperCase()]; } /** * Shared renderer instance. * @memberof SystemGfx# * @type {Renderer} */ this.renderer = sharedRenderer; /** * Root drawing element. * @memberof SystemGfx# * @type {Node} */ this.root = Node(); this.root.system = this; /** * Map of layer containers. * @memberof SystemGfx# * @type {Object} */ this.layers = {}; /** * Background color cache * @type {Number|String} * @private */ this._backgroundColor = 0x000000; this.timestamp = 0; this.delta = 0; this.animList = []; } /** * Background color setter * @param {Number} c Color to set */ set backgroundColor(c) { this.renderer.backgroundColor = this._backgroundColor = c; } /** * Background color getter * @return {Number} Background color as number */ get backgroundColor() { return this._backgroundColor; } /** * Mouse position getter. Require the `engine/gfx/interaction` before * using. * @return {Vector} Mouse position */ get mouse() { if (this.renderer.plugins.interaction) { return this.renderer.plugins.interaction.mouse.global; } else { return Zero.set(0, 0); } } /** * Request animating an item * @param {Node} item Item to be animated * @private */ requestAnimate(item) { let idx = this.animList.indexOf(item); if (idx < 0) { this.animList.push(item); } } /** * Cancel the request of an animating * @param {Node} item Item to be canceled * @private */ cancelAnimate(item) { let idx = this.animList.indexOf(item); if (idx >= 0) { removeItems(this.animList, idx, 1); } } /** * Awake callback */ awake() { this.renderer.backgroundColor = this._backgroundColor; this.timestamp = performance.now(); } /** * Update callback */ update() { this.renderer.render(this.root); } /** * Fixed update callback * @param {Number} delta Delta time in ms */ fixedUpdate(delta) { this.delta = delta; for (let i = this.animList.length - 1; i >= 0; i--) { this.animList[i].update(this.delta); } } /** * Create a layer * @param {String} name Name of this layer * @param {String} parent Which layer to add this into * @return {SystemGfx} Self for chaining */ createLayer(name, parent) { if (this.layers[name]) { console.log(`Layer "${name}" already exist!`); return this; } let c; if (!parent) { c = this.root; } else if (this.layers.hasOwnProperty(parent)) { c = this.layers[parent]; } else { console.log(`Parent layer "${parent}" does not exist!`); return this; } this.layers[name] = Node().addTo(c); return this; } /** * Entity spawn callback * @param {Entity} ent Entity to be spawned */ onEntitySpawn(ent) { let name = ent.layer; if (ent.gfx) { ent.gfx.entity = ent; // Default layer is the root if (!name) { this.root.addChild(ent.gfx); } // Find the layer and add this entitiy into it else if (this.layers.hasOwnProperty(name)) { this.layers[name].addChild(ent.gfx); } // Override gfx's position with the entity's ent.gfx.position = ent.position; } } /** * Entity remove callback * @param {Entity} ent Entity to be removed */ onEntityRemove(ent) { if (ent.gfx) { ent.gfx.remove(); ent.gfx.entity = null; } } } module.exports = SystemGfx;