From 0b4bb544414f558c805e463fef542e442bb7e848 Mon Sep 17 00:00:00 2001 From: Evert Prants Date: Sun, 19 Aug 2018 18:31:10 +0300 Subject: [PATCH] HTTP request, Tiled map loading --- dist/dwelibs.min.js | 2 +- src/file.js | 40 ++++++++++++ src/image.js | 27 ++++++++ src/index.js | 6 ++ src/tiled.js | 146 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 src/file.js create mode 100644 src/tiled.js diff --git a/dist/dwelibs.min.js b/dist/dwelibs.min.js index d4b4d13..f27986d 100644 --- a/dist/dwelibs.min.js +++ b/dist/dwelibs.min.js @@ -1 +1 @@ -!function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(r,o,function(e){return t[e]}.bind(null,o));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=0)}([function(t,e,n){"use strict";window.DWE={};n(1),n(2),n(3),n(4),n(5)},function(t,e,n){"use strict";DWE.context=function(t){return t.star=function(e,n,r,o,i){var a=Math.PI/2*3,u=e,c=n,s=Math.PI/r;t.beginPath(),t.moveTo(e,n-o);for(var h=0;hthis.width/2+t.r)&&(!(e.y>this.height/2+t.r)&&(e.x<=this.width/2||(e.y<=this.height/2||Math.pow(e.x-this.width/2,2)+Math.pow(e.y-this.height/2,2)<=Math.pow(t.r,2))))}}]),t}(),DWE.Math.Circle=function(){function t(e,n,r){o(this,t),this.x=e,this.y=n,this.r=r}return r(t,[{key:"radius",get:function(){return this.r}}]),t}()},function(t,e,n){"use strict";DWE.getMousePosition=function(t,e){var n=void 0,r=void 0;if(t.changedTouches){var o=t.changedTouches[0];o&&(t.pageX=o.pageX,t.pageY=o.pageY)}return t.pageX||t.pageY?(n=t.pageX,r=t.pageY):(n=t.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,r=t.clientY+document.body.scrollTop+document.documentElement.scrollTop),n-=e.offsetLeft,r-=e.offsetTop,new DWE.Math.Vector2(n,r)}},function(t,e,n){"use strict";DWE.Keyboard={};var r={},o={},i={backspace:8,tab:9,enter:13,shift:16,ctrl:17,alt:18,pausebreak:19,capslock:20,escape:27,pgup:33,pgdown:34,end:35,home:36,left:37,up:38,right:39,down:40,insert:45,delete:46,"left-window":91,"right-window":92,select:93,numpad0:96,numpad1:97,numpad2:98,numpad3:99,numpad4:100,numpad5:101,numpad6:102,numpad7:103,numpad8:104,numpad9:105,multiply:106,add:107,subtract:109,decimal:110,divide:111,f1:112,f2:113,f3:114,f4:115,f5:116,f6:117,f7:118,f8:119,f9:120,f10:121,f11:122,f12:123,numlock:144,scrolllock:145,"semi-colon":186,equals:187,comma:188,dash:189,period:190,fwdslash:191,grave:192,"open-bracket":219,bkslash:220,"close-braket":221,"single-quote":222};function a(t){return null!=r[t]&&r[t]}function u(t){return null!=o[t]&&o[t]}DWE.Keyboard.toggleKey=function(t,e){var n=null;for(var o in i){if(t===i[o]){n=o;break}}n||(n=String.fromCharCode(t).toLowerCase()),r[n]=!0===e},DWE.Keyboard.keyDown=function(t){var e;window.event?e=window.event.keyCode:t&&(e=t.which),DWE.Keyboard.toggleKey(e,!0)},DWE.Keyboard.keyUp=function(t){var e;window.event?e=window.event.keyCode:t&&(e=t.which),DWE.Keyboard.toggleKey(e,!1)},DWE.Keyboard.isDown=function(t){return a(t)&&u(t)},DWE.Keyboard.isUp=function(t){return!DWE.Keyboard.isDown(t)},DWE.Keyboard.isPressed=function(t){return!0===a(t)&&!1===u(t)},DWE.Keyboard.nextIteration=function(){for(var t in o={},r)!0===r[t]&&(o[t]=!0)}},function(t,e,n){"use strict";DWE.Image={},DWE.Image.Image=function(t){var e=this;this.src=t,this.img=new Image,this.img.src=this.src,this.width=0,this.height=0,this.loaded=!1,this.errored=!1,this.img.onload=function(){e.loaded=!0,e.width=e.img.width,e.height=e.img.height,e.onload&&e.onload.apply(e,[])},this.img.onerror=function(t){e.loaded=!1,e.errored=!0,e.onerror&&e.onerror.apply(e,[t])}},DWE.Image.loadImageArray=function(t){return new Promise(function(e,n){var r=0,o=t.length,i=[];!function a(u){var c=t[u],s=new DWE.Image.Image(c);s.onload=function(){i.push(s),++r==o?e(i):a(r)},s.onerror=function(t){n(t)}}(r)})}}]); \ No newline at end of file +!function(t){var e={};function n(i){if(e[i])return e[i].exports;var r=e[i]={i:i,l:!1,exports:{}};return t[i].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=t,n.c=e,n.d=function(t,e,i){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)n.d(i,r,function(e){return t[e]}.bind(null,r));return i},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=0)}([function(t,e,n){"use strict";window.DWE={};n(1),n(2),n(3),n(4),n(5),n(6),n(7)},function(t,e,n){"use strict";DWE.context=function(t){return t.star=function(e,n,i,r,o){var a=Math.PI/2*3,s=e,u=n,l=Math.PI/i;t.beginPath(),t.moveTo(e,n-r);for(var h=0;hthis.width/2+t.r)&&(!(e.y>this.height/2+t.r)&&(e.x<=this.width/2||(e.y<=this.height/2||Math.pow(e.x-this.width/2,2)+Math.pow(e.y-this.height/2,2)<=Math.pow(t.r,2))))}}]),t}(),DWE.Math.Circle=function(){function t(e,n,i){r(this,t),this.x=e,this.y=n,this.r=i}return i(t,[{key:"radius",get:function(){return this.r}}]),t}()},function(t,e,n){"use strict";DWE.getMousePosition=function(t,e){var n=void 0,i=void 0;if(t.changedTouches){var r=t.changedTouches[0];r&&(t.pageX=r.pageX,t.pageY=r.pageY)}return t.pageX||t.pageY?(n=t.pageX,i=t.pageY):(n=t.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,i=t.clientY+document.body.scrollTop+document.documentElement.scrollTop),n-=e.offsetLeft,i-=e.offsetTop,new DWE.Math.Vector2(n,i)}},function(t,e,n){"use strict";DWE.Keyboard={};var i={},r={},o={backspace:8,tab:9,enter:13,shift:16,ctrl:17,alt:18,pausebreak:19,capslock:20,escape:27,pgup:33,pgdown:34,end:35,home:36,left:37,up:38,right:39,down:40,insert:45,delete:46,"left-window":91,"right-window":92,select:93,numpad0:96,numpad1:97,numpad2:98,numpad3:99,numpad4:100,numpad5:101,numpad6:102,numpad7:103,numpad8:104,numpad9:105,multiply:106,add:107,subtract:109,decimal:110,divide:111,f1:112,f2:113,f3:114,f4:115,f5:116,f6:117,f7:118,f8:119,f9:120,f10:121,f11:122,f12:123,numlock:144,scrolllock:145,"semi-colon":186,equals:187,comma:188,dash:189,period:190,fwdslash:191,grave:192,"open-bracket":219,bkslash:220,"close-braket":221,"single-quote":222};function a(t){return null!=i[t]&&i[t]}function s(t){return null!=r[t]&&r[t]}DWE.Keyboard.toggleKey=function(t,e){var n=null;for(var r in o){if(t===o[r]){n=r;break}}n||(n=String.fromCharCode(t).toLowerCase()),i[n]=!0===e},DWE.Keyboard.keyDown=function(t){var e;window.event?e=window.event.keyCode:t&&(e=t.which),DWE.Keyboard.toggleKey(e,!0)},DWE.Keyboard.keyUp=function(t){var e;window.event?e=window.event.keyCode:t&&(e=t.which),DWE.Keyboard.toggleKey(e,!1)},DWE.Keyboard.isDown=function(t){return a(t)&&s(t)},DWE.Keyboard.isUp=function(t){return!DWE.Keyboard.isDown(t)},DWE.Keyboard.isPressed=function(t){return!0===a(t)&&!1===s(t)},DWE.Keyboard.nextIteration=function(){for(var t in r={},i)!0===i[t]&&(r[t]=!0)}},function(t,e,n){"use strict";var i=function(){function t(t,e){for(var n=0;n=400&&i(r.responseText)},r.open("GET",t,!0),r.responseType=e?"xml":"text",r.send(null)})},DWE.File.loadXML=function(t){return DWE.File.httpGET(t,!0)},DWE.File.loadJson=function(t){return new Promise(function(e,n){DWE.File.httpGET(t).then(function(t){var i;try{i=JSON.parse(t)}catch(t){return n(t)}e(i)},n)})}},function(t,e,n){"use strict";var i=function(){function t(t,e){for(var n=0;n=a.offset&&u.tile<=l&&a.draw(t,u.tile-1,u.x*this.tileWidth*this.scale+e.x+r.x+n.x,u.y*this.tileHeight*this.scale+e.y+r.y+n.y,this.tileWidth*this.scale,this.tileHeight*this.scale)}}}},{key:"collideLayer",value:function(t,e){if(!this.layers[e])return null;this.layers[e];return null}},{key:"setScale",value:function(t){this.scale=t}}]),t}()}]); \ No newline at end of file diff --git a/src/file.js b/src/file.js new file mode 100644 index 0000000..6b60832 --- /dev/null +++ b/src/file.js @@ -0,0 +1,40 @@ + +DWE.File = {} + +DWE.File.httpGET = function (url, xml) { + return new Promise(function (resolve, reject) { + var xmlHttp = new XMLHttpRequest() + + xmlHttp.onreadystatechange = function() { + if (xmlHttp.readyState == 4 && xmlHttp.status == 200) { + resolve(xml === true ? xmlHttp.response : xmlHttp.responseText) + } else if (xmlHttp.readyState == 4 && xmlHttp.status >= 400) { + reject(xmlHttp.responseText) + } + } + + xmlHttp.open('GET', url, true) + xmlHttp.responseType = xml ? 'xml' : 'text' + xmlHttp.send(null) + }) +} + +DWE.File.loadXML = function (url) { + return DWE.File.httpGET(url, true) +} + +DWE.File.loadJson = function (url) { + return new Promise(function (resolve, reject) { + var promise = DWE.File.httpGET(url) + promise.then(function (data) { + var json + try { + json = JSON.parse(data) + } catch (e) { + return reject(e) + } + + resolve(json) + }, reject) + }) +} diff --git a/src/image.js b/src/image.js index 5bb9143..1ed87e1 100644 --- a/src/image.js +++ b/src/image.js @@ -32,6 +32,33 @@ DWE.Image.Image = function (src) { } } +DWE.Image.TileMap = class TileMap extends DWE.Image.Image { + constructor (src, aspectWidth, aspectHeight) { + super(src) + this.aspectWidth = aspectWidth + this.aspectHeight = aspectHeight + this.tiles = [] + } + + onload () { + for (let y = 0; y < this.height / this.aspectHeight; y++) { + for (let x = 0; x < this.width / this.aspectWidth; x++) { + this.tiles.push(new DWE.Math.Vector2(x, y)) + } + } + + if (this['onready']) { + this.onready.call(this, this) + } + } + + draw (ctx, index, x, y, w, h) { + let box = this.tiles[index] + if (!box) return + ctx.drawImage(this.img, box.x * this.aspectWidth, box.y * this.aspectHeight, this.aspectWidth, this.aspectHeight, x, y, w, h) + } +} + // Load an array of image URLs // Returns a Promise DWE.Image.loadImageArray = function (uris) { diff --git a/src/index.js b/src/index.js index 5b629a5..00b2ef9 100644 --- a/src/index.js +++ b/src/index.js @@ -14,3 +14,9 @@ require('./keyboard.js') // Image helpers require('./image.js') + +// File helpers +require('./file.js') + +// File helpers +require('./tiled.js') diff --git a/src/tiled.js b/src/tiled.js new file mode 100644 index 0000000..cb2edbd --- /dev/null +++ b/src/tiled.js @@ -0,0 +1,146 @@ + +DWE.Tiled = {} + +DWE.Tiled.Map = class { + constructor (file) { + this.file = file + let fname = file.split('/') + this.name = fname[fname.length - 1] + this.dir = fname.slice(0, -1).join('/') + this.loaded = false + + this.tileMaps = [] + this.layers = {} + this.tileWidth = 0 + this.tileHeight = 0 + this.scale = 1 + + this.loadTiledMap() + } + + done () { + if (this['onready']) { + this.onready.apply(this, [this]) + } + this.loaded = true + } + + error (e) { + if (this['onerror']) + this.onerror.apply(this, [e]) + else + console.error(e) + + this.loaded = false + } + + loadTiledMap () { + DWE.File.loadJson(this.file).then((mapData) => { + // Currently, only allow orthogonal and right-down options. + if (mapData.orientation !== 'orthogonal' || mapData.renderorder !== 'right-down') + return this.error(new Error('Currently, DWE Libs only allows orthogonal orientation and right-down render order.')) + + var map = this + + // Load map layers + function loadMapLayers () { + let width = mapData.width + let height = mapData.height + for (let i in mapData.layers) { + let layer = mapData.layers[i] + let tiles = [] + if (layer.type != 'tilelayer' || !layer.visible) continue + + for(let i = 0; i < width; i++) { + for(let j = 0; j < height; j++) { + let value = layer.data[(j * width) + i] + if (value == 0) continue + + tiles.push({ + x: i, + y: j, + tile: value + }) + } + } + + map.layers[layer.name] = { + tiles, x: parseInt(layer.x), y: parseInt(layer.y) + } + } + + map.width = width + map.height = height + + map.tileWidth = mapData.tilewidth + map.tileHeight = mapData.tileheight + + map.done() + } + + // Load tile maps + function loadNextTileMap(index) { + if (index === mapData.tilesets.length) return loadMapLayers() + var xtile = mapData.tilesets[index] + var path = map.dir + '/' + xtile.source + + DWE.File.loadXML(path).then(function (data) { + var parser = new DOMParser() + var doc = parser.parseFromString(data, 'application/xml') + var tilesets = doc.getElementsByTagName('tileset') + var dataf = {} + for (let i in tilesets) { + let d = tilesets[i] + if (!(d instanceof Element)) continue + let tw = parseInt(d.getAttribute('tilewidth')) + let th = parseInt(d.getAttribute('tileheight')) + let imgfile = d.getElementsByTagName('image')[0] + if (imgfile) { + let img = new DWE.Image.TileMap(map.dir + '/' + imgfile.getAttribute('source'), tw, th) + img.onready = function () { + loadNextTileMap(index + 1) + } + img.offset = xtile.firstgid + img.tileCount = parseInt(d.getAttribute('tilecount')) + map.tileMaps.push(img) + } + } + }, function (e) { + map.error.apply(map, [e]) + }) + } + + loadNextTileMap(0) + }, function (e) { + map.error.apply(map, [e]) + }) + } + + drawLayer (ctx, origin, viewport, name) { + if (!this.layers[name]) return null + let layer = this.layers[name] + for (let i in this.tileMaps) { + let t = this.tileMaps[i] + for (let j in layer.tiles) { + let tile = layer.tiles[j] + let tcount = t.tileCount || t.tiles.length + if (tile.tile >= t.offset && tile.tile <= tcount) { + t.draw(ctx, tile.tile - 1, ((tile.x * this.tileWidth * this.scale) + origin.x + layer.x) + viewport.x, + ((tile.y * this.tileHeight * this.scale) + origin.y + layer.y) + viewport.y, this.tileWidth * this.scale, + this.tileHeight * this.scale) + } + } + } + } + + collideLayer (object, name) { + if (!this.layers[name]) return null + let layer = this.layers[name] + // TODO: Handle object collisions with map tiles + return null + } + + setScale (scale) { + this.scale = scale + } +}