UNPKG

tsxna-framework

Version:
204 lines (184 loc) 4.56 kB
var Emitter = require('eventemitter2').EventEmitter2 var now = require('performance-now') var inherits = require('inherits') var raf = require('raf') module.exports = Game inherits(Game, Emitter) /** * Create the game * @name createGame * @param {Object} options * @param {Object} options.renderer * @param {Number} options.fps * @example * var createGame = require('gameloop') * * var game = createGame({ * renderer: document.createElement('canvas').getContext('2d') * }) */ function Game (options) { options = options || {} Emitter.call(this) this.paused = true this.renderer = options.renderer || {} this.fps = options.fps || 60 this.step = 1 / this.fps } /** * Start the game. Emits the `start` event. * @name game.start * @fires Game#start * @param {Object} state – arbitrary starting game state emitted by `start` event. * @example * game.start() */ Game.prototype.start = function start (state) { this.paused = false this.last = now() this.time = 0 this.accumulator = 0 this.emit('start', state) raf(this.frame.bind(this)) } /** * Execute a frame * @name game.frame * @private */ Game.prototype.frame = function frame (time) { if (!this.paused) { var newTime = now() var dt = (newTime - this.last) / 1000 if (dt > 0.2) dt = this.step this.accumulator += dt this.last = newTime while (this.accumulator >= this.step) { this.time += this.step this.accumulator -= this.step this.update(this.step, this.time) } this.draw(this.renderer, this.accumulator / this.step) raf(this.frame.bind(this)) } } /** * Update the game state. Emits the `update` event. You'll likely never call this method, but you may need to override it. Make sure to always emit the update event with the `delta` time. * @name game.update * @param {Number} interval – interval between each frame * @param {Number} time – total time elapsed * @fires Game#update */ Game.prototype.update = function update (interval, time) { this.emit('update', interval, time) } /** * Draw the game. Emits the `draw` event. You'll likely never call this method, but you may need to override it. Make sure to always emit the update event with the renderer and `delta` time. * @name game.draw * @param {Object} renderer * @param {Number} deltaTime – time remaining until game.update is called * @fires Game#draw */ Game.prototype.draw = function draw (renderer, frameState) { this.emit('draw', renderer, frameState) } /** * End the game. Emits the `end` event/ * @name game.end * @param {Object} state – state of end game conditions * @fires Game#end * @example * game.end() */ Game.prototype.end = function end (state) { this.emit('end', state) } /** * Pause the game. Emits the `pause` event. * @name game.pause * @fires Game#pause * @example * game.pause() */ Game.prototype.pause = function pause () { if (!this.paused) { this.paused = true this.emit('pause') } } /** * Resume the game. Emits the `resume` event. * @name game.resume * @fires Game#resume * @example * game.resume() */ Game.prototype.resume = function resume () { if (this.paused) { this.start() this.emit('resume') } } /** * Pause or start game depending on game state. Emits either the `pause` or `resume` event. * @name game.toggle * @example * game.toggle() */ Game.prototype.toggle = function toggle () { if (this.paused) this.resume() else this.pause() } /* Event documentation */ /** * Start event. Fired when `game.start()` is called. * * @event Game#start * @example * game.on('start', function () {}) */ /** * End event. Fired when `game.end()` is called. * * @event Game#end * @param {Object} state - state of end game conditions * @example * game.on('end', function (state) {}) */ /** * Update event. * * @event Game#update * @param {Number} interval – interval between each frame * @param {Number} frameState – current state of the completion of the frame * @param {Number} time – total time elapsed * @example * game.on('update', function (interval, time) { * console.log(interval) * }) */ /** * Draw event. * * @event Game#draw * @param {Number} frameState – current state of the completion of the frame * @param {Number} delta * @example * game.on('draw', function (renderer, dt) { * console.log(dt) * }) */ /** * Pause event. Fired when `game.pause()` is called. * * @event Game#pause * @example * game.on('pause', function () {}) */ /** * Resume event. Fired when `game.resume()` is called. * * @event Game#resume * @example * game.on('resume', function () {}) */