This repository has been archived on 2022-11-26. You can view files and clone it, but cannot push or open issues or pull requests.
dwelibs/src/tiled.js

174 lines
5.0 KiB
JavaScript

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 () {
var width = mapData.width
var height = mapData.height
for (let i in mapData.layers) {
let layer = mapData.layers[i]
let lw = layer.width || width
let lh = layer.height || height
let tiles = []
if (layer.type != 'tilelayer' || !layer.visible) continue
for(let i = 0; i < lw; i++) {
for(let j = 0; j < lh; j++) {
let value = layer.data[(j * lw) + 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.httpGET(path).then(function (data) {
var parser = new DOMParser()
var doc = parser.parseFromString(data, 'application/xml')
var tilesets = doc.getElementsByTagName('tileset')
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.offset = xtile.firstgid
img.tileCount = parseInt(d.getAttribute('tilecount'))
map.tileMaps.push(img)
img.onready = function () {
loadNextTileMap(index + 1)
}
}
}
}, 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
var layer = this.layers[name]
for (let i in this.tileMaps) {
let tileMap = this.tileMaps[i]
for (let j in layer.tiles) {
let tile = layer.tiles[j]
let tcount = tileMap.tileCount || tileMap.tiles.length
if (tile.tile >= tileMap.offset && tile.tile <= tcount) {
tileMap.draw(ctx, tile.tile - tileMap.offset, ((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)
}
}
}
}
// object: Object that collides (i.e. a player, monster)
// name: Name of the layer (generally "static")
// effectiveRange: Range around object where tiles are tested for collisions
collideLayer (object, origin, viewport, name, effectiveRange) {
if (!this.layers[name]) return null
var layer = this.layers[name]
var collisions = null
var posAbs = new DWE.Math.Box2(object.x + origin.x + layer.x - viewport.x,
object.y + origin.y + layer.y - viewport.y, object.width * this.scale, object.height * this.scale)
for (let i in layer.tiles) {
let tile = layer.tiles[i]
let tilePosAbs = new DWE.Math.Box2((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)
if (tilePosAbs.distance(posAbs) > effectiveRange) continue
collisions = tilePosAbs.intersectsBox(posAbs)
if (collisions) break
}
return collisions
}
setScale (scale) {
this.scale = scale
}
}