Path: blob/main/public/games/files/algaes-escapade/js/gamejs/gamejs.min.js
1037 views
/* This file has been generated by yabbler.js */1require.define({2"gamejs/mask": function(require, exports, module) {3var gamejs = require('../gamejs');4var objects = require('./utils/objects');56/**7* @fileoverview Image masks. Usefull for pixel perfect collision detection.8*/910/**11* Creates an image mask from the given Surface. The alpha of each pixel is checked12* to see if it is greater than the given threshold. If it is greater then13* that pixel is set as non-colliding.14*15* @param {gamejs.Surface} surface16* @param {Number} threshold 0 to 255. defaults to: 255, fully transparent17*/18exports.fromSurface = function(surface, threshold) {19threshold = threshold && (255 - threshold) || 255;20var imgData = surface.getImageData().data;21var dims = surface.getSize();22var mask = new Mask(dims);23for (var i=0;i<imgData.length;i += 4) {24// y: pixel # / width25var y = parseInt((i / 4) / dims[0], 10);26// x: pixel # % width27var x = parseInt((i / 4) % dims[0], 10);28var alpha = imgData[i+3];29if (alpha >= threshold) {30mask.setAt(x, y);31}32}33return mask;34};3536/**37* Image Mask38* @param {Array} dimensions [width, height]39*40*/41var Mask = exports.Mask = function(dims) {42/**43* @ignore44*/45this.width = dims[0];46/**47* @ignore48*/49this.height = dims[1];50/**51* @ignore52*/53this._bits = [];54for (var i=0;i<this.width;i++) {55this._bits[i] = [];56for (var j=0;j<this.height;j++) {57this._bits[i][j] = false;58}59}60return;61};6263/**64* @param {gamejs.mask.Mask} otherMask65* @param {Array} offset [x,y]66* @returns the overlapping rectangle or null if there is no overlap;67*/68Mask.prototype.overlapRect = function(otherMask, offset) {69var arect = this.rect;70var brect = otherMask.rect;71if (offset) {72brect.moveIp(offset);73}74// bounding box intersect75if (!brect.collideRect(arect)) {76return null;77}78var xStart = Math.max(arect.left, brect.left);79var xEnd = Math.min(arect.right, brect.right);8081var yStart = Math.max(arect.top, brect.top);82var yEnd = Math.min(arect.bottom, brect.bottom);8384return new gamejs.Rect([xStart, yStart], [xEnd - xStart, yEnd - yStart]);85};8687/**88*89* @returns True if the otherMask overlaps with this map.90* @param {Mask} otherMask91* @param {Array} offset92*/93Mask.prototype.overlap = function(otherMask, offset) {94var overlapRect = this.overlapRect(otherMask, offset);95if (overlapRect === null) {96return false;97}9899var arect = this.rect;100var brect = otherMask.rect;101if (offset) {102brect.moveIp(offset);103}104105var count = 0;106for (var y=overlapRect.top; y<=overlapRect.bottom; y++) {107for (var x=overlapRect.left; x<=overlapRect.right; x++) {108if (this.getAt(x - arect.left, y - arect.top) &&109otherMask.getAt(x - brect.left, y - brect.top)) {110return true;111}112}113}114// NOTE this should not happen because either we bailed out115// long ago because the rects do not overlap or there is an116// overlap and we should not have gotten this far.117// throw new Error("Maks.overlap: overlap detected but could not create mask for it.");118return false;119};120121/**122* @param {gamejs.mask.Mask} otherMask123* @param {Array} offset [x,y]124* @returns the number of overlapping pixels125*/126Mask.prototype.overlapArea = function(otherMask, offset) {127var overlapRect = this.overlapRect(otherMask, offset);128if (overlapRect === null) {129return 0;130}131132var arect = this.rect;133var brect = otherMask.rect;134if (offset) {135brect.moveIp(offset);136}137138var count = 0;139for (var y=overlapRect.top; y<=overlapRect.bottom; y++) {140for (var x=overlapRect.left; x<=overlapRect.right; x++) {141if (this.getAt(x - arect.left, y - arect.top) &&142otherMask.getAt(x - brect.left, y - brect.top)) {143count++;144}145}146}147return count;148};149150/**151* @param {gamejs.mask.Mask} otherMask152* @param {Array} offset [x,y]153* @returns a mask of the overlapping pixels154*/155Mask.prototype.overlapMask = function(otherMask, offset) {156var overlapRect = this.overlapRect(otherMask, offset);157if (overlapRect === null) {158return 0;159}160161var arect = this.rect;162var brect = otherMask.rect;163if (offset) {164brect.moveIp(offset);165}166167var mask = new Mask([overlapRect.width, overlapRect.height]);168for (var y=overlapRect.top; y<=overlapRect.bottom; y++) {169for (var x=overlapRect.left; x<=overlapRect.right; x++) {170if (this.getAt(x - arect.left, y - arect.top) &&171otherMask.getAt(x - brect.left, y - brect.top)) {172mask.setAt(x, y);173}174}175}176return mask;177};178179/**180* Set bit at position.181* @param {Number} x182* @param {Number} y183*/184Mask.prototype.setAt = function(x, y) {185this._bits[x][y] = true;186};187188/**189* Get bit at position.190*191* @param {Number} x192* @param {Number} y193*/194Mask.prototype.getAt = function(x, y) {195x = parseInt(x, 10);196y = parseInt(y, 10);197if (x < 0 || y < 0 || x >= this.width || y >= this.height) {198return false;199}200return this._bits[x][y];201};202203204/**205* Flip the bits in this map.206*/207Mask.prototype.invert = function() {208this._bits = this._bits.map(function(row) {209return row.map(function(b) {210return !b;211});212});213};214215/**216* @returns {Array} the dimensions of the map217*/218Mask.prototype.getSize = function() {219return [this.width, this.height];220};221222objects.accessors(Mask.prototype, {223/**224* Rect of this Mask.225*/226'rect': {227get: function() {228return new gamejs.Rect([0, 0], [this.width, this.height]);229}230},231/**232* @returns {Number} number of set pixels in this mask.233*/234'length': {235get: function() {236var c = 0;237this._bits.forEach(function(row) {238row.forEach(function(b) {239if (b) {240c++;241}242});243});244return c;245}246}247});248249}}, ["gamejs", "gamejs/utils/objects"]);/* This file has been generated by yabbler.js */250require.define({251"gamejs/http": function(require, exports, module) {252/**253* @fileoverview Make synchronous http requests to your game's serverside component.254*255* If you configure a ajax base URL you can make http requests to your256* server using those functions.257258* The most high-level functions are `load()` and `save()` which take259* and return a JavaScript object, which they will send to / recieve from260* the server-side in JSON format.261*262* @example263*264* <script>265* // Same Origin policy applies! You can only make requests266* // to the server from which the html page is served.267* var $g = {268* ajaxBaseHref: "http://the-same-server.com/ajax/"269* };270* </script>271* <script src="./public/gamejs-wrapped.js"></script>272* ....273* typeof gamejs.load('userdata/') === 'object'274* typeof gamejs.get('userdata/') === 'string'275* ...276*277*/278279/**280* Response object returned by http functions `get` and `post`. This281* class is not instantiable.282*283* @param{String} responseText284* @param {String} responseXML285* @param {Number} status286* @param {String} statusText287*/288exports.Response = function() {289/**290* @param {String} header291*/292this.getResponseHeader = function(header) {293};294throw new Error('response class not instantiable');295};296297/**298* Make http request to server-side299* @param {String} method http method300* @param {String} url301* @param {String|Object} data302* @param {String|Object} type "Accept" header value303* @return {Response} response304*/305var ajax = exports.ajax = function(method, url, data, type) {306data = data || null;307var response = new XMLHttpRequest();308response.open(method, url, false);309if (type) {310response.setRequestHeader("Accept", type);311}312if (data instanceof Object) {313data = JSON.stringify(data);314response.setRequestHeader('Content-Type', 'application/json');315}316response.setRequestHeader('X-Requested-With', 'XMLHttpRequest');317response.send(data);318return response;319};320321/**322* Make http GET request to server-side323* @param {String} url324*/325var get = exports.get = function(url) {326return ajax('GET', url);327};328329/**330* Make http POST request to server-side331* @param {String} url332* @param {String|Object} data333* @param {String|Object} type "Accept" header value334* @returns {Response}335*/336var post = exports.post = function(url, data, type) {337return ajax('POST', url, data, type);338};339340function stringify(response) {341// eval is evil342return eval('(' + response.responseText + ')');343}344345function ajaxBaseHref() {346return (window.$g && window.$g.ajaxBaseHref) || './';347}348349/**350* Load an object from the server-side.351* @param {String} url352* @return {Object} the object loaded from the server353*/354exports.load = function(url) {355return stringify(get(ajaxBaseHref() + url));356};357358/**359* Send an object to a server-side function.360* @param {String} url361* @param {String|Object} data362* @param {String|Object} type "Accept" header value363* @returns {Object} the response object364*/365exports.save = function(url, data, type) {366return stringify(post(ajaxBaseHref() + url, {payload: data}, type));367};368369}}, []);/* This file has been generated by yabbler.js */370require.define({371"gamejs/mixer": function(require, exports, module) {372var gamejs = require('../gamejs');373374/**375* @fileoverview Playing sounds with the html5 audio tag. Audio files must be preloaded376* with the usual `gamejs.preload()` function. Ogg, wav and webm supported.377*378* Sounds & Images are loaded relative to './'.379*/380381var CACHE = {};382383/**384* need to export preloading status for require385* @ignore386*/387var _PRELOADING = false;388389/**390* @ignore391*/392var NUM_CHANNELS = 8;393394/**395* Sets the number of available channels for the mixer. The default value is 8.396*/397exports.setNumChannels = function(count) {398NUM_CHANNELS = parseInt(count, 10) || NUM_CHANNELS;399};400401exports.getNumChannels = function() {402return NUM_CHANNELS;403};404405/**406* put all audios on page in cache407* if same domain as current page, remove common href-prefix408* @ignore409*/410exports.init = function() {411var audios = Array.prototype.slice.call(document.getElementsByTagName("audio"), 0);412addToCache(audios);413return;414};415416/**417* Preload the audios into cache418* @param {String[]} List of audio URIs to load419* @returns {Function} which returns 0-1 for preload progress420* @ignore421*/422exports.preload = function(audioUrls, showProgressOrImage) {423var countTotal = 0;424var countLoaded = 0;425426function incrementLoaded() {427countLoaded++;428if (countLoaded == countTotal) {429_PRELOADING = false;430}431}432433function getProgress() {434return countTotal > 0 ? countLoaded / countTotal : 1;435}436437function successHandler() {438addToCache(this);439incrementLoaded();440}441function errorHandler() {442incrementLoaded();443throw new Error('Error loading ' + this.src);444}445446for (var key in audioUrls) {447if (key.indexOf('wav') == -1 && key.indexOf('ogg') == -1 && key.indexOf('webm') == -1) {448continue;449}450countTotal++;451var audio = new Audio();452audio.addEventListener('canplay', successHandler, true);453audio.addEventListener('error', errorHandler, true);454audio.src = audioUrls[key];455audio.gamejsKey = key;456audio.load();457}458if (countTotal > 0) {459_PRELOADING = true;460}461return getProgress;462};463464/**465* @ignore466*/467exports.isPreloading = function() {468return _PRELOADING;469};470471/**472* @param {dom.ImgElement} audios the <audio> elements to put into cache473* @ignore474*/475function addToCache(audios) {476if (!(audios instanceof Array)) {477audios = [audios];478}479480var docLoc = document.location.href;481audios.forEach(function(audio) {482CACHE[audio.gamejsKey] = audio;483});484return;485}486487/**488* Sounds can be played back.489* @constructor490* @param {String|dom.AudioElement} uriOrAudio the uri of <audio> dom element491* of the sound492*/493exports.Sound = function Sound(uriOrAudio) {494var cachedAudio;495if (typeof uriOrAudio === 'string') {496cachedAudio = CACHE[uriOrAudio];497} else {498cachedAudio = uriOrAudio;499}500if (!cachedAudio) {501// TODO sync audio loading502throw new Error('Missing "' + uriOrAudio + '", gamejs.preload() all audio files before loading');503}504505var channels = [];506var i = NUM_CHANNELS;507while (i-->0) {508var audio = new Audio();509audio.preload = "auto";510audio.loop = false;511audio.src = cachedAudio.src;512channels.push(audio);513}514/**515* start the sound516* @param {Boolean} loop whether the audio should loop for ever or not517*/518this.play = function(loop) {519channels.some(function(audio) {520if (audio.ended || audio.paused) {521audio.loop = !!loop;522audio.play();523return true;524}525return false;526});527};528529/**530* Stop the sound.531* This will stop the playback of this Sound on any active Channels.532*/533this.stop = function() {534channels.forEach(function(audio) {535audio.stop();536});537};538539/**540* Set volume of this sound541* @param {Number} value volume from 0 to 1542*/543this.setVolume = function(value) {544channels.forEach(function(audio) {545audio.volume = value;546});547};548549/**550* @returns {Number} the sound's volume from 0 to 1551*/552this.getVolume = function() {553return channels[0].volume;554};555556/**557* @returns {Number} Duration of this sound in seconds558*/559this.getLength = function() {560return channels[0].duration;561};562563return this;564};565566}}, ["gamejs"]);/* This file has been generated by yabbler.js */567require.define({568"gamejs/tmx": function(require, exports, module) {569var gamejs = require('gamejs');570var objects = require('gamejs/utils/objects');571var xml = require('gamejs/xml');572var base64 = require('gamejs/base64');573var uri = require('gamejs/utils/uri');574575/**576* @fileoverview577* This is a loader for the general purpose tile map editor "Tiled".578*579* This module can load all ".tmx" files even if additionally base64 encoded580* (can be configured in Tiled).581*582* This module loads the whole map definition, including the TileSets with583* all necessary images. For an example on how to render a map loaded with584* this module, see `examples/tiledmap`.585*586* You will typically create a Map instance with `Map(url)` and deal587* with the layers, tilesets, etc. through the Map instance588* instead of loading & creating them yourself.589*590* Only orthogonol maps are supported (no isometric maps).591*592* @see http://www.mapeditor.org/593* @see https://github.com/bjorn/tiled/wiki/TMX-Map-Format594*/595596/**597* My code is inspired by:598* * https://bitbucket.org/maikg/tiled2cocos/599* * https://github.com/obiot/melonJS/600*601*/602603/**604* A Tiled Map holds all layers defined in the tmx file as well605* as the necessary tiles to render the map.606* @param {String} url Relative or absolute URL to the tmx file607*/608var Map = exports.Map = function(url) {609610var url = uri.resolve(document.location.href, url);611var xmlDoc = xml.Document.fromURL(url);612var mapNode = xmlDoc.element('map');613614/**615* Width of a single tile in pixels616* @type Number617*/618this.tileWidth = mapNode.attribute('tilewidth');619/**620* Height of a single tile in pixels621* @type Number622*/623this.tileHeight = mapNode.attribute('tileheight');624/**625* Width of the map in tiles626* @type Number627*/628this.width = mapNode.attribute('width');629/**630* Height of the map in tiles631* @type Number632*/633this.height = mapNode.attribute('height');634635var orientation = mapNode.attribute('orientation');636if (orientation !== 'orthogonal') {637throw new Error('only orthogonol maps supported');638}639640/**641* Custom properties of the map642*/643this.properties = {};644setProperties(this.properties, mapNode);645646/**647* All tiles of this map.648* @type TileSets649*/650this.tiles = new TileSets(mapNode, url);651this.layers = loadLayers(mapNode);652return this;653};654655/**656* A Tile. Can not be instantiated. Get a Tile by calling `getTile(gid)`657* on a `TileSets` instance.658*/659var Tile = exports.Tile = function() {660throw new Error('Can not be instantiated.')661/**662* @type {gamejs.Surface} this tile's Surface663*/664this.surface = null;665/**666* @type {Object} custom properties attach for this tile667*/668this.properties = null;669return;670}671672/**673* A TileSets instance holds all tilesets of a map. This class674* makes it easy to get the image for a certain tile ID. You usually675* don't care about in which specific TileSet an image is so this676* class holds them all and deals with the lookup.677*678* You don't usually create a `TileSets` instance yourself, instead679* it is automatically created and attached to a `Map`.680*/681var TileSets = exports.TileSets = function(mapNode, mapUrl) {682var tileSets = [];683684/**685* Retrieve the image for a tile ID (gid).686*687* @param {Number} gid global tile id to retrieve688* @returns {gamejs.Surface} the Surface for the gid689*/690this.getSurface = function(gid) {691var tile = this.getTile(gid);692return tile && tile.surface || null;693};694695/**696* @param {Number} gid global tile id697* @returns {Object} the custom properties of this tile698*/699this.getProperties = function(gid) {700var tile = this.getTile(gid);701return tile && tile.properties || {};702};703704/**705* @param {Number} gid global tile id706* @returns {Object} the Tile object for this gid707*/708this.getTile = function(gid) {709var tile = null;710tileSets.some(function(tileSet, idx) {711if (tileSet.firstGid <= gid) {712tile = tileSet.tiles[gid - tileSet.firstGid];713return true;714}715return false;716}, this);717return tile;718};719720var loadTileSet = function(tileSetNode) {721var tiles = [];722var tileWidth = tileSetNode.attribute('tilewidth');723var tileHeight = tileSetNode.attribute('tileheight');724var spacing = tileSetNode.attribute('spacing') || 0;725// broken in tiled?726var margin = 0;727728var imageNode = tileSetNode.element('image');729var imageAtlasFile = imageNode.attribute('source');730var imageUrl = uri.makeRelative(uri.resolve(mapUrl, imageAtlasFile));731var atlas = gamejs.image.load(imageUrl);732// FIXME set transparency if imageNode.attribute('trans') is set733734var tileNodes = tileSetNode.elements('tile')735var dims = atlas.getSize();736var imgSize = new gamejs.Rect([0,0], [tileWidth, tileHeight]);737var idx = 0;738var y = 0;739while (y + tileHeight <= dims[1]) {740x = 0;741while (x + tileWidth <= dims[0]) {742var tileImage = new gamejs.Surface(tileWidth, tileHeight);743var rect = new gamejs.Rect([x, y], [tileWidth, tileHeight]);744tileImage.blit(atlas, imgSize, rect);745var tileProperties = {};746tileNodes.some(function(tileNode) {747if (tileNode.attribute('id') === idx) {748setProperties(tileProperties, tileNode);749return true;750}751}, this);752tiles.push({753surface: tileImage,754properties: tileProperties755});756x += tileWidth + spacing;757idx++;758}759y += tileHeight + spacing;760}761return tiles;762}763764/**765*766* constructor767**/768mapNode.elements('tileset').forEach(function(tileSetNode) {769var firstGid = tileSetNode.attribute('firstgid');770var externalSource = tileSetNode.attribute('source');771if (externalSource) {772var tileSetDocument = xml.Document.fromURL(uri.resolve(mapUrl, externalSource));773tileSetNode = tileSetDocument.element('tileset');774}775tileSets.push({776tiles: loadTileSet(tileSetNode),777firstGid: firstGid778});779});780tileSets.reverse();781782return this;783};784785/**786* loadLayers787*/788var H_FLIP = 0x80000000;789var V_FLIP = 0x40000000;790var loadLayers = function(mapNode) {791var layers = [];792793var getGids = function(layerNode) {794var dataNode = layerNode.element('data');795var encoding = dataNode.attribute('encoding');796var compression = dataNode.attribute('compression')797var data = "";798dataNode.children().forEach(function(textNode) {799data += textNode.value();800});801var byteData = [];802if (encoding === 'base64') {803if (compression) {804throw new Error('Compression of map data unsupported');805}806byteData = base64.decodeAsArray(data, 4);807} else if (encoding === 'csv') {808data.trim().split('\n').forEach(function(row) {809row.split(',', width).forEach(function(entry) {810byteData.push(parseInt(entry, 10));811});812});813} else {814// FIXME individual XML tile elements815throw new Error('individual tile format not supported');816}817return byteData;818};819820var width = mapNode.attribute('width');821var height = mapNode.attribute('height');822mapNode.elements('layer').forEach(function(layerNode) {823// create empty gid matrix824var gidMatrix = [];825var i = height;826while (i-->0) {827var j = width;828gidMatrix[i] = [];829while (j-->0) {830gidMatrix[i][j] = 0;831}832}833834getGids(layerNode).forEach(function(gid, idx) {835// FIXME flipX/Y currently ignored836var flipX = gid & H_FLIP;837var flipY = gid & V_FLIP;838// clear flags839gid &= ~(H_FLIP | V_FLIP);840gidMatrix[parseInt(idx / width, 10)][parseInt(idx % width, 10)] = gid;841});842layers.push({843gids: gidMatrix,844opacity: layerNode.attribute('opacity'),845visible: layerNode.attribute('visible'),846properties: setProperties({}, layerNode)847});848});849return layers;850}851852/**853* set generic <properties><property name="" value="">... on given object854*/855var setProperties = function(object, node) {856var props = node.element('properties');857if (!props) {858return;859}860props.elements('property').forEach(function(propertyNode) {861var name = propertyNode.attribute('name');862var value = propertyNode.attribute('value');863object[name] = value;864});865return object;866};867868}}, ["gamejs", "gamejs/utils/objects", "gamejs/xml", "gamejs/base64", "gamejs/utils/uri"]);/* This file has been generated by yabbler.js */869require.define({870"gamejs/time": function(require, exports, module) {871/**872* @fileoverview873* Provides tools for game time managment.874*875* This is very different from how PyGame works. We can not876* pause the execution of the script in Browser JavaScript, so what877* we do you do is write a main function which contains the code878* you would put into your main loop and pass that to `fpsCallback()`:879*880* @example881* function main() {882* // update models883* // draw to screen884* };885* gamejs.time.fpsCallback(main, this, 30);886* ;887* function aiUpdate() {888* // do stuff that needs low update rates889* }890* gamejs.time.fpsCallback(aiUpdate, this, 10);891*892*893*/894895896var TIMER_LASTCALL = null;897var CALLBACKS = {};898var CALLBACKS_LASTCALL = {};899var TIMER = null;900var STARTTIME = null;901902/**903* @ignore904*/905exports.init = function() {906STARTTIME = Date.now();907TIMER = setInterval(perInterval, 10);908return;909};910911/**912* @param {Function} fn the function to call back913* @param {Object} thisObj `this` will be set to that object when executing the function914* @param {Number} fps specify the framerate by which you want the callback to be called. (e.g. 30 = 30 times per seconds). default: 30915*/916exports.fpsCallback = function(fn, thisObj, fps) {917if ( fps === undefined ) {918fps = 30;919}920921fps = parseInt(1000/fps, 10);922CALLBACKS[fps] = CALLBACKS[fps] || [];923CALLBACKS_LASTCALL[fps] = CALLBACKS_LASTCALL[fps] || 0;924925CALLBACKS[fps].push({926'rawFn': fn,927'callback': function(msWaited) {928fn.apply(thisObj, [msWaited]);929}930});931return;932};933934/**935* @param {Function} callback the function delete936* @param {Number} fps937*/938exports.deleteCallback = function(callback, fps) {939fps = parseInt(1000/fps, 10);940var callbacks = CALLBACKS[fps];941if (!callbacks) {942return;943}944945CALLBACKS[fps] = callbacks.filter(function(fnInfo, idx) {946if (fnInfo.rawFn !== callback) {947return true;948}949return false;950});951return;952};953954var perInterval = function() {955var msNow = Date.now();956var lastCalls = CALLBACKS_LASTCALL;957function callbackWrapper(fnInfo) {958fnInfo.callback(msWaited);959}960for (var fpsKey in lastCalls) {961if (!lastCalls[fpsKey]) {962CALLBACKS_LASTCALL[fpsKey] = msNow;963}964var msWaited = msNow - lastCalls[fpsKey];965if (fpsKey <= msWaited) {966CALLBACKS_LASTCALL[fpsKey] = msNow;967CALLBACKS[fpsKey].forEach(callbackWrapper, this);968}969}970return;971};972973}}, []);/* This file has been generated by yabbler.js */974require.define({975"gamejs/draw": function(require, exports, module) {976/**977* @fileoverview Utilities for drawing geometrical objects to Surfaces. If you want to put images on978* the screen see `gamejs.image`.979*980* ### Colors981* There are several ways to specify colors. Whenever the docs says "valid #RGB string"982* you can pass in any of the following formats.983*984*985* @example986* "#ff00ff"987* "rgb(255, 0, 255)"988* "rgba(255,0, 255, 1)"989*/990991// FIXME all draw functions must return a minimal rect containing the drawn shape992993/**994* @param {gamejs.Surface} surface the Surface to draw on995* @param {String} color valid #RGB string, e.g., "#ff0000"996* @param {Array} startPos [x, y] position of line start997* @param {Array} endPos [x, y] position of line end998* @param {Number} width of the line, defaults to 1999*/1000exports.line = function(surface, color, startPos, endPos, width) {1001var ctx = surface.context;1002ctx.save();1003ctx.beginPath();1004ctx.strokeStyle = color;1005ctx.lineWidth = width || 1;1006ctx.moveTo(startPos[0], startPos[1]);1007ctx.lineTo(endPos[0], endPos[1]);1008ctx.stroke();1009ctx.restore();1010return;1011};10121013/**1014* Draw connected lines. Use this instead of indiviudal line() calls for1015* better performance1016*1017* @param {gamejs.Surface} surface the Surface to draw on1018* @param {String} color a valid #RGB string, "#ff0000"1019* @param {Boolean} closed if true the last and first point are connected1020* @param {Array} pointlist holding array [x,y] arrays of points1021* @param {Number} width width of the lines, defaults to 11022*/1023exports.lines = function(surface, color, closed, pointlist, width) {1024closed = closed || false;1025var ctx = surface.context;1026ctx.save();1027ctx.beginPath();1028ctx.strokeStyle = ctx.fillStyle = color;1029ctx.lineWidth = width || 1;1030pointlist.forEach(function(point, idx) {1031if (idx === 0) {1032ctx.moveTo(point[0], point[1]);1033} else {1034ctx.lineTo(point[0], point[1]);1035}1036});1037if (closed) {1038ctx.lineTo(pointlist[0][0], pointlist[0][1]);1039}1040ctx.stroke();1041ctx.restore();1042return;1043};10441045/**1046* Draw a circle on Surface1047*1048* @param {gamejs.Surface} surface the Surface to draw on1049* @param {String} color a valid #RGB String, #ff00cc1050* @param {Array} pos [x, y] position of the circle center1051* @param {Number} radius of the circle1052* @param {Number} width width of the circle, if not given or 0 the circle is filled1053*/1054exports.circle = function(surface, color, pos, radius, width) {1055if (!radius) {1056throw new Error('[circle] radius required argument');1057}1058if (!pos || !(pos instanceof Array)) {1059throw new Error('[circle] pos must be given & array' + pos);1060}10611062var ctx = surface.context;1063ctx.save();1064ctx.beginPath();1065ctx.strokeStyle = ctx.fillStyle = color;1066ctx.lineWidth = width || 1;1067ctx.arc(pos[0], pos[1], radius, 0, 2*Math.PI, true);1068if (width === undefined || width === 0) {1069ctx.fill();1070} else {1071ctx.stroke();1072}1073ctx.restore();1074return;1075};10761077/**1078* @param {gamejs.Surface} surface the Surface to draw on1079* @param {String} color a valid #RGB String, #ff00cc1080* @param {gamejs.Rect} rect the position and dimension attributes of this Rect will be used1081* @param {Number} width the width of line drawing the Rect, if 0 or not given the Rect is filled.1082*/1083exports.rect = function(surface, color, rect, width) {1084var ctx =surface.context;1085ctx.save();1086ctx.beginPath();1087ctx.strokeStyle = ctx.fillStyle = color;1088if (isNaN(width) || width === 0) {1089ctx.fillRect(rect.left, rect.top, rect.width, rect.height);1090} else {1091ctx.lineWidth = width || 1;1092ctx.strokeRect(rect.left, rect.top, rect.width, rect.height);1093}1094ctx.restore();1095};10961097/**1098* @param {gamejs.Surface} surface the Surface to draw on1099* @param {String} color a valid #RGB String, #ff00cc1100* @param {gamejs.Rect} rect the position and dimension attributes of this Rect will be used1101* @param {Number} startAngle1102* @param {Number} stopAngle1103* @param {Number} width the width of line, if 0 or not given the arc is filled.1104*/1105exports.arc= function(surface, color, rect, startAngle, stopAngle, width) {1106var ctx = surface.context;1107ctx.save();1108ctx.beginPath();1109ctx.strokeStyle = ctx.fillStyle = color;1110ctx.arc(rect.center[0], rect.center[1],1111rect.width/2,1112startAngle * (Math.PI/180), stopAngle * (Math.PI/180),1113false1114);1115if (isNaN(width) || width === 0) {1116ctx.fill();1117} else {1118ctx.lineWidth = width || 1;1119ctx.stroke();1120}1121ctx.restore();1122};11231124/**1125* Draw a polygon on the surface. The pointlist argument are the vertices1126* for the polygon.1127*1128* @param {gamejs.Surface} surface the Surface to draw on1129* @param {String} color a valid #RGB String, #ff00cc1130* @param {Array} pointlist array of vertices [x, y] of the polygon1131* @param {Number} width the width of line, if 0 or not given the polygon is filled.1132*/1133exports.polygon = function(surface, color, pointlist, width) {1134var ctx = surface.context;1135ctx.save();1136ctx.fillStyle = ctx.strokeStyle = color;1137ctx.beginPath();1138pointlist.forEach(function(point, idx) {1139if (idx == 0) {1140ctx.moveTo(point[0], point[1]);1141} else {1142ctx.lineTo(point[0], point[1]);1143}1144});1145ctx.closePath();1146if (isNaN(width) || width === 0) {1147ctx.fill();1148} else {1149ctx.lineWidth = width || 1;1150ctx.stroke();1151}1152ctx.restore();1153};11541155}}, []);/* This file has been generated by yabbler.js */1156require.define({1157"gamejs/worker": function(require, exports, module) {1158var gamejs = require('gamejs');1159var uri = require('gamejs/utils/uri');11601161/**1162* @fileoverview1163* Workers are useful to relieve your GameJs application from code which1164* might take long to run. Either expensive algorithms, which might get called1165* every now and then (e.g., path-finding) or another logic being run continously1166* within the rendering loop (e.g., physics engine).1167*1168* A Worker is like a seperate GameJs application being executed - another `main.js`1169* with its own `gamejs.ready()`. The Worker's most important feature is that1170* code executing within it does not block the rendering code. The Worker's1171* greatest limitation is that you can only communicate with it through text1172* messages.1173*1174* See the `examples/workers` directory for a running example.1175*1176* @example1177* // Create a worker with the main module "./test"1178* var fooWorker = new Worker('./test');1179* // Send a message to your worker.1180* // The Message doesn't have to be a string but it must be `JSON.stringify()`-able1181* fooWorker.post("foobar");1182*1183* // The result of the worker will be accessible1184* // in the main application via the gamejs.event queue1185* if (event.type === gamejs.event.WORKER_RESULT) {1186* gamejs.log('Worker #' + event.worker.id + ' returned ' + event.data);1187* }1188*1189* // In the worker module, we can send results back to the main application1190* // by posting them to the gamejs event queue as type `gamejs.event.WORKER_RESULT`1191* gamejs.event.post({1192* type: gamejs.event.WORKER_RESULT,1193* data: "zarzar"1194* });1195*1196*/11971198/**1199* true if this GameJs instance is being executed within a WebWorker1200* @type Boolean1201*/1202exports.inWorker = (this.importScripts !== undefined);12031204/**1205* Executed in scope of worker after user's main module1206* @ignore1207*/1208exports._ready = function () {1209var gamejs = require('gamejs');1210self.onmessage = function(event) {1211gamejs.event.post(event.data)1212};1213self.postMessage({1214type: gamejs.event.WORKER_ALIVE1215});1216};12171218/**1219* Send message to main context for logging1220* @ignore1221**/1222exports._logMessage = function(arguments) {1223self.postMessage({1224type: gamejs.event.WORKER_LOGMESSAGE,1225arguments: Array.prototype.slice.apply(arguments)1226});1227};12281229/**1230* Send result message to main context1231* @ignore1232*/1233exports._messageMain = function(event) {1234self.postMessage({1235type: gamejs.event.WORKER_RESULT,1236data: event.data1237});1238};12391240/**1241* executed in scope of worker before user's main module1242* @ignore1243*/1244var workerPrefix = function workerPrefix() {1245__scripts.forEach(function(script) {1246try {1247importScripts(script)1248} catch (e) {1249// can't help the worker1250}1251});1252};12531254/**1255* Setup a worker which has `require()` defined1256* @ignore1257**/1258var create = function(workerModuleId) {1259var moduleRoot = uri.resolve(document.location.href, window.require.getModuleRoot());1260var initialScripts = [];1261Array.prototype.slice.apply(document.getElementsByTagName('script'), [0]).forEach(function(script) {1262if (script.src) {1263initialScripts.push(script.src);1264}1265});12661267var URL = window.URL || window.webkitURL;1268var prefixString = workerPrefix.toString();1269// don't be afraid...1270prefixString = prefixString.substring(prefixString.indexOf("{") + 1, prefixString.lastIndexOf("}"));1271var blob = new Blob([1272'var __scripts = ["' + initialScripts.join('","') + '"];',1273prefixString,1274'self.require.setModuleRoot("' + moduleRoot + '");',1275'self.require.run("'+ workerModuleId +'");'1276]);12771278var blobURL = URL.createObjectURL(blob);1279return new Worker(blobURL);1280};12811282/**1283* The `Worker` constructor takes only one argument: a module id. This module1284* will be executed inside the newly created Worker. It is effectively the1285* main module of the Worker.1286*1287* Inside a Worker, you can use `require()` to import other scripts or1288* GameJs modules.1289*1290* **Note:** A Worker does not have access to the browser's `document`. So1291* a lot of GameJs modules - everything related to drawing to the canvas -1292* do not work in the Worker.1293*1294* You can use `gamejs.time.*`, `gamejs.utils.*`, `gamejs.event.*` and probably others1295* (as well as any module you write yourself for this purpose, of course).1296*1297* @param {String} moduleId The Worker's main module id. The main module will be executed in the worker1298*/1299exports.Worker = function(moduleId) {1300// FIXME id should be unchangeable1301/**1302* Unique id of this worker1303* @property {Number}1304*/1305var id = this.id = guid(moduleId);1306var worker = create(moduleId);1307var deadQueue = [];1308var alive = false;1309var self = this;13101311worker.onmessage = function(event) {1312if (event.data.type === gamejs.event.WORKER_ALIVE) {1313alive = true;1314deadQueue.forEach(function(data) {1315self.post(data);1316});1317} else if (event.data.type === gamejs.event.WORKER_LOGMESSAGE) {1318gamejs.log.apply(null, [id].concat(event.data.arguments));1319} else {1320gamejs.event.post({1321type: gamejs.event.WORKER_RESULT,1322data: event.data.data,1323worker: self,1324event: event,1325})1326}1327};1328worker.onerror = function(event) {1329gamejs.error('Error in worker "' + id + '" line ' + event.lineno + ': ', event.message)1330gamejs.event.post({1331type: gamejs.event.WORKER_ERROR,1332data: event.data,1333worker: self,1334event: event,1335})1336};13371338/**1339* Send a message to the worker1340*1341* @param {Object} data Payload object which gets sent to the Worker1342*/1343this.post = function(data) {1344if (alive) {1345worker.postMessage({1346type: gamejs.event.WORKER,1347data: data1348});1349} else {1350deadQueue.push(data);1351}1352};1353return this;1354}13551356/**1357* not a real GUID1358* @ignore1359*/1360function guid(moduleId) {1361var S4 = function() {1362return (((1+Math.random())*0x10000)|0).toString(16).substring(1);1363};1364return moduleId + '@' + (S4()+S4());1365}13661367}}, ["gamejs", "gamejs/utils/uri"]);/* This file has been generated by yabbler.js */1368require.define({1369"gamejs/event": function(require, exports, module) {1370var display = require('./display');1371var gamejs = require('../gamejs');1372/**1373* @fileoverview Methods for polling mouse and keyboard.1374*1375* Call `gamejs.event.get()` in your main loop to get a list of events that happend1376* since your last call.1377*1378* Note that some events, which would trigger a default browser action, are prevented1379* from triggering their default behaviour.1380*1381* All events have a type identifier. This event type is in between the values1382* of NOEVENT and NUMEVENTS. Each event has a constant in `gamejs.event.*`1383* All user defined events can have the value of USEREVENT or higher.1384* Make sure your custom event ids* follow this system.1385*1386* A pattern for using the event loop: your main game function (tick in this example)1387* is being called by [gamejs.time.fpsCallback()](../time/#fpsCallback) 25 times per second.1388* Inside tick we call [gamejs.event.get()](#get) for a list of events that happened since the last1389* tick and we loop over each event and act on the event properties.1390*1391* @example1392* var events = gamejs.event.get()1393* events.forEach(function(event) {1394* if (event.type === gamejs.event.MOUSE_UP) {1395* gamejs.log(event.pos, event.button);1396* } else if (event.type === gamejs.event.KEY_UP) {1397* gamejs.log(event.key);1398* }1399* });1400*1401*/1402// key constants1403exports.K_UP = 38;1404exports.K_DOWN = 40;1405exports.K_RIGHT = 39;1406exports.K_LEFT = 37;14071408exports.K_SPACE = 32;1409exports.K_BACKSPACE = 8;1410exports.K_TAB = 9;1411exports.K_ENTER = 13;1412exports.K_SHIFT = 16;1413exports.K_CTRL = 17;1414exports.K_ALT = 18;1415exports.K_ESC = 27;14161417exports.K_0 = 48;1418exports.K_1 = 49;1419exports.K_2 = 50;1420exports.K_3 = 51;1421exports.K_4 = 52;1422exports.K_5 = 53;1423exports.K_6 = 54;1424exports.K_7 = 55;1425exports.K_8 = 56;1426exports.K_9 = 57;1427exports.K_a = 65;1428exports.K_b = 66;1429exports.K_c = 67;1430exports.K_d = 68;1431exports.K_e = 69;1432exports.K_f = 70;1433exports.K_g = 71;1434exports.K_h = 72;1435exports.K_i = 73;1436exports.K_j = 74;1437exports.K_k = 75;1438exports.K_l = 76;1439exports.K_m = 77;1440exports.K_n = 78;1441exports.K_o = 79;1442exports.K_p = 80;1443exports.K_q = 81;1444exports.K_r = 82;1445exports.K_s = 83;1446exports.K_t = 84;1447exports.K_u = 85;1448exports.K_v = 86;1449exports.K_w = 87;1450exports.K_x = 88;1451exports.K_y = 89;1452exports.K_z = 90;14531454exports.K_KP1 = 97;1455exports.K_KP2 = 98;1456exports.K_KP3 = 99;1457exports.K_KP4 = 100;1458exports.K_KP5 = 101;1459exports.K_KP6 = 102;1460exports.K_KP7 = 103;1461exports.K_KP8 = 104;1462exports.K_KP9 = 105;14631464// event type constants1465exports.NOEVENT = 01466exports.NUMEVENTS = 3200014671468exports.QUIT = 0;1469exports.KEY_DOWN = 1;1470exports.KEY_UP = 2;1471exports.MOUSE_MOTION = 3;1472exports.MOUSE_UP = 4;1473exports.MOUSE_DOWN = 5;1474exports.MOUSE_WHEEL = 6;1475exports.USEREVENT = 2000;14761477exports.WORKER = 1000;1478exports.WORKER_RESULT = 1001;1479/** @ignore **/1480exports.WORKER_ERROR = 1002;1481/** @ignore **/1482exports.WORKER_ALIVE = 1003;1483/** @ignore **/1484exports.WORKER_LOG = 1004;14851486var QUEUE = [];14871488/**1489* Get all events from the event queue1490* @returns {Array}1491*/1492exports.get = function() {1493return QUEUE.splice(0, QUEUE.length);1494};14951496/**1497* Get the newest event of the event queue1498* @returns {gamejs.event.Event}1499*/1500exports.poll = function() {1501return QUEUE.pop();1502};15031504/**1505* Post an event to the event queue.1506* @param {gamejs.event.Event} userEvent the event to post to the queue1507*/1508exports.post = function(userEvent) {1509if (userEvent.type === exports.WORKER_RESULT && gamejs.worker.inWorker === true) {1510gamejs.worker._messageMain(userEvent);1511} else if (userEvent.type === exports.WORKER && gamejs.worker.inWorker === false) {1512if (!userEvent.worker || !userEvent.worker.post) {1513throw new Error('Missing "worker" property on event');1514}1515userEvent.worker.post(userEvent.data);1516} else {1517QUEUE.push(userEvent);1518}1519return;1520};15211522/**1523* Remove all events from the queue1524*/1525exports.clear = function() {1526QUEUE = [];1527};15281529/**1530* Holds all information about an event.1531* @class1532*/15331534exports.Event = function() {1535/**1536* The type of the event. e.g., gamejs.event.QUIT, KEYDOWN, MOUSEUP.1537*/1538this.type = null;1539/**1540* key the keyCode of the key. compare with gamejs.event.K_a, gamejs.event.K_b,...1541*/1542this.key = null;1543/**1544* relative movement for a mousemove event1545*/1546this.rel = null;1547/**1548* the number of the mousebutton pressed1549*/1550this.button = null;1551/**1552* pos the position of the event for mouse events1553*/1554this.pos = null;1555};15561557/**1558* @ignore1559*/1560exports.init = function() {15611562var lastPos = [];15631564// anonymous functions as event handlers = memory leak, see MDC:elementAddEventListener15651566function onMouseDown (ev) {1567var canvasOffset = display._getCanvasOffset();1568QUEUE.push({1569'type': gamejs.event.MOUSE_DOWN,1570'pos': [ev.clientX - canvasOffset[0], ev.clientY - canvasOffset[1]],1571'button': ev.button,1572'shiftKey': ev.shiftKey,1573'ctrlKey': ev.ctrlKey,1574'metaKey': ev.metaKey1575});1576}15771578function onMouseUp (ev) {1579var canvasOffset = display._getCanvasOffset();1580QUEUE.push({1581'type':gamejs.event.MOUSE_UP,1582'pos': [ev.clientX - canvasOffset[0], ev.clientY - canvasOffset[1]],1583'button': ev.button,1584'shiftKey': ev.shiftKey,1585'ctrlKey': ev.ctrlKey,1586'metaKey': ev.metaKey1587});1588}15891590function onKeyDown (ev) {1591var key = ev.keyCode || ev.which;1592QUEUE.push({1593'type': gamejs.event.KEY_DOWN,1594'key': key,1595'shiftKey': ev.shiftKey,1596'ctrlKey': ev.ctrlKey,1597'metaKey': ev.metaKey1598});15991600if ((!ev.ctrlKey && !ev.metaKey &&1601((key >= exports.K_LEFT && key <= exports.K_DOWN) ||1602(key >= exports.K_0 && key <= exports.K_z) ||1603(key >= exports.K_KP1 && key <= exports.K_KP9) ||1604key === exports.K_SPACE ||1605key === exports.K_TAB ||1606key === exports.K_ENTER)) ||1607key === exports.K_ALT ||1608key === exports.K_BACKSPACE) {1609ev.preventDefault();1610}1611}16121613function onKeyUp (ev) {1614QUEUE.push({1615'type': gamejs.event.KEY_UP,1616'key': ev.keyCode,1617'shiftKey': ev.shiftKey,1618'ctrlKey': ev.ctrlKey,1619'metaKey': ev.metaKey1620});1621}16221623function onMouseMove (ev) {1624var canvasOffset = display._getCanvasOffset();1625var currentPos = [ev.clientX - canvasOffset[0], ev.clientY - canvasOffset[1]];1626var relativePos = [];1627if (lastPos.length) {1628relativePos = [1629lastPos[0] - currentPos[0],1630lastPos[1] - currentPos[1]1631];1632}1633QUEUE.push({1634'type': gamejs.event.MOUSE_MOTION,1635'pos': currentPos,1636'rel': relativePos,1637'buttons': null, // FIXME, fixable?1638'timestamp': ev.timeStamp1639});1640lastPos = currentPos;1641return;1642}16431644function onMouseScroll(ev) {1645var canvasOffset = display._getCanvasOffset();1646var currentPos = [ev.clientX - canvasOffset[0], ev.clientY - canvasOffset[1]];1647QUEUE.push({1648type: gamejs.event.MOUSE_WHEEL,1649pos: currentPos,1650delta: ev.detail || (- ev.wheelDeltaY / 40)1651});1652return;1653}16541655function onBeforeUnload (ev) {1656QUEUE.push({1657'type': gamejs.event.QUIT1658});1659return;1660}16611662// IEFIX does not support addEventListener on document itself1663// MOZFIX but in moz & opera events don't reach body if mouse outside window or on menubar1664var canvas = display.getSurface()._canvas;1665canvas.addEventListener('mousedown', onMouseDown, false);1666canvas.addEventListener('mouseup', onMouseUp, false);1667document.addEventListener('keydown', onKeyDown, false);1668document.addEventListener('keyup', onKeyUp, false);1669canvas.addEventListener('mousemove', onMouseMove, false);1670canvas.addEventListener('mousewheel', onMouseScroll, false);1671// MOZFIX1672// https://developer.mozilla.org/en/Code_snippets/Miscellaneous#Detecting_mouse_wheel_events1673canvas.addEventListener('DOMMouseScroll', onMouseScroll, false);1674canvas.addEventListener('beforeunload', onBeforeUnload, false);16751676};16771678}}, ["gamejs/display", "gamejs"]);/* This file has been generated by yabbler.js */1679require.define({1680"gamejs/transform": function(require, exports, module) {1681var Surface = require('../gamejs').Surface;1682var matrix = require('./utils/matrix');1683var math = require('./utils/math');1684var vectors = require('./utils/vectors');16851686/**1687* @fileoverview Rotate and scale Surfaces.1688*/16891690/**1691* Returns a new surface which holds the original surface rotate by angle degrees.1692* @param {Surface} surface1693* @param {angel} angle Clockwise angle by which to rotate1694* @returns {Surface} new, rotated surface1695*/1696exports.rotate = function (surface, angle) {1697var origSize = surface.getSize();1698var radians = (angle * Math.PI / 180);1699var newSize = origSize;1700// find new bounding box1701if (angle % 360 !== 0) {1702var rect = surface.getRect();1703var points = [1704[-rect.width/2, rect.height/2],1705[rect.width/2, rect.height/2],1706[-rect.width/2, -rect.height/2],1707[rect.width/2, -rect.height/2]1708];1709var rotPoints = points.map(function(p) {1710return vectors.rotate(p, radians);1711});1712var xs = rotPoints.map(function(p) { return p[0]; });1713var ys = rotPoints.map(function(p) { return p[1]; });1714var left = Math.min.apply(Math, xs);1715var right = Math.max.apply(Math, xs);1716var bottom = Math.min.apply(Math, ys);1717var top = Math.max.apply(Math, ys);1718newSize = [right-left, top-bottom];1719}1720var newSurface = new Surface(newSize);1721var oldMatrix = surface._matrix;1722surface._matrix = matrix.translate(surface._matrix, origSize[0]/2, origSize[1]/2);1723surface._matrix = matrix.rotate(surface._matrix, radians);1724surface._matrix = matrix.translate(surface._matrix, -origSize[0]/2, -origSize[1]/2);1725var offset = [(newSize[0] - origSize[0]) / 2, (newSize[1] - origSize[1]) / 2];1726newSurface.blit(surface, offset);1727surface._matrix = oldMatrix;1728return newSurface;1729};17301731/**1732* Returns a new surface holding the scaled surface.1733* @param {Surface} surface1734* @param {Array} dimensions new [width, height] of surface after scaling1735* @returns {Surface} new, scaled surface1736*/1737exports.scale = function(surface, dims) {1738var width = dims[0];1739var height = dims[1];1740if (width <= 0 || height <= 0) {1741throw new Error('[gamejs.transform.scale] Invalid arguments for height and width', [width, height]);1742}1743var oldDims = surface.getSize();1744var ws = width / oldDims[0];1745var hs = height / oldDims[1];1746var newSurface = new Surface([width, height]);1747var originalMatrix = surface._matrix.slice(0);1748surface._matrix = matrix.scale(surface._matrix, [ws, hs]);1749newSurface.blit(surface);1750surface._matrix = originalMatrix;1751return newSurface;1752};17531754/**1755* Flip a Surface either vertically, horizontally or both. This returns1756* a new Surface (i.e: nondestructive).1757* @param {gamejs.Surface} surface1758* @param {Boolean} flipHorizontal1759* @param {Boolean} flipVertical1760* @returns {Surface} new, flipped surface1761*/1762exports.flip = function(surface, flipHorizontal, flipVertical) {1763var dims = surface.getSize();1764var newSurface = new Surface(dims);1765var scaleX = 1;1766var scaleY = 1;1767var xPos = 0;1768var yPos = 0;1769if (flipHorizontal === true) {1770scaleX = -1;1771xPos = -dims[0];1772}1773if (flipVertical === true) {1774scaleY = -1;1775yPos = -dims[1];1776}1777newSurface.context.save();1778newSurface.context.scale(scaleX, scaleY);1779newSurface.context.drawImage(surface.canvas, xPos, yPos);1780newSurface.context.restore();1781return newSurface;1782};17831784}}, ["gamejs", "gamejs/utils/matrix", "gamejs/utils/math", "gamejs/utils/vectors"]);/* This file has been generated by yabbler.js */1785require.define({1786"gamejs/xml": function(require, exports, module) {1787/**1788* @fileoverview1789*1790* Provides facilities for parsing an xml String.1791*1792* You will typically get a `gamejs.xml.Document` instance1793* by loading the data with one of the two static1794* `Document.fromString(string)` or `Document.fromUrl(url)`.17951796* Querying for `elements(name)` or `children()` will return a1797* new `gamejs.xml.Document` matching your result (or null).1798*1799* Use `attributes(name)` and `value()` to get the data stored1800* in the XML Document.1801*/18021803/**1804* XMLParser1805*/1806var Parser = exports.Parser = function() {18071808var xmlDoc = null;1809var parser = new DOMParser();18101811this.parseFromString = function(xmlString) {1812xmlDoc = parser.parseFromString(xmlString, 'text/xml');1813return xmlDoc;1814};18151816return this;1817};18181819/**1820* Instantiate with the static functions `Document.fromString()` and `fromURL()`.1821*/1822var Document = exports.Document = function(xmlDocument) {1823if (!xmlDocument || (!xmlDocument instanceof XMLDocument) ) {1824throw new Error('Need a valid xmlDocument.');1825}1826/** @ignore **/1827this._xmlDocument = xmlDocument;1828return this;1829};18301831/**1832* Returns the first element in the current document whose tag-name matches1833* the given 'name'.1834* @returns gamejs.xml.Document1835*/1836Document.prototype.element = function(name) {1837var elem = this._xmlDocument.getElementsByTagName(name)[0];1838return elem && new Document(elem) || null;1839};18401841/**1842* Returns all elements in the current document whose tag-name matches1843* the given 'name'.1844* @returns an Array of gamejs.xml.Document1845*/1846Document.prototype.elements = function(name) {1847var elems = this._xmlDocument.getElementsByTagName(name);1848return Array.prototype.slice.apply(elems, [0]).map(function(elem) {1849return new Document(elem);1850});1851};18521853/**1854* Returns the attribute value of this document.1855*1856* @returns String1857*/1858Document.prototype.attribute = function(name) {1859var attributeValue = this._xmlDocument.getAttribute(name);1860attributeValue = attributeValue ? attributeValue.trim() : null;1861if (attributeValue === null) {1862return null;1863}1864if (attributeValue.toLowerCase() === 'true') {1865return true;1866}1867if (attributeValue.toLowerCase() === 'false') {1868return false;1869}1870var attributeIntValue = parseInt(attributeValue, 10);1871var attributeFloatValue = parseFloat(attributeValue, 10);1872if (!isNaN(attributeIntValue)) {1873if (attributeFloatValue !== attributeIntValue) {1874return attributeFloatValue;1875}1876return attributeIntValue;1877}1878return attributeValue;1879};18801881/**1882* Returns the nodevalue of the current xml document1883* @returns String1884*/1885Document.prototype.value = function() {1886return this._xmlDocument.nodeValue;1887};18881889/**1890* Returns all children of this xml document1891* @returns Array of gamejs.xml.Document1892*/1893Document.prototype.children = function() {1894return Array.prototype.slice.apply(this._xmlDocument.childNodes, [0]).map(function(cNode) {1895return new Document(cNode);1896});1897};18981899/**1900* @returns gamejs.xml.Document1901*/1902Document.fromString = function(xmlString) {1903var parser = new DOMParser();1904var xmlDoc = parser.parseFromString(xmlString, 'text/xml');1905return new Document(xmlDoc);1906};19071908/**1909* @returns gamejs.xml.Document1910*/1911Document.fromURL = function(url) {1912var response = new XMLHttpRequest();1913response.open('GET', url, false);1914response.setRequestHeader('X-Requested-With', 'XMLHttpRequest');1915response.setRequestHeader('Content-Type', 'text/xml');1916response.overrideMimeType('text/xml');1917response.send();1918return new Document(response.responseXML);1919};19201921}}, []);/* This file has been generated by yabbler.js */1922require.define({1923"gamejs/sprite": function(require, exports, module) {1924var gamejs = require('../gamejs');1925var arrays = require('./utils/arrays');1926var $o = require('./utils/objects');1927var $v = require('./utils/vectors');19281929/**1930* @fileoverview Provides `Sprite` the basic building block for any game and1931* `SpriteGroups`, which are an efficient1932* way for doing collision detection between groups as well as drawing layered1933* groups of objects on the screen.1934*1935*/19361937/**1938* Your visible game objects will typically subclass Sprite. By setting it's image1939* and rect attributes you can control its appeareance. Those attributes control1940* where and what `Sprite.draw(surface)` will blit on the the surface.1941*1942* Your subclass should overwrite `update(msDuration)` with its own implementation.1943* This function is called once every game tick, it is typically used to update1944* the status of that object.1945* @constructor1946*/1947var Sprite = exports.Sprite = function() {1948/** @ignore */1949this._groups = [];1950/** @ignore */1951this._alive = true;19521953/**1954* Image to be rendered for this Sprite.1955* @type gamejs.Surface1956*/1957this.image = null;1958/**1959* Rect describing the position of this sprite on the display.1960* @type gamejs.Rect1961*/1962this.rect = null;19631964/**1965* List of all groups that contain this sprite.1966*/1967$o.accessor(this, 'groups', function() {1968return this._groups;1969});19701971return this;1972};19731974/**1975* Kill this sprite. This removes the sprite from all associated groups and1976* makes future calls to `Sprite.isDead()` return `true`1977*/1978Sprite.prototype.kill = function() {1979this._alive = false;1980this._groups.forEach(function(group) {1981group.remove(this);1982}, this);1983return;1984};19851986/**1987* Remove the sprite from the passed groups1988* @param {Array|gamejs.sprite.Group} groups One or more `gamejs.Group`1989* instances1990*/1991Sprite.prototype.remove = function(groups) {1992if (!(groups instanceof Array)) {1993groups = [groups];1994}19951996groups.forEach(function(group) {1997group.remove(this);1998}, this);1999return;2000};20012002/**2003* Add the sprite to the passed groups2004* @param {Array|gamejs.sprite.Group} groups One or more `gamejs.sprite.Group`2005* instances2006*/2007Sprite.prototype.add = function(groups) {2008if (!(groups instanceof Array)) {2009groups = [groups];2010}20112012groups.forEach(function(group) {2013group.add(this);2014}, this);2015return;2016};20172018/**2019* Draw this sprite onto the given surface. The position is defined by this2020* sprite's rect.2021* @param {gamejs.Surface} surface The surface to draw on2022*/2023Sprite.prototype.draw = function(surface) {2024surface.blit(this.image, this.rect);2025return;2026};20272028/**2029* Update this sprite. You **should** override this method with your own to2030* update the position, status, etc.2031*/2032Sprite.prototype.update = function() {};20332034/**2035* @returns {Boolean} True if this sprite has had `Sprite.kill()` called on it2036* previously, otherwise false2037*/2038Sprite.prototype.isDead = function() {2039return !this._alive;2040};20412042/**2043* Sprites are often grouped. That makes collision detection more efficient and2044* improves rendering performance. It also allows you to easly keep track of layers2045* of objects which are rendered to the screen in a particular order.2046*2047* `Group.update()` calls `update()` on all the contained sprites; the same is true for `draw()`.2048* @constructor2049*/2050var Group = exports.Group = function() {2051/** @ignore */2052this._sprites = [];205320542055if (arguments[0] instanceof Sprite ||2056(arguments[0] instanceof Array &&2057arguments[0].length &&2058arguments[0][0] instanceof Sprite2059)) {2060this.add(arguments[0]);2061}2062return this;2063};20642065/**2066* Update all the sprites in this group. This is equivalent to calling the2067* update method on each sprite in this group.2068*/2069Group.prototype.update = function() {2070var updateArgs = arguments;20712072this._sprites.forEach(function(sp) {2073sp.update.apply(sp, updateArgs);2074}, this);2075return;2076};20772078/**2079* Add one or more sprites to this group2080* @param {Array|gamejs.sprite.Sprite} sprites One or more2081* `gamejs.sprite.Sprite` instances2082*/2083Group.prototype.add = function(sprites) {2084if (!(sprites instanceof Array)) {2085sprites = [sprites];2086}20872088sprites.forEach(function(sprite) {2089this._sprites.push(sprite);2090sprite._groups.push(this);2091}, this);2092return;2093};20942095/**2096* Remove one or more sprites from this group2097* @param {Array|gamejs.sprite.Sprite} sprites One or more2098* `gamejs.sprite.Sprite` instances2099*/2100Group.prototype.remove = function(sprites) {2101if (!(sprites instanceof Array)) {2102sprites = [sprites];2103}21042105sprites.forEach(function(sp) {2106arrays.remove(sp, this._sprites);2107arrays.remove(this, sp._groups);2108}, this);2109return;2110};21112112/**2113* Check for the existence of one or more sprites within a group2114* @param {Array|gamejs.sprite.Sprite} sprites One or more2115* `gamejs.sprite.Sprite` instances2116* @returns {Boolean} True if every sprite is in this group, false otherwise2117*/2118Group.prototype.has = function(sprites) {2119if (!(sprites instanceof Array)) {2120sprites = [sprites];2121}21222123return sprites.every(function(sp) {2124return this._sprites.indexOf(sp) !== -1;2125}, this);2126};21272128/**2129* Get the sprites in this group2130* @returns {Array} An array of `gamejs.sprite.Sprite` instances2131*/2132Group.prototype.sprites = function() {2133return this._sprites;2134};21352136/**2137* Draw all the sprites in this group. This is equivalent to calling each2138* sprite's draw method.2139*/2140Group.prototype.draw = function() {2141var args = arguments;2142this._sprites.forEach(function(sprite) {2143sprite.draw.apply(sprite, args);2144}, this);2145return;2146};21472148/**2149* Draw background (`source` argument) over each sprite in the group2150* on the `destination` surface.2151*2152* This can, for example, be used to clear the2153* display surface to a a static background image in all the places2154* occupied by the sprites of all group.2155*2156* @param {gamejs.Surface} destination the surface to draw on2157* @param {gamejs.Surface} source surface2158*/2159Group.prototype.clear = function(destination, source) {2160this._sprites.forEach(function(sprite) {2161destination.blit(source, sprite.rect);2162}, this);2163};21642165/**2166* Remove all sprites from this group2167*/2168Group.prototype.empty = function() {2169this._sprites = [];2170return;2171};21722173/**2174* @returns {Array} of sprites colliding with the point2175*/2176Group.prototype.collidePoint = function() {2177var args = Array.prototype.slice.apply(arguments);2178return this._sprites.filter(function(sprite) {2179return sprite.rect.collidePoint.apply(sprite.rect, args);2180}, this);2181};21822183/**2184* Loop over each sprite in this group. This is a shortcut for2185* `group.sprites().forEach(...)`.2186*/2187Group.prototype.forEach = function(callback, thisArg) {2188return this._sprites.forEach(callback, thisArg);2189};21902191/**2192* Check whether some sprite in this group passes a test. This is a shortcut2193* for `group.sprites().some(...)`.2194*/2195Group.prototype.some = function(callback, thisArg) {2196return this._sprites.some(callback, thisArg);2197};21982199/**2200* Find sprites in a group that intersect another sprite2201* @param {gamejs.sprite.Sprite} sprite The sprite to check2202* @param {gamejs.sprite.Group} group The group to check2203* @param {Boolean} doKill If true, kill sprites in the group when collided2204* @param {function} collided Collision function to use, defaults to `gamejs.sprite.collideRect`2205* @returns {Array} An array of `gamejs.sprite.Sprite` instances that collided2206*/2207exports.spriteCollide = function(sprite, group, doKill, collided) {2208collided = collided || collideRect;2209doKill = doKill || false;22102211var collidingSprites = [];2212group.sprites().forEach(function(groupSprite) {2213if (collided(sprite, groupSprite)) {2214if (doKill) {2215groupSprite.kill();2216}2217collidingSprites.push(groupSprite);2218}2219});2220return collidingSprites;2221};22222223/**2224* Find all Sprites that collide between two Groups.2225*2226* @example2227* groupCollide(group1, group2).forEach(function (collision) {2228* var group1Sprite = collision.a;2229* var group2Sprite = collision.b;2230* // Do processing here!2231* });2232*2233* @param {gamejs.sprite.Group} groupA First group to check2234* @param {gamejs.sprite.Group} groupB Second group to check2235* @param {Boolean} doKillA If true, kill sprites in the first group when2236* collided2237* @param {Boolean} doKillB If true, kill sprites in the second group when2238* collided2239* @param {function} collided Collision function to use, defaults to `gamejs.sprite.collideRect`2240* @returns {Array} A list of objects where properties 'a' and 'b' that2241* correspond with objects from the first and second groups2242*/2243exports.groupCollide = function(groupA, groupB, doKillA, doKillB, collided) {2244doKillA = doKillA || false;2245doKillB = doKillB || false;22462247var collideList = [];2248var collideFn = collided || collideRect;2249groupA.sprites().forEach(function(groupSpriteA) {2250groupB.sprites().forEach(function(groupSpriteB) {2251if (collideFn(groupSpriteA, groupSpriteB)) {2252if (doKillA) {2253groupSpriteA.kill();2254}2255if (doKillB) {2256groupSpriteB.kill();2257}22582259collideList.push({2260'a': groupSpriteA,2261'b': groupSpriteB2262});2263}2264});2265});22662267return collideList;2268};22692270/**2271* Check for collisions between two sprites using their rects.2272*2273* @param {gamejs.sprite.Sprite} spriteA First sprite to check2274* @param {gamejs.sprite.Sprite} spriteB Second sprite to check2275* @returns {Boolean} True if they collide, false otherwise2276*/2277var collideRect = exports.collideRect = function (spriteA, spriteB) {2278return spriteA.rect.collideRect(spriteB.rect);2279};22802281/**2282* Collision detection between two sprites utilizing the optional `mask`2283* attribute on the sprites. Beware: expensive operation.2284*2285* @param {gamejs.sprite.Sprite} spriteA Sprite with 'mask' property set to a `gamejs.mask.Mask`2286* @param {gamejs.sprite.Sprite} spriteB Sprite with 'mask' property set to a `gamejs.mask.Mask`2287* @returns {Boolean} True if any mask pixels collide, false otherwise2288*/2289exports.collideMask = function(spriteA, spriteB) {2290if (!spriteA.mask || !spriteB.mask) {2291throw new Error("Both sprites must have 'mask' attribute set to an gamejs.mask.Mask");2292}2293var offset = [2294spriteB.rect.left - spriteA.rect.left,2295spriteB.rect.top - spriteA.rect.top2296];2297return spriteA.mask.overlap(spriteB.mask, offset);2298};22992300/**2301* Collision detection between two sprites using circles at centers.2302* There sprite property `radius` is used if present, otherwise derived from bounding rect.2303* @param {gamejs.sprite.Sprite} spriteA First sprite to check2304* @param {gamejs.sprite.Sprite} spriteB Second sprite to check2305* @returns {Boolean} True if they collide, false otherwise2306*/2307exports.collideCircle = function(spriteA, spriteB) {2308var rA = spriteA.radius || Math.max(spriteA.rect.width, spriteA.rect.height);2309var rB = spriteB.radius || Math.max(spriteB.rect.width, spriteB.rect.height);2310return $v.distance(spriteA.rect.center, spriteB.rect.center) <= rA + rB;2311};23122313}}, ["gamejs", "gamejs/utils/arrays", "gamejs/utils/objects", "gamejs/utils/vectors"]);/* This file has been generated by yabbler.js */2314require.define({2315"gamejs/display": function(require, exports, module) {2316var Surface = require('../gamejs').Surface;23172318/**2319* @fileoverview Methods to create, access and manipulate the display Surface.2320*2321* @example2322* var display = gamejs.display.setMode([800, 600]);2323* // blit sunflower picture in top left corner of display2324* var sunflower = gamejs.image.load("images/sunflower");2325* display.blit(sunflower);2326*2327*/23282329var CANVAS_ID = "gjs-canvas";2330var LOADER_ID = "gjs-loader";2331var SURFACE = null;23322333/**2334* @returns {document.Element} the canvas dom element2335*/2336var getCanvas = function() {2337var jsGameCanvas = null;2338var canvasList = Array.prototype.slice.call(document.getElementsByTagName("canvas"));2339canvasList.every(function(canvas) {2340if (canvas.getAttribute("id") == CANVAS_ID) {2341jsGameCanvas = canvas;2342return false;2343}2344return true;2345});2346return jsGameCanvas;2347};23482349/**2350* Create the master Canvas plane.2351* @ignore2352*/2353exports.init = function() {2354// create canvas element if not yet present2355var jsGameCanvas = null;2356if ((jsGameCanvas = getCanvas()) === null) {2357jsGameCanvas = document.createElement("canvas");2358jsGameCanvas.setAttribute("id", CANVAS_ID);2359document.body.appendChild(jsGameCanvas);2360}2361// remove loader if any;2362var $loader = document.getElementById('gjs-loader');2363if ($loader) {2364$loader.style.display = "none";2365}2366return;2367};23682369/**2370* Set the width and height of the Display. Conviniently this will2371* return the actual display Surface - the same as calling [gamejs.display.getSurface()](#getSurface))2372* later on.2373* @param {Array} dimensions [width, height] of the display surface2374*/2375exports.setMode = function(dimensions) {2376var canvas = getCanvas();2377canvas.width = dimensions[0];2378canvas.height = dimensions[1];2379return getSurface();2380};23812382/**2383* Set the Caption of the Display (document.title)2384* @param {String} title the title of the app2385* @param {gamejs.Image} icon FIXME implement favicon support2386*/2387exports.setCaption = function(title, icon) {2388document.title = title;2389};239023912392/**2393* The Display (the canvas element) is most likely not in the top left corner2394* of the browser due to CSS styling. To calculate the mouseposition within the2395* canvas we need this offset.2396* @see {gamejs.event}2397* @ignore2398*2399* @returns {Array} [x, y] offset of the canvas2400*/24012402exports._getCanvasOffset = function() {2403var boundRect = getCanvas().getBoundingClientRect();2404return [boundRect.left, boundRect.top];2405};24062407/**2408* Drawing on the Surface returned by `getSurface()` will draw on the screen.2409* @returns {gamejs.Surface} the display Surface2410*/2411var getSurface = exports.getSurface = function() {2412if (SURFACE === null) {2413var canvas = getCanvas();2414SURFACE = new Surface([canvas.clientWidth, canvas.clientHeight]);2415SURFACE._canvas = canvas;2416SURFACE._context = canvas.getContext('2d');2417SURFACE._smooth();2418}2419return SURFACE;2420};24212422}}, ["gamejs"]);/* This file has been generated by yabbler.js */2423require.define({2424"gamejs/pathfinding/astar": function(require, exports, module) {2425/**2426* @fileoverview2427* AStar Path finding algorithm2428*2429* Use the `findRoute(map, from, to, [timeout])` function to get the linked list2430* leading `from` a point `to` another on the given `map`.2431*2432* The map must implement interface `gamejs.pathfinding.Map`. This2433* class really holds an example implementation & data for you to study. If you2434* understand what this calls provides, you understand this module.2435*2436* Optionally, the search is canceld after `timeout` in millseconds.2437*2438* If there is no route `null` is returned.2439*2440* @see http://eloquentjavascript.net/chapter7.html2441*/2442var BinaryHeap = require('../utils/binaryheap').BinaryHeap;24432444/**2445* helper function for A*2446*/2447function ReachedList(hashFn) {2448var list = {};24492450this.store = function(point, route) {2451list[hashFn(point)] = route;2452return;2453};24542455this.find = function(point) {2456return list[hashFn(point)];2457};2458return this;2459}246024612462/** A* search function.2463*2464* This function expects a `Map` implementation and the origin and destination2465* points given. If there is a path between the two it will return the optimal2466* path as a linked list. If there is no path it will return null.2467*2468* The linked list is in reverse order: the first item is the destination and2469* the path to the origin follows.2470*2471* @param {Map} map map instance, must follow interface defined in {Map}2472* @param {Array} origin2473* @param {Array} destination2474* @param {Number} timeout milliseconds after which search should be canceled2475* @returns {Object} the linked list leading from `to` to `from` (sic!).2476**/2477exports.findRoute = function(map, from, to, timeout) {2478var open = new BinaryHeap(routeScore);2479var hashFn = typeof map.hash === 'function' ? map.hash : defaultHash;2480var reached = new ReachedList(hashFn);24812482function routeScore(route) {2483if (route.score === undefined) {2484route.score = map.estimatedDistance(route.point, to) + route.length;2485}2486return route.score;2487}2488function addOpenRoute(route) {2489open.push(route);2490reached.store(route.point, route);2491}24922493function processNewPoints(direction) {2494var known = reached.find(direction);2495var newLength = route.length + map.actualDistance(route.point, direction);2496if (!known || known.length > newLength){2497if (known) {2498open.remove(known);2499}2500addOpenRoute({2501point: direction,2502from: route,2503length: newLength2504});2505}2506}2507var startMs = Date.now();2508var route = null;2509addOpenRoute({2510point: from,2511from: null,2512length: 02513});2514var equalsFn = typeof map.equals === 'function' ? map.equals : defaultEquals;2515while (open.size() > 0 && (!timeout || Date.now() - startMs < timeout)) {2516route = open.pop();2517if (equalsFn(to, route.point)) {2518return route;2519}2520map.adjacent(route.point).forEach(processNewPoints);2521} // end while2522return null;2523};25242525var defaultEquals = function(a, b) {2526return a[0] === b[0] && a[1] === b[1];2527};25282529var defaultHash = function(a) {2530return a[0] + '-' + a[1];2531};25322533/**2534* This is the interface for a Map that can be passed to the `findRoute()`2535* function. `Map` is not instantiable - see the unit tests for an example2536* implementation of Map.2537*/2538var Map = exports.Map = function() {2539throw new Error('not instantiable, this is an interface');2540};25412542/**2543* @param {Array} origin2544* @returns {Array} list of points accessible from given Point2545*/2546Map.prototype.adjacent = function(origin) {2547};25482549/**2550* @param {Object} a one of the points ot test for equality2551* @param {Object} b ... the other point2552* @returns Wheter the two points are equal.2553*/2554Map.prototype.equals = defaultEquals;25552556/**2557* @param {Object} a point2558* @returns {String} hash for the point2559*/2560Map.prototype.hash = defaultHash;25612562/**2563* Estimated lower bound distance between two, adjacent points.2564* @param {Object} pointA2565* @param {Object} pointB2566* @returns {Number} the estimated distance between two points2567*/2568Map.prototype.estimatedDistance = function(pointA, pointB) {2569return 1;2570};25712572/**2573* Actual distance between the two given points.2574* @param {Object} pointA2575* @param {Object} pointB2576* @returns {Number} the actual distance between two points2577*/2578Map.prototype.actualDistance = function(pointA, pointB) {2579return 1;2580};25812582}}, ["gamejs/utils/binaryheap"]);/* This file has been generated by yabbler.js */2583require.define({2584"gamejs/surfacearray": function(require, exports, module) {2585var gamejs = require('../gamejs');2586var accessors = require('./utils/objects').accessors;2587/**2588* @fileoverview Fast pixel access.2589*2590* @example2591*2592* // create array from display surface2593* var srfArray = new SurfaceArray(display);2594* // direct pixel access2595* srfArray.set(50, 100, [255, 0, 0, 100]);2596* console.log(srfArray.get(30, 50));2597* // blit modified array back to display surface2598* blitArray(display, srfArray);2599*/26002601/**2602* Directly copy values from an array into a Surface.2603*2604* This is faster than blitting the `surface` property on a SurfaceArray2605*2606* The array must be the same dimensions as the Surface and will completely2607* replace all pixel values.2608* @param {gamejs.Surface} surface2609* @param {gamejs.surfacearray.SurfaceArray} surfaceArray2610*/2611exports.blitArray = function(surface, surfaceArray) {2612surface.context.putImageData(surfaceArray.imageData, 0, 0);2613return;2614};26152616/**2617* The SurfaceArray can be constructed with a surface whose values2618* are then used to initialize the pixel array.2619*2620* The surface passed as argument is not modified by the SurfaceArray.2621*2622* If an array is used to construct SurfaceArray, the array must describe2623* the dimensions of the SurfaceArray [width, height].2624*2625* @param {gamejs.Surface|Array} surfaceOrDimensions2626* @see http://dev.w3.org/html5/2dcontext/#pixel-manipulation2627*/2628var SurfaceArray = exports.SurfaceArray = function(surfaceOrDimensions) {2629var size = null;2630var data = null;2631var imageData = null;26322633/**2634* Set rgba value at position x, y.2635*2636* For performance reasons this function has only one signature2637* being Number, Number, Array[4].2638*2639* @param {Number} x x position of pixel2640* @param {Number} y y position of pixel2641* @param {Array} rgba [red, green, blue, alpha] values [255, 255, 255, 255] (alpha, the last argument defaults to 255)2642* @throws Error if x, y out of range2643*/2644this.set = function(x, y, rgba) {2645var offset = (x * 4) + (y * size[0] * 4);2646/** faster without2647if (offset + 3 >= data.length || x < 0 || y < 0) {2648throw new Error('x, y out of range', x, y);2649}2650**/2651data[offset] = rgba[0];2652data[offset+1] = rgba[1];2653data[offset+2] = rgba[2];2654data[offset+3] = rgba[3] === undefined ? 255 : rgba[3];2655return;2656};26572658/**2659* Get rgba value at position xy,2660* @param {Number} x2661* @param {Number} y2662* @returns {Array} [red, green, blue, alpha]2663*/2664this.get = function(x, y) {2665var offset = (x * 4) + (y * size[0] * 4);2666return [2667data[offset],2668data[offset+1],2669data[offset+2],2670data[offset+3]2671];2672};26732674/**2675* a new gamejs.Surface on every access, representing2676* the current state of the SurfaceArray.2677* @type {gamejs.Surface}2678*/2679// for jsdoc only2680this.surface = null;26812682accessors(this, {2683surface: {2684get: function() {2685var s = new gamejs.Surface(size);2686s.context.putImageData(imageData, 0, 0);2687return s;2688}2689},2690imageData: {2691get: function() {2692return imageData;2693}2694}2695});26962697this.getSize = function() {2698return size;2699};27002701/**2702* constructor2703*/2704if (surfaceOrDimensions instanceof Array) {2705size = surfaceOrDimensions;2706imageData = gamejs.display.getSurface().context.createImageData(size[0], size[1]);2707data = imageData.data;2708} else {2709size = surfaceOrDimensions.getSize();2710imageData = surfaceOrDimensions.getImageData(0, 0, size[0], size[1]);2711data = imageData.data;2712}2713return this;2714};27152716}}, ["gamejs", "gamejs/utils/objects"]);/* This file has been generated by yabbler.js */2717require.define({2718"gamejs/base64": function(require, exports, module) {2719/**2720* @fileoverview2721* Base64 encode / decode2722* @author http://www.webtoolkit.info2723*/272427252726var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";27272728/**2729* Decodes a base64 encoded string to a string.2730*/2731var decode = exports.decode = function(input) {2732var output = [], chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0;2733input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");27342735while (i < input.length) {2736enc1 = keyStr.indexOf(input.charAt(i++));2737enc2 = keyStr.indexOf(input.charAt(i++));2738enc3 = keyStr.indexOf(input.charAt(i++));2739enc4 = keyStr.indexOf(input.charAt(i++));27402741chr1 = (enc1 << 2) | (enc2 >> 4);2742chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);2743chr3 = ((enc3 & 3) << 6) | enc4;27442745output.push(String.fromCharCode(chr1));27462747if (enc3 != 64) {2748output.push(String.fromCharCode(chr2));2749}2750if (enc4 != 64) {2751output.push(String.fromCharCode(chr3));2752}2753}27542755output = output.join('');2756return output;2757};27582759/**2760* Decodes a base64 encoded string into a byte array2761* @param {String} input2762* @param {Array} bytes bytes per character, defaults to 12763*/2764exports.decodeAsArray = function(input, bytes) {2765bytes = bytes || 1;2766var decoded = decode(input);2767var len = decoded.length / bytes;2768var array = [];2769for (var i=0; i< len; i++) {2770array[i] = 0;2771for (var j = bytes - 1; j >=0; --j) {2772array[i] += decoded.charCodeAt((i * bytes) + j) << (j <<3 )2773}2774}2775return array;2776}27772778}}, []);/* This file has been generated by yabbler.js */2779require.define({2780"gamejs/image": function(require, exports, module) {2781var gamejs = require('../gamejs');27822783/**2784* @fileoverview Load images as Surfaces.2785*2786* Sounds & Images are loaded relative to your game's html page2787* (the html which includes the GameJs code) or relative to the2788* property `window.$g.resourceBaseHref`2789* if it is set.2790*2791*2792*/27932794var CACHE = {};27952796/**2797* need to export preloading status for require2798* @ignore2799*/2800var _PRELOADING = false;28012802/**2803* Load image and return it on a Surface.2804*2805* All images must be preloaded before they can be used.2806* @example28072808* gamejs.preload(["./images/ship.png", "./images/sunflower.png"]);2809* // ...later...2810* display.blit(gamejs.load('images/ship.png'))2811*2812* @param {String|dom.Image} uriOrImage resource uri for image2813* @returns {gamejs.Surface} surface with the image on it.2814*/2815exports.load = function(key) {2816var img;2817if (typeof key === 'string') {2818img = CACHE[key];2819if (!img) {2820// TODO sync image loading2821throw new Error('Missing "' + key + '", gamejs.preload() all images before trying to load them.');2822}2823} else {2824img = key;2825}2826var canvas = document.createElement('canvas');2827// IEFIX missing html5 feature naturalWidth/Height2828canvas.width = img.naturalWidth || img.width;2829canvas.height = img.naturalHeight || img.height;2830var context = canvas.getContext('2d');2831context.drawImage(img, 0, 0);2832img.getSize = function() { return [img.naturalWidth, img.naturalHeight]; };2833var surface = new gamejs.Surface(img.getSize());2834// NOTE hack setting protected _canvas directly2835surface._canvas = canvas;2836surface._context = context;2837return surface;2838};283928402841/**2842* add all images on the currrent page into cache2843* @ignore2844*/2845exports.init = function() {2846return;2847};28482849/**2850* preload the given img URIs2851* @returns {Function} which returns 0-1 for preload progress2852* @ignore2853*/2854exports.preload = function(imgIdents) {28552856var countLoaded = 0;2857var countTotal = 0;28582859function incrementLoaded() {2860countLoaded++;2861if (countLoaded == countTotal) {2862_PRELOADING = false;2863}2864if (countLoaded % 10 === 0) {2865gamejs.log('gamejs.image: preloaded ' + countLoaded + ' of ' + countTotal);2866}2867}28682869function getProgress() {2870return countTotal > 0 ? countLoaded / countTotal : 1;2871}28722873function successHandler() {2874addToCache(this);2875incrementLoaded();2876}2877function errorHandler() {2878incrementLoaded();2879throw new Error('Error loading ' + this.src);2880}28812882for (var key in imgIdents) {2883var lowerKey = key.toLowerCase();2884if (lowerKey.indexOf('.png') == -1 &&2885lowerKey.indexOf('.jpg') == -1 &&2886lowerKey.indexOf('.jpeg') == -1 &&2887lowerKey.indexOf('.svg') == -1 &&2888lowerKey.indexOf('.gif') == -1) {2889continue;2890}2891var img = new Image();2892img.addEventListener('load', successHandler, true);2893img.addEventListener('error', errorHandler, true);2894img.src = imgIdents[key];2895img.gamejsKey = key;2896countTotal++;2897}2898if (countTotal > 0) {2899_PRELOADING = true;2900}2901return getProgress;2902};29032904/**2905* add the given <img> dom elements into the cache.2906* @private2907*/2908var addToCache = function(img) {2909CACHE[img.gamejsKey] = img;2910return;2911};29122913}}, ["gamejs"]);/* This file has been generated by yabbler.js */2914require.define({2915"gamejs/utils/objects": function(require, exports, module) {2916/**2917* @fileoverview Utility functions for working with Objects2918*/29192920/**2921* Put a prototype into the prototype chain of another prototype.2922* @param {Object} subClass2923* @param {Object} superClass2924*/2925exports.extend = function(subClass, superClass) {2926if (subClass === undefined) {2927throw new Error('unknown subClass');2928}2929if (superClass === undefined) {2930throw new Error('unknown superClass');2931}2932// new Function() is evil2933var f = new Function();2934f.prototype = superClass.prototype;29352936subClass.prototype = new f();2937subClass.prototype.constructor = subClass;2938subClass.superClass = superClass.prototype;2939subClass.superConstructor = superClass;2940return;2941};29422943/**2944* Creates a new object as the as the keywise union of the provided objects.2945* Whenever a key exists in a later object that already existed in an earlier2946* object, the according value of the earlier object takes precedence.2947* @param {Object} obj... The objects to merge2948*/2949exports.merge = function() {2950var result = {};2951for (var i = arguments.length; i > 0; --i) {2952var obj = arguments[i - 1];2953for (var property in obj) {2954result[property] = obj[property];2955}2956}2957return result;2958};29592960/**2961* fallback for Object.keys2962* @param {Object} obj2963* @returns {Array} list of own properties2964* @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/keys2965*/2966var keys = exports.keys = function(obj) {2967if (Object.keys) {2968return Object.keys(obj);2969}29702971var ret=[],p;2972for (p in obj) {2973if(Object.prototype.hasOwnProperty.call(obj, p)) {2974ret.push(p);2975}2976}2977return ret;2978};29792980/**2981* Create object accessors2982* @param {Object} object The object on which to define the property2983* @param {String} name name of the property2984* @param {Function} get2985* @param {Function} set2986* @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty2987*/2988var accessor = exports.accessor = function(object, name, get, set) {2989// ECMA52990if (Object.defineProperty !== undefined) {2991Object.defineProperty(object, name, {2992get: get,2993set: set2994});2995// non-standard2996} else if (Object.prototype.__defineGetter__ !== undefined) {2997object.__defineGetter__(name, get);2998if (set) {2999object.__defineSetter__(name, set);3000}3001}3002return;3003};30043005/**3006* @param {Object} object The object on which to define or modify properties.3007* @param {Object} props An object whose own enumerable properties constitute descriptors for the properties to be defined or modified.3008* @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperties3009*/3010exports.accessors = function(object, props) {3011keys(props).forEach(function(propKey) {3012accessor(object, propKey, props[propKey].get, props[propKey].set);3013});3014return;3015};30163017}}, []);/* This file has been generated by yabbler.js */3018require.define({3019"gamejs/utils/uri": function(require, exports, module) {3020/**3021* @fileoverview Utilies for URI handling.3022*3023*/30243025var URI_REGEX = new RegExp(3026'^' +3027'(?:' +3028'([^:/?#.]+)' + // scheme - ignore special characters3029// used by other URL parts such as :,3030// ?, /, #, and .3031':)?' +3032'(?://' +3033'(?:([^/?#]*)@)?' + // userInfo3034'([\\w\\d\\-\\u0100-\\uffff.%]*)' + // domain - restrict to letters,3035// digits, dashes, dots, percent3036// escapes, and unicode characters.3037'(?::([0-9]+))?' + // port3038')?' +3039'([^?#]+)?' + // path3040'(?:\\?([^#]*))?' + // query3041'(?:#(.*))?' + // fragment3042'$');30433044/**3045* Resolve path against URI.3046*3047* @param {String} uri3048* @param {String} path to resolve3049*/3050var resolve = exports.resolve = function(uri, path) {3051var m = match(uri);3052var host = m[1] + '://' + m[3];3053if (m[4]) {3054host = host + ":" + m[4];3055}3056var absolutePath = m[5];3057if (path.charAt(0) !== '/') {3058var lastSlashIndex = absolutePath.lastIndexOf('/');3059absolutePath = absolutePath.substr(0, lastSlashIndex + 1) + path;3060} else {3061absolutePath = path;3062}3063return host + removeDotSegments(absolutePath);30643065};30663067/**3068* Try to match an URI against a regex returning the following3069* capture groups:3070* $1 = http scheme3071* $2 = <undefined> userInfo -\3072* $3 = www.ics.uci.edu domain | authority3073* $4 = <undefined> port -/3074* $5 = /pub/ietf/uri/ path3075* $6 = <undefined> query without ?3076* $7 = Related fragment without #3077*3078* @param {String} uri3079*/3080var match = exports.match = function(uri) {3081return uri.match(URI_REGEX);3082}30833084/**3085* Make an absolute URI relative to document.location.href3086* @param {String} uri3087* @returns The relative URI or the unchanged URI if it's not3088* possible to make it relative to the path of document.location.href.3089*/3090var makeRelative = exports.makeRelative = function(uri) {3091var docLocPath = resolve(document.location.href, './');3092if (uri.indexOf(docLocPath) == 0) {3093uri = './' + uri.substring(docLocPath.length);3094}3095return uri;3096};30973098/**3099* Removes dot segments in given path component3100*/3101var removeDotSegments = function(path) {3102if (path == '..' || path == '.') {3103return '';3104}3105var leadingSlash = path.indexOf('/') > -1;31063107var segments = path.split('/');3108var out = [];31093110for (var pos = 0; pos < segments.length; ) {3111var segment = segments[pos++];31123113if (segment == '.') {3114if (leadingSlash && pos == segments.length) {3115out.push('');3116}3117} else if (segment == '..') {3118if (out.length > 1 || out.length == 1 && out[0] != '') {3119out.pop();3120}3121if (leadingSlash && pos == segments.length) {3122out.push('');3123}3124} else {3125out.push(segment);3126leadingSlash = true;3127}3128}3129return out.join('/');3130};31313132}}, []);/* This file has been generated by yabbler.js */3133require.define({3134"gamejs/utils/strings": function(require, exports, module) {3135/**3136* Get the longest common segment that two strings3137* have in common, starting at the beginning of the string3138* @param {String} str1 a string3139* @param {String} str2 another string3140* @returns {String} the longest common segment3141*/3142exports.getCommonPrefix = function getCommonPrefix(str1, str2) {3143if (str1 == null || str2 == null) {3144return null;3145} else if (str1.length > str2.length && str1.indexOf(str2) == 0) {3146return str2;3147} else if (str2.length > str1.length && str2.indexOf(str1) == 0) {3148return str1;3149}3150var length = Math.min(str1.length, str2.length);3151for (var i = 0; i < length; i++) {3152if (str1[i] != str2[i]) {3153return str1.slice(0, i);3154}3155}3156return str1.slice(0, length);3157}31583159}}, []);/* This file has been generated by yabbler.js */3160require.define({3161"gamejs/utils/matrix": function(require, exports, module) {3162/**3163* @fileoverview Matrix manipulation, used by GameJs itself. You3164* probably do not need this unless you manipulate a Context's transformation3165* matrix yourself.3166*/31673168// correct way to do scale, rotate, translate3169// * gamejs.utils.matrix will be used in gamejs.transforms, modifing the surfaces.matrix3170// * this matrix must be applied to the context in Surface.draw()31713172/**3173* @returns {Array} [1, 0, 0, 1, 0, 0]3174*/3175var identiy = exports.identity = function () {3176return [1, 0, 0, 1, 0, 0];3177};31783179/**3180* @param {Array} matrix3181* @param {Array} matrix3182* @returns {Array} matrix sum3183*/3184var add = exports.add = function(m1, m2) {3185return [3186m1[0] + m2[0],3187m1[1] + m2[1],3188m1[2] + m2[2],3189m1[3] + m2[3],3190m1[4] + m2[4],3191m1[5] + m2[5],3192m1[6] + m2[6]3193];3194};31953196/**3197* @param {Array} matrix A3198* @param {Array} matrix B3199* @returns {Array} matrix product3200*/3201var multiply = exports.multiply = function(m1, m2) {3202return [3203m1[0] * m2[0] + m1[2] * m2[1],3204m1[1] * m2[0] + m1[3] * m2[1],3205m1[0] * m2[2] + m1[2] * m2[3],3206m1[1] * m2[2] + m1[3] * m2[3],3207m1[0] * m2[4] + m1[2] * m2[5] + m1[4],3208m1[1] * m2[4] + m1[3] * m2[5] + m1[5]3209];3210};32113212/**3213* @param {Array} matrix3214* @param {Number} dx3215* @param {Number} dy3216* @returns {Array} translated matrix3217*/3218var translate = exports.translate = function(m1, dx, dy) {3219return multiply(m1, [1, 0, 0, 1, dx, dy]);3220};32213222/**3223* @param {Array} matrix3224* @param {Number} angle in radians3225* @returns {Array} rotated matrix3226*/3227var rotate = exports.rotate = function(m1, angle) {3228// radians3229var sin = Math.sin(angle);3230var cos = Math.cos(angle);3231return multiply(m1, [cos, sin, -sin, cos, 0, 0]);3232};32333234/**3235* @param {Array} matrix3236* @returns {Number} rotation in radians3237*/3238var rotation = exports.rotation = function(m1) {3239return Math.atan2(m1[1], m1[0]);3240};32413242/**3243* @param {Array} matrix3244* @param {Array} vector [a, b]3245* @returns {Array} scaled matrix3246*/3247var scale = exports.scale = function(m1, svec) {3248var sx = svec[0];3249var sy = svec[1];3250return multiply(m1, [sx, 0, 0, sy, 0, 0]);3251};32523253}}, []);/* This file has been generated by yabbler.js */3254require.define({3255"gamejs/utils/math": function(require, exports, module) {3256/**3257*3258* absolute angle to relative angle, in degrees3259* @param {Number} absolute angle in degrees3260* @returns {Number} relative angle in degrees3261*/3262exports.normaliseDegrees=function(degrees){3263degrees=degrees % 360;3264if(degrees<0) {3265degrees+=360;3266}3267return degrees;3268};32693270/**3271*3272* absolute angle to relative angle, in radians3273* @param {Number} absolute angle in radians3274* @returns {Number} relative angle in radians3275*/3276exports.normaliseRadians=function(radians){3277radians=radians % (2*Math.PI);3278if(radians<0) {3279radians+=(2*Math.PI);3280}3281return radians;3282};32833284/**3285*3286* convert radians to degrees3287* @param {Number} radians3288* @returns {Number} degrees3289*/3290exports.degrees=function(radians) {3291return radians*(180/Math.PI);3292};32933294/**3295*3296* convert degrees to radians3297* @param {Number} degrees3298* @returns {Number} radians3299*/3300exports.radians=function(degrees) {3301return degrees*(Math.PI/180);3302};33033304/**3305* @returns the center of multipled 2d points3306* @param {Array} first point3307* @param {Array} second point3308* @param {Array} ...3309*/3310exports.centroid = function() {3311var args = Array.prototype.slice.apply(arguments, [0]);3312var c = [0,0];3313args.forEach(function(p) {3314c[0] += parseInt(p[0], 10);3315c[1] += parseInt(p[1], 10);3316});3317var len = args.length;3318return [3319c[0] / len,3320c[1] / len3321];3322};33233324}}, []);/* This file has been generated by yabbler.js */3325require.define({3326"gamejs/utils/vectors": function(require, exports, module) {3327var math=require('./math');33283329/**3330* @param {Array} origin point [b0, b1]3331* @param {Array} target point [b0, b1]3332* @returns {Number} distance between two points3333*/3334exports.distance = function(a, b) {3335return len(subtract(a, b));3336};33373338/**3339* subtracts vectors [a0, a1] - [a0, a1]3340* @param {Array} a3341* @param {Array} b3342* @returns {Array} vector3343*/3344var subtract = exports.subtract = function(a, b) {3345return [a[0] - b[0], a[1] - b[1]];3346};33473348/**3349* adds vectors [a0, a1] - [a0, a1]3350* @param {Array} a vector3351* @param {Array} b vector3352* @returns {Array} vector3353*/3354var add = exports.add = function(a, b) {3355return [a[0] + b[0], a[1] + b[1]];3356};33573358/**3359* multiply vector with scalar or other vector3360* @param {Array} vector [v0, v1]3361* @param {Number|Array} vector or number3362* @returns {Number|Array} result3363*/3364var multiply = exports.multiply = function(a, s) {3365if (typeof s === 'number') {3366return [a[0] * s, a[1] * s];3367}33683369return [a[0] * s[0], a[1] * s[1]];3370};33713372/**3373* @param {Array} a vector3374* @param {Number} s3375*/3376exports.divide = function(a, s) {3377if (typeof s === 'number') {3378return [a[0] / s, a[1] / s];3379}3380throw new Error('only divide by scalar supported');3381};33823383/**3384* @param {Array} vector [v0, v1]3385* @returns {Number} length of vector3386*/3387var len = exports.len = function(v) {3388return Math.sqrt(v[0]*v[0] + v[1]*v[1]);3389};33903391/**3392*3393* normalize vector to unit vector3394* @param {Array} vector [v0, v1]3395* @returns {Array} unit vector [v0, v1]3396*/3397var unit = exports.unit = function(v) {3398var l = len(v);3399if(l) return [v[0] / l, v[1] / l];3400return [0, 0];3401};34023403/**3404*3405* rotate vector3406* @param {Array} vector [v0, v1]3407* @param {Number} angle to rotate vector by, radians. can be negative3408* @returns {Array} rotated vector [v0, v1]3409*/3410exports.rotate=function(v, angle){3411angle=math.normaliseRadians(angle);3412return [v[0]* Math.cos(angle)-v[1]*Math.sin(angle),3413v[0]* Math.sin(angle)+v[1]*Math.cos(angle)];34143415};34163417/**3418*3419* calculate vector dot product3420* @param {Array} vector [v0, v1]3421* @param {Array} vector [v0, v1]3422* @returns {Number} dot product of v1 and v23423*/3424var dot = exports.dot=function(v1, v2){3425return (v1[0] * v2[0]) + (v1[1] * v2[1]);3426};34273428/**3429*3430* calculate angle between vectors3431* @param {Array} vector [v0, v1]3432* @param {Array} vector [v0, v1]3433* @returns {Number} angle between v1 and v2 in radians3434*/3435exports.angle=function(v1, v2){3436var a1 = Math.atan2(v1[0], v1[1]);3437var a2 = Math.atan2(v2[0], v2[1]);3438var rel = a1 - a2;3439return rel - Math.floor((rel + Math.PI) / (2 * Math.PI)) * (2 * Math.PI) - (2 * Math.PI);3440};34413442/**3443* @returns {Array} vector with max length as specified.3444*/3445exports.truncate = function(v, maxLength) {3446if (len(v) > maxLength) {3447return multiply(unit(v), maxLength);3448};3449return v;3450};34513452}}, ["gamejs/utils/math"]);/* This file has been generated by yabbler.js */3453require.define({3454"gamejs/utils/arrays": function(require, exports, module) {3455/**3456* @fileoverview Utility functions for working with Obiects3457* @param {Object} item3458* @param {Array} array3459* @param {Object} returns removed item or null3460*/34613462exports.remove = function(item, array) {3463var index = array.indexOf(item);3464if (index !== -1) {3465return array.splice(array.indexOf(item), 1);3466}3467return null;3468};34693470/**3471* Shuffles the array *in place*.3472* @see http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle3473*/3474exports.shuffle = function(array) {3475var len = array.length -1;3476for (i = len; i > 0; i--) {3477var idx = parseInt(Math.random() * (i + 1));3478var item = array[i];3479array[i] = array[idx];3480array[idx] = item;3481}3482return array;3483};34843485}}, []);/* This file has been generated by yabbler.js */3486require.define({3487"gamejs/utils/binaryheap": function(require, exports, module) {3488/**3489* Binary Heap3490*3491* @see http://eloquentjavascript.net/appendix2.html3492*/3493var BinaryHeap = exports.BinaryHeap = function(scoreFunction){3494/**3495* @ignore3496*/3497this.content = [];3498/**3499* @ignore3500*/3501this.scoreFunction = scoreFunction;3502return this;3503};35043505/**3506* Add element to heap.3507* @param {Object} element3508*/3509BinaryHeap.prototype.push = function(element) {3510this.content.push(element);3511this.sinkDown(this.content.length - 1);3512return;3513};35143515/**3516* Return first element from heap.3517* @param {Object} element3518* @returns {Object} element3519*/3520BinaryHeap.prototype.pop = function() {3521// Store the first element so we can return it later.3522var result = this.content[0];3523// Get the element at the end of the array.3524var end = this.content.pop();3525// If there are any elements left, put the end element at the3526// start, and let it bubble up.3527if (this.content.length > 0) {3528this.content[0] = end;3529this.bubbleUp(0);3530}3531return result;3532};35333534/**3535* Remove the given element from the heap.3536* @param {Object} element3537* @throws {Error} if node not found3538*/3539BinaryHeap.prototype.remove = function(node) {3540// To remove a value, we must search through the array to find3541// it.3542var isFound = this.content.some(function(cNode, idx) {3543if (cNode == node) {3544var end = this.content.pop();3545if (idx != this.content.length) {3546this.content[idx] = end;3547if (this.scoreFunction(end) < this.scoreFunction(node)) {3548this.sinkDown(idx);3549} else {3550this.bubbleUp(idx);3551}3552}3553return true;3554}3555return false;3556}, this);3557if (!isFound) {3558//throw new Error("Node not found.");3559}3560return;3561};35623563/**3564* Number of elements in heap.3565*/3566BinaryHeap.prototype.size = function() {3567return this.content.length;3568};35693570/**3571* @ignore3572*/3573BinaryHeap.prototype.sinkDown = function(idx) {3574// Fetch the element that has to be sunk3575var element = this.content[idx];3576// When at 0, an element can not sink any further.3577while (idx > 0) {3578// Compute the parent element's index, and fetch it.3579var parentIdx = Math.floor((idx + 1) / 2) - 1;3580var parent = this.content[parentIdx];3581// Swap the elements if the parent is greater.3582if (this.scoreFunction(element) < this.scoreFunction(parent)) {3583this.content[parentIdx] = element;3584this.content[idx] = parent;3585// Update 'n' to continue at the new position.3586idx = parentIdx;3587// Found a parent that is less, no need to sink any further.3588} else {3589break;3590}3591}3592return;3593};35943595/**3596* @ignore3597*/3598BinaryHeap.prototype.bubbleUp = function(idx) {3599// Look up the target element and its score.3600var length = this.content.length;3601var element = this.content[idx];3602var elemScore = this.scoreFunction(element);36033604while(true) {3605// Compute the indices of the child elements.3606var child2Idx = (idx + 1) * 2;3607var child1Idx= child2Idx - 1;3608// This is used to store the new position of the element,3609// if any.3610var swapIdx = null;3611// If the first child exists (is inside the array)...3612if (child1Idx < length) {3613// Look it up and compute its score.3614var child1 = this.content[child1Idx];3615var child1Score = this.scoreFunction(child1);3616// If the score is less than our element's, we need to swap.3617if (child1Score < elemScore) {3618swapIdx = child1Idx;3619}3620}3621// Do the same checks for the other child.3622if (child2Idx < length) {3623var child2 = this.content[child2Idx];3624var child2Score = this.scoreFunction(child2);3625if (child2Score < (swapIdx === null ? elemScore : child1Score)) {3626swapIdx = child2Idx;3627}3628}36293630// If the element needs to be moved, swap it, and continue.3631if (swapIdx !== null) {3632this.content[idx] = this.content[swapIdx];3633this.content[swapIdx] = element;3634idx = swapIdx;3635// Otherwise, we are done.3636} else {3637break;3638}3639}3640return;3641};36423643}}, []);/* This file has been generated by yabbler.js */3644require.define({3645"gamejs/font": function(require, exports, module) {3646var Surface = require('../gamejs').Surface;3647var objects = require('./utils/objects');36483649/**3650* @fileoverview Methods for creating Font objects which can render text3651* to a Surface.3652*3653* @example3654* // create a font3655* var font = new Font('20px monospace');3656* // render text - this returns a surface with the text written on it.3657* var helloSurface = font.render('Hello World')3658*/36593660/**3661* Create a Font to draw on the screen. The Font allows you to3662* `render()` text. Rendering text returns a Surface which3663* in turn can be put on screen.3664*3665* @constructor3666* @property {Number} fontHeight the line height of this Font3667*3668* @param {String} fontSettings a css font definition, e.g., "20px monospace"3669* @param {STring} backgroundColor valid #rgb string, "#ff00cc"3670*/3671var Font = exports.Font = function(fontSettings, backgroundColor) {3672/**3673* @ignore3674*/3675this.sampleSurface = new Surface([10,10]);3676this.sampleSurface.context.font = fontSettings;3677this.sampleSurface.context.textAlign = 'start';3678// http://diveintohtml5.org/canvas.html#text3679this.sampleSurface.context.textBaseline = 'bottom';3680this.backgroundColor = backgroundColor || false;3681return this;3682};36833684/**3685* Returns a Surface with the given text on it.3686* @param {String} text the text to render3687* @param {String} color a valid #RGB String, "#ffcc00"3688* @returns {gamejs.Surface} Surface with the rendered text on it.3689*/3690Font.prototype.render = function(text, color) {3691var dims = this.size(text);3692var surface = new Surface(dims);3693var ctx = surface.context;3694ctx.save();3695if ( this.backgroundColor ) {3696ctx.fillStyle = this.backgroundColor;3697ctx.fillRect(0, 0, surface.rect.width, surface.rect.height);3698}3699ctx.font = this.sampleSurface.context.font;3700ctx.textBaseline = this.sampleSurface.context.textBaseline;3701ctx.textAlign = this.sampleSurface.context.textAlign;3702ctx.fillStyle = ctx.strokeStyle = color || "#000000";3703ctx.fillText(text, 0, surface.rect.height, surface.rect.width);3704ctx.restore();3705return surface;3706};37073708/**3709* Determine the width and height of the given text if rendered3710* with this Font.3711* @param {String} text the text to measure3712* @returns {Array} the [width, height] of the text if rendered with this Font3713*/3714Font.prototype.size = function(text) {3715var metrics = this.sampleSurface.context.measureText(text);3716// FIXME measuretext is buggy, make extra wide3717return [metrics.width, this.fontHeight];3718};37193720/**3721* Height of the font in pixels.3722*/3723objects.accessors(Font.prototype, {3724'fontHeight': {3725get: function() {3726// Returns an approximate line height of the text3727// »This version of the specification does not provide a way to obtain3728// the bounding box dimensions of the text.«3729// see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-measuretext3730return this.sampleSurface.context.measureText('M').width * 1.5;3731}3732}37333734});37353736}}, ["gamejs", "gamejs/utils/objects"]);/* This file has been generated by yabbler.js */3737require.define({3738"gamejs": function(require, exports, module) {3739var matrix = require('./gamejs/utils/matrix');3740var objects = require('./gamejs/utils/objects');37413742/**3743* @fileoverview This module holds the essential `Rect` and `Surface` classes as3744* well as static methods for preloading assets. `gamejs.ready()` is maybe3745* the most important as it kickstarts your app.3746*3747*/37483749var DEBUG_LEVELS = ['info', 'warn', 'error', 'fatal'];3750var debugLevel = 2;37513752/**3753* set logLevel as string or number3754* * 0 = info3755* * 1 = warn3756* * 2 = error3757* * 3 = fatal3758*3759* @example3760* gamejs.setLogLevel(0); // debug3761* gamejs.setLogLevel('error'); // equal to setLogLevel(2)3762*/3763exports.setLogLevel = function(logLevel) {3764if (typeof logLevel === 'string' && DEBUG_LEVELS.indexOf(logLevel)) {3765debugLevel = DEBUG_LEVELS.indexOf(logLevel);3766} else if (typeof logLevel === 'number') {3767debugLevel = logLevel;3768} else {3769throw new Error('invalid logLevel ', logLevel, ' Must be one of: ', DEBUG_LEVELS);3770}3771return debugLevel;3772};3773/**3774* Log a msg to the console if console is enable3775* @param {String} msg the msg to log3776*/3777var log = exports.log = function() {37783779if (gamejs.worker.inWorker === true) {3780gamejs.worker._logMessage(arguments);3781return;3782}37833784// IEFIX can't call apply on console3785var args = Array.prototype.slice.apply(arguments, [0]);3786args.unshift(Date.now());3787if (window.console !== undefined && console.log.apply) {3788console.log.apply(console, args);3789}3790};3791exports.info = function() {3792if (debugLevel <= DEBUG_LEVELS.indexOf('info')) {3793log.apply(this, arguments);3794}3795};3796exports.warn = function() {3797if (debugLevel <= DEBUG_LEVELS.indexOf('warn')) {3798log.apply(this, arguments);3799}3800};3801exports.error = function() {3802if (debugLevel <= DEBUG_LEVELS.indexOf('error')) {3803log.apply(this, arguments);3804}3805};3806exports.fatal = function() {3807if (debugLevel <= DEBUG_LEVELS.indexOf('fatal')) {3808log.apply(this, arguments);3809}3810};38113812/**3813* Normalize various ways to specify a Rect into {left, top, width, height} form.3814*3815*/3816function normalizeRectArguments() {3817var left = 0;3818var top = 0;3819var width = 0;3820var height = 0;38213822if (arguments.length === 2) {3823if (arguments[0] instanceof Array && arguments[1] instanceof Array) {3824left = arguments[0][0];3825top = arguments[0][1];3826width = arguments[1][0];3827height = arguments[1][1];3828} else {3829left = arguments[0];3830top = arguments[1];3831}3832} else if (arguments.length === 1 && arguments[0] instanceof Array) {3833left = arguments[0][0];3834top = arguments[0][1];3835width = arguments[0][2];3836height = arguments[0][3];3837} else if (arguments.length === 1 && arguments[0] instanceof Rect) {3838left = arguments[0].left;3839top = arguments[0].top;3840width = arguments[0].width;3841height = arguments[0].height;3842} else if (arguments.length === 4) {3843left = arguments[0];3844top = arguments[1];3845width = arguments[2];3846height = arguments[3];3847} else {3848throw new Error('not a valid rectangle specification');3849}3850return {left: left || 0, top: top || 0, width: width || 0, height: height || 0};3851}38523853/**3854* Creates a Rect. Rects are used to hold rectangular areas. There are a couple3855* of convinient ways to create Rects with different arguments and defaults.3856*3857* Any function that requires a `gamejs.Rect` argument also accepts any of the3858* constructor value combinations `Rect` accepts.3859*3860* Rects are used a lot. They are good for collision detection, specifying3861* an area on the screen (for blitting) or just to hold an objects position.3862*3863* The Rect object has several virtual attributes which can be used to move and align the Rect:3864*3865* top, left, bottom, right3866* topleft, bottomleft, topright, bottomright3867* center3868* width, height3869* w,h3870*3871* All of these attributes can be assigned to.3872* Assigning to width or height changes the dimensions of the rectangle; all other3873* assignments move the rectangle without resizing it. Notice that some attributes3874* are Numbers and others are pairs of Numbers.3875*3876* @example3877* new Rect([left, top]) // width & height default to 03878* new Rect(left, top) // width & height default to 03879* new Rect(left, top, width, height)3880* new Rect([left, top], [width, height])3881* new Rect(oldRect) // clone of oldRect is created3882*3883* @property {Number} right3884* @property {Number} bottom3885* @property {Number} center3886*3887* @param {Array|gamejs.Rect} position Array holding left and top coordinates3888* @param {Array} dimensions Array holding width and height3889*/3890var Rect = exports.Rect = function() {38913892var args = normalizeRectArguments.apply(this, arguments);38933894/**3895* Left, X coordinate3896* @type Number3897*/3898this.left = args.left;38993900/**3901* Top, Y coordinate3902* @type Number3903*/3904this.top = args.top;39053906/**3907* Width of rectangle3908* @type Number3909*/3910this.width = args.width;39113912/**3913* Height of rectangle3914* @type Number3915*/3916this.height = args.height;39173918return this;3919};39203921objects.accessors(Rect.prototype, {3922/**3923* Bottom, Y coordinate3924* @name Rect.prototype.bottom3925* @type Number3926*/3927'bottom': {3928get: function() {3929return this.top + this.height;3930},3931set: function(newValue) {3932this.top = newValue - this.height;3933return;3934}3935},3936/**3937* Right, X coordinate3938* @name Rect.prototype.right3939* @type Number3940*/3941'right': {3942get: function() {3943return this.left + this.width;3944},3945set: function(newValue) {3946this.left = newValue - this.width;3947}3948},3949/**3950* Center Position. You can assign a rectangle form.3951* @name Rect.prototype.center3952* @type Array3953*/3954'center': {3955get: function() {3956return [this.left + (this.width / 2) | 0,3957this.top + (this.height / 2) | 03958];3959},3960set: function() {3961var args = normalizeRectArguments.apply(this, arguments);3962this.left = args.left - (this.width / 2) | 0;3963this.top = args.top - (this.height / 2) | 0;3964return;3965}3966},3967/**3968* Top-left Position. You can assign a rectangle form.3969* @name Rect.prototype.topleft3970* @type Array3971*/3972'topleft': {3973get: function() {3974return [this.left, this.top];3975},3976set: function() {3977var args = normalizeRectArguments.apply(this, arguments);3978this.left = args.left;3979this.top = args.top;3980return;3981}3982},3983/**3984* Bottom-left Position. You can assign a rectangle form.3985* @name Rect.prototype.bottomleft3986* @type Array3987*/3988'bottomleft': {3989get: function() {3990return [this.left, this.bottom];3991},3992set: function() {3993var args = normalizeRectArguments.apply(this, arguments);3994this.left = args.left;3995this.bottom = args.bottom;3996return;3997}3998},3999/**4000* Top-right Position. You can assign a rectangle form.4001* @name Rect.prototype.topright4002* @type Array4003*/4004'topright': {4005get: function() {4006return [this.right, this.top];4007},4008set: function() {4009var args = normalizeRectArguments.apply(this, arguments);4010this.right = args.right;4011this.top = args.top;4012return;4013}4014},4015/**4016* Bottom-right Position. You can assign a rectangle form.4017* @name Rect.prototype.bottomright4018* @type Array4019*/4020'bottomright': {4021get: function() {4022return [this.right, this.bottom];4023},4024set: function() {4025var args = normalizeRectArguments.apply(this, arguments);4026this.right = args.right;4027this.bottom = args.bottom;4028return;4029}4030},4031/**4032* Position x value, alias for `left`.4033* @name Rect.prototype.y4034* @type Array4035*/4036'x': {4037get: function() {4038return this.left;4039},4040set: function(newValue) {4041this.left = newValue;4042return;4043}4044},4045/**4046* Position y value, alias for `top`.4047* @name Rect.prototype.y4048* @type Array4049*/4050'y': {4051get: function() {4052return this.top;4053},4054set: function(newValue) {4055this.top = newValue;4056return;4057}4058}4059});40604061/**4062* Move returns a new Rect, which is a version of this Rect4063* moved by the given amounts. Accepts any rectangle form.4064* as argument.4065*4066* @param {Number|gamejs.Rect} x amount to move on x axis4067* @param {Number} y amount to move on y axis4068*/4069Rect.prototype.move = function() {4070var args = normalizeRectArguments.apply(this, arguments);4071return new Rect(this.left + args.left, this.top + args.top, this.width, this.height);4072};40734074/**4075* Move this Rect in place - not returning a new Rect like `move(x, y)` would.4076*4077* `moveIp(x,y)` or `moveIp([x,y])`4078*4079* @param {Number|gamejs.Rect} x amount to move on x axis4080* @param {Number} y amount to move on y axis4081*/4082Rect.prototype.moveIp = function() {4083var args = normalizeRectArguments.apply(this, arguments);4084this.left += args.left;4085this.top += args.top;4086return;4087};40884089/**4090* Return the area in which this Rect and argument Rect overlap.4091*4092* @param {gamejs.Rect} Rect to clip this one into4093* @returns {gamejs.Rect} new Rect which is completely inside the argument Rect,4094* zero sized Rect if the two rectangles do not overlap4095*/4096Rect.prototype.clip = function(rect) {4097if(!this.collideRect(rect)) {4098return new Rect(0,0,0,0);4099}41004101var x, y, width, height;41024103// Left4104if ((this.left >= rect.left) && (this.left < rect.right)) {4105x = this.left;4106} else if ((rect.left >= this.left) && (rect.left < this.right)) {4107x = rect.left;4108}41094110// Right4111if ((this.right > rect.left) && (this.right <= rect.right)) {4112width = this.right - x;4113} else if ((rect.right > this.left) && (rect.right <= this.right)) {4114width = rect.right - x;4115}41164117// Top4118if ((this.top >= rect.top) && (this.top < rect.bottom)) {4119y = this.top;4120} else if ((rect.top >= this.top) && (rect.top < this.bottom)) {4121y = rect.top;4122}41234124// Bottom4125if ((this.bottom > rect.top) && (this.bottom <= rect.bottom)) {4126height = this.bottom - y;4127} else if ((rect.bottom > this.top) && (rect.bottom <= this.bottom)) {4128height = rect.bottom - y;4129}4130return new Rect(x, y, width, height);4131};41324133/**4134* Join two rectangles4135*4136* @param {gamejs.Rect} union with this rectangle4137* @returns {gamejs.Rect} rectangle containing area of both rectangles4138*/4139Rect.prototype.union = function(rect) {4140var x, y, width, height;41414142x = Math.min(this.left, rect.left);4143y = Math.min(this.top, rect.top);4144width = Math.max(this.right, rect.right) - x;4145height = Math.max(this.bottom, rect.bottom) - y;4146return new Rect(x, y, width, height);4147};41484149/**4150* Grow or shrink the rectangle size4151*4152* @param {Number} amount to change in the width4153* @param {Number} amount to change in the height4154* @returns {gamejs.Rect} inflated rectangle centered on the original rectangle's center4155*/4156Rect.prototype.inflate = function(x, y) {4157var copy = this.clone();41584159copy.inflateIp(x, y);41604161return copy;4162}41634164/**4165* Grow or shrink this Rect in place - not returning a new Rect like `inflate(x, y)` would.4166*4167* @param {Number} amount to change in the width4168* @param {Number} amount to change in the height4169*/4170Rect.prototype.inflateIp = function(x, y) {4171// Use Math.floor here to deal with rounding of negative numbers the4172// way this relies on.4173this.left -= Math.floor(x / 2);4174this.top -= Math.floor(y / 2);4175this.width += x;4176this.height += y;4177}41784179/**4180* Check for collision with a point.4181*4182* `collidePoint(x,y)` or `collidePoint([x,y])` or `collidePoint(new Rect(x,y))`4183*4184* @param {Array|gamejs.Rect} point the x and y coordinates of the point to test for collision4185* @returns {Boolean} true if the point collides with this Rect4186*/4187Rect.prototype.collidePoint = function() {4188var args = normalizeRectArguments.apply(this, arguments);4189return (this.left <= args.left && args.left <= this.right) &&4190(this.top <= args.top && args.top <= this.bottom);4191};41924193/**4194* Check for collision with a Rect.4195* @param {gamejs.Rect} rect the Rect to test check for collision4196* @returns {Boolean} true if the given Rect collides with this Rect4197*/4198Rect.prototype.collideRect = function(rect) {4199return !(this.left > rect.right || this.right < rect.left ||4200this.top > rect.bottom || this.bottom < rect.top);4201};42024203/**4204* @param {Array} pointA start point of the line4205* @param {Array} pointB end point of the line4206* @returns true if the line intersects with the rectangle4207* @see http://stackoverflow.com/questions/99353/how-to-test-if-a-line-segment-intersects-an-axis-aligned-rectange-in-2d/293052#2930524208*4209*/4210Rect.prototype.collideLine = function(p1, p2) {4211var x1 = p1[0];4212var y1 = p1[1];4213var x2 = p2[0];4214var y2 = p2[1];42154216function linePosition(point) {4217var x = point[0];4218var y = point[1];4219return (y2 - y1) * x + (x1 - x2) * y + (x2 * y1 - x1 * y2);4220}42214222var relPoses = [[this.left, this.top],4223[this.left, this.bottom],4224[this.right, this.top],4225[this.right, this.bottom]4226].map(linePosition);42274228var noNegative = true;4229var noPositive = true;4230var noZero = true;4231relPoses.forEach(function(relPos) {4232if (relPos > 0) {4233noPositive = false;4234} else if (relPos < 0) {4235noNegative = false;4236} else if (relPos === 0) {4237noZero = false;4238}4239}, this);42404241if ( (noNegative || noPositive) && noZero) {4242return false;4243}4244return !((x1 > this.right && x2 > this.right) ||4245(x1 < this.left && x2 < this.left) ||4246(y1 < this.top && y2 < this.top) ||4247(y1 > this.bottom && y2 > this.bottom)4248);4249};42504251/**4252* @returns {String} Like "[x, y][w, h]"4253*/4254Rect.prototype.toString = function() {4255return ["[", this.left, ",", this.top, "]"," [",this.width, ",", this.height, "]"].join("");4256};42574258/**4259* @returns {gamejs.Rect} A new copy of this rect4260*/4261Rect.prototype.clone = function() {4262return new Rect(this);4263};42644265/**4266* A Surface represents a bitmap image with a fixed width and height. The4267* most important feature of a Surface is that they can be `blitted`4268* onto each other.4269*4270* @example4271* new gamejs.Surface([width, height]);4272* new gamejs.Surface(width, height);4273* new gamejs.Surface(rect);4274* @constructor4275*4276* @param {Array} dimensions Array holding width and height4277*/4278var Surface = exports.Surface = function() {4279var args = normalizeRectArguments.apply(this, arguments);4280var width = args.left;4281var height = args.top;4282// unless argument is rect:4283if (arguments.length == 1 && arguments[0] instanceof Rect) {4284width = args.width;4285height = args.height;4286}4287// only for rotatation & scale4288/** @ignore */4289this._matrix = matrix.identity();4290/** @ignore */4291this._canvas = document.createElement("canvas");4292this._canvas.width = width;4293this._canvas.height = height;4294/** @ignore */4295this._blitAlpha = 1.0;42964297/** @ignore */4298this._context = this._canvas.getContext('2d')4299this._smooth();4300return this;4301};43024303/** @ignore */4304Surface.prototype._noSmooth = function() {4305// disable image scaling4306// see https://developer.mozilla.org/en/Canvas_tutorial/Using_images#Controlling_image_scaling_behavior4307// and https://github.com/jbuck/processing-js/commit/65de16a8340c694cee471a2db7634733370b941c4308this.context.mozImageSmoothingEnabled = false;4309this.canvas.style.setProperty("image-rendering", "optimizeSpeed", "important");4310this.canvas.style.setProperty("image-rendering", "-moz-crisp-edges", "important");4311this.canvas.style.setProperty("image-rendering", "-webkit-optimize-contrast", "important");4312this.canvas.style.setProperty("image-rendering", "optimize-contrast", "important");4313this.canvas.style.setProperty("-ms-interpolation-mode", "nearest-neighbor", "important");4314return;4315};4316/** @ignore */4317Surface.prototype._smooth = function() {4318this.canvas.style.setProperty("image-rendering", "optimizeQuality", "important");4319this.canvas.style.setProperty("-ms-interpolation-mode", "bicubic", "important");4320this.context.mozImageSmoothingEnabled = true;4321};43224323/**4324* Blits another Surface on this Surface. The destination where to blit to4325* can be given (or it defaults to the top left corner) as well as the4326* Area from the Surface which should be blitted (e.g., for cutting out parts of4327* a Surface).4328*4329* @example4330* // blit flower in top left corner of display4331* displaySurface.blit(flowerSurface);4332*4333* // position flower at 10/10 of display4334* displaySurface.blit(flowerSurface, [10, 10])4335*4336* // ... `dest` can also be a rect whose topleft position is taken:4337* displaySurface.blit(flowerSurface, new gamejs.Rect([10, 10]);4338*4339* // only blit half of the flower onto the display4340* var flowerRect = flowerSurface.rect;4341* flowerRect = new gamejs.Rect([0,0], [flowerRect.width/2, flowerRect.height/2])4342* displaySurface.blit(flowerSurface, [0,0], flowerRect);4343*4344* @param {gamejs.Surface} src The Surface which will be blitted onto this one4345* @param {gamejs.Rect|Array} dst the Destination x, y position in this Surface.4346* If a Rect is given, it's top and left values are taken. If this argument4347* is not supplied the blit happens at [0,0].4348* @param {gamesjs.Rect|Array} area the Area from the passed Surface which4349* should be blitted onto this Surface.4350* @param {Number} compositionOperation how the source and target surfaces are composited together; one of: source-atop, source-in, source-out, source-over (default), destination-atop, destination-in, destination-out, destination-over, lighter, copy, xor; for an explanation of these values see: http://dev.w3.org/html5/2dcontext/#dom-context-2d-globalcompositeoperation4351* @returns {gamejs.Rect} Rect actually repainted FIXME actually return something?4352*/4353Surface.prototype.blit = function(src, dest, area, compositeOperation) {43544355var rDest, rArea;43564357if (dest instanceof Rect) {4358rDest = dest.clone();4359var srcSize = src.getSize();4360if (!rDest.width) {4361rDest.width = srcSize[0];4362}4363if (!rDest.height) {4364rDest.height = srcSize[1];4365}4366} else if (dest && dest instanceof Array && dest.length == 2) {4367rDest = new Rect(dest, src.getSize());4368} else {4369rDest = new Rect([0,0], src.getSize());4370}4371compositeOperation = compositeOperation || 'source-over';43724373// area within src to be drawn4374if (area instanceof Rect) {4375rArea = area;4376} else if (area && area instanceof Array && area.length == 2) {4377var size = src.getSize();4378rArea = new Rect(area, [size[0] - area[0], size[1] - area[1]]);4379} else {4380rArea = new Rect([0,0], src.getSize());4381}43824383if (isNaN(rDest.left) || isNaN(rDest.top) || isNaN(rDest.width) || isNaN(rDest.height)) {4384throw new Error('[blit] bad parameters, destination is ' + rDest);4385}43864387this.context.save();4388this.context.globalCompositeOperation = compositeOperation;4389// first translate, then rotate4390var m = matrix.translate(matrix.identity(), rDest.left, rDest.top);4391m = matrix.multiply(m, src._matrix);4392this.context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);4393// drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)4394this.context.globalAlpha = src._blitAlpha;4395this.context.drawImage(src.canvas, rArea.left, rArea.top, rArea.width, rArea.height, 0, 0, rDest.width, rDest.height);4396this.context.restore();4397return;4398};43994400/**4401* @returns {Number[]} the width and height of the Surface4402*/4403Surface.prototype.getSize = function() {4404return [this.canvas.width, this.canvas.height];4405};44064407/**4408* Obsolte, only here for compatibility.4409* @deprecated4410* @ignore4411* @returns {gamejs.Rect} a Rect of the size of this Surface4412*/4413Surface.prototype.getRect = function() {4414return new Rect([0,0], this.getSize());4415};44164417/**4418* Fills the whole Surface with a color. Usefull for erasing a Surface.4419* @param {String} CSS color string, e.g. '#0d120a' or '#0f0' or 'rgba(255, 0, 0, 0.5)'4420* @param {gamejs.Rect} a Rect of the area to fill (defauts to entire surface if not specified)4421*/4422Surface.prototype.fill = function(color, rect) {4423this.context.save();4424this.context.fillStyle = color || "#000000";4425if ( rect === undefined )4426rect = new Rect(0, 0, this.canvas.width, this.canvas.height);44274428this.context.fillRect(rect.left, rect.top, rect.width, rect.height);4429this.context.restore();4430return;4431};44324433/**4434* Clear the surface.4435*/4436Surface.prototype.clear = function(rect) {4437var size = this.getSize();4438rect = rect || new Rect(0, 0, size[0], size[1]);4439this.context.clearRect(rect.left, rect.top, rect.width, rect.height);4440return;4441};44424443/**4444* Crop the surface by a given amount4445*/4446Surface.prototype.crop = function ( rect )4447{4448if ( typeof(this._originalImg) == 'undefined' )4449{4450var _size = this.getSize();4451this._originalImg = new gamejs.Surface([_size[0], _size[1]]);44524453var originalSize = new gamejs.Rect(0, 0, _size[0], _size[1]);4454this._originalImg.blit(this, originalSize, originalSize);4455}44564457this.clear();44584459this.canvas.width = rect.width;4460this.canvas.height = rect.height;44614462var newPos = new gamejs.Rect([0,0], [rect.width, rect.height]);4463this.blit( this._originalImg, newPos, rect);4464}44654466objects.accessors(Surface.prototype, {4467/**4468* @type gamejs.Rect4469*/4470'rect': {4471get: function() {4472return this.getRect();4473}4474},4475/**4476* @ignore4477*/4478'context': {4479get: function() {4480return this._context;4481}4482},4483'canvas': {4484get: function() {4485return this._canvas;4486}4487}4488});44894490/**4491* @returns {gamejs.Surface} a clone of this surface4492*/4493Surface.prototype.clone = function() {4494var newSurface = new Surface(this.getRect());4495newSurface.blit(this);4496return newSurface;4497};44984499/**4500* @returns {Number} current alpha value4501*/4502Surface.prototype.getAlpha = function() {4503return (1 - this._blitAlpha);4504};45054506/**4507* Set the alpha value for the whole Surface. When blitting the Surface on4508* a destination, the pixels will be drawn slightly transparent.4509* @param {Number} alpha value in range 0.0 - 1.04510* @returns {Number} current alpha value4511*/4512Surface.prototype.setAlpha = function(alpha) {4513if (isNaN(alpha) || alpha < 0 || alpha > 1) {4514return;4515}45164517this._blitAlpha = (1 - alpha);4518return (1 - this._blitAlpha);4519};45204521/**4522* The data must be represented in left-to-right order, row by row top to bottom,4523* starting with the top left, with each pixel's red, green, blue, and alpha components4524* being given in that order for each pixel.4525* @see http://dev.w3.org/html5/2dcontext/#canvaspixelarray4526* @returns {ImageData} an object holding the pixel image data {data, width, height}4527*/4528Surface.prototype.getImageData = function() {4529var size = this.getSize();4530return this.context.getImageData(0, 0, size[0], size[1]);4531};45324533/**4534* @ignore4535*/4536exports.display = require('./gamejs/display');4537/**4538* @ignore4539*/4540exports.draw = require('./gamejs/draw');4541/**4542* @ignore4543*/4544exports.event = require('./gamejs/event');4545/**4546* @ignore4547*/4548exports.font = require('./gamejs/font');4549/**4550* @ignore4551*/4552exports.http = require('./gamejs/http');4553/**4554* @ignore4555*/4556exports.image = require('./gamejs/image');4557/**4558* @ignore4559*/4560exports.mask = require('./gamejs/mask');4561/**4562* @ignore4563*/4564exports.mixer = require('./gamejs/mixer');4565/**4566* @ignore4567*/4568exports.sprite = require('./gamejs/sprite');4569/**4570* @ignore4571*/4572exports.surfacearray = require('./gamejs/surfacearray');4573/**4574* @ignore4575*/4576exports.time = require('./gamejs/time');4577/**4578* @ignore4579*/4580exports.transform = require('./gamejs/transform');45814582/**4583* @ignore4584*/4585exports.utils = {4586arrays: require('./gamejs/utils/arrays'),4587objects: require('./gamejs/utils/objects'),4588matrix: require('./gamejs/utils/matrix'),4589vectors: require('./gamejs/utils/vectors'),4590math: require('./gamejs/utils/math'),4591uri: require('./gamejs/utils/uri')4592};45934594/**4595* @ignore4596*/4597exports.pathfinding = {4598astar: require('./gamejs/pathfinding/astar')4599};46004601/**4602* @ignore4603*/4604exports.worker = require('./gamejs/worker');46054606/**4607* @ignore4608*/4609exports.base64 = require('./gamejs/base64');46104611/**4612* @ignore4613*/4614exports.xml = require('./gamejs/xml');46154616/**4617* @ignore4618*/4619exports.tmx = require('./gamejs/tmx');46204621// preloading stuff4622var gamejs = exports;4623var RESOURCES = {};46244625/**4626* ReadyFn is called once all modules and assets are loaded.4627* @param {Function} readyFn the function to be called once gamejs finished loading4628* @name ready4629*/4630if (gamejs.worker.inWorker === true) {4631exports.ready = function(readyFn) {4632gamejs.worker._ready();4633gamejs.init();4634readyFn();4635}4636} else {4637exports.ready = function(readyFn) {46384639var getMixerProgress = null;4640var getImageProgress = null;46414642// init time instantly - we need it for preloaders4643gamejs.time.init();46444645// 2.4646function _ready() {4647if (!document.body) {4648return window.setTimeout(_ready, 50);4649}4650getImageProgress = gamejs.image.preload(RESOURCES);4651try {4652getMixerProgress = gamejs.mixer.preload(RESOURCES);4653} catch (e) {4654gamejs.debug('Error loading audio files ', e);4655}4656window.setTimeout(_readyResources, 50);4657}46584659// 3.4660function _readyResources() {4661if (getImageProgress() < 1 || getMixerProgress() < 1) {4662return window.setTimeout(_readyResources, 100);4663}4664gamejs.display.init();4665gamejs.image.init();4666gamejs.mixer.init();4667gamejs.event.init();4668readyFn();4669}46704671// 1.4672window.setTimeout(_ready, 13);46734674function getLoadProgress() {4675if (getImageProgress) {4676return (0.5 * getImageProgress()) + (0.5 * getMixerProgress());4677}4678return 0.1;4679}46804681return getLoadProgress;4682};4683}46844685/**4686* Initialize all gamejs modules. This is automatically called4687* by `gamejs.ready()`.4688* @returns {Object} the properties of this objecte are the moduleIds that failed, they value are the exceptions4689* @ignore4690*/4691exports.init = function() {4692var errorModules = {};4693['time', 'display', 'image', 'mixer', 'event'].forEach(function(moduleName) {4694try {4695gamejs[moduleName].init();4696} catch (e) {4697errorModules[moduleName] = e.toString();4698}4699});4700return errorModules;4701}47024703function resourceBaseHref() {4704return (window.$g && window.$g.resourceBaseHref) || document.location.href;4705}47064707/**4708* Preload resources.4709* @param {Array} resources list of resources paths4710* @name preload4711*/4712var preload = exports.preload = function(resources) {4713var uri = require('./gamejs/utils/uri');4714var baseHref = resourceBaseHref();4715resources.forEach(function(res) {4716RESOURCES[res] = uri.resolve(baseHref, res);4717}, this);4718return;4719};47204721}}, ["gamejs/utils/matrix", "gamejs/utils/objects", "gamejs/display", "gamejs/draw", "gamejs/event", "gamejs/font", "gamejs/http", "gamejs/image", "gamejs/mask", "gamejs/mixer", "gamejs/sprite", "gamejs/surfacearray", "gamejs/time", "gamejs/transform", "gamejs/utils/arrays", "gamejs/utils/vectors", "gamejs/utils/math", "gamejs/utils/uri", "gamejs/pathfinding/astar", "gamejs/worker", "gamejs/base64", "gamejs/xml", "gamejs/tmx"]);47224723