tsxna-framework
Version:
A simple TypeScript Game Framework
204 lines (184 loc) • 4.56 kB
JavaScript
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 () {})
*/