193 lines
4.5 KiB
JavaScript
193 lines
4.5 KiB
JavaScript
import { ctx, ResourceCacheFactory } from './canvas'
|
|
import Resource from './resource'
|
|
|
|
const cacheFactory = new ResourceCacheFactory()
|
|
|
|
class TileMap {
|
|
constructor (image, rows) {
|
|
this._src = image
|
|
this.rows = rows
|
|
this.defs = {}
|
|
}
|
|
|
|
get height () {
|
|
return this.image.height
|
|
}
|
|
|
|
get width () {
|
|
return this.image.width
|
|
}
|
|
|
|
get tile () {
|
|
return this.width / this.rows
|
|
}
|
|
|
|
get image () {
|
|
return Resource.loadImage(this._src, true)
|
|
}
|
|
|
|
tileAt (i) {
|
|
return { x: (i % this.rows) * this.tile, y: Math.floor(i / this.rows) * this.tile }
|
|
}
|
|
|
|
define (tile, index) {
|
|
if (typeof tile === 'object') {
|
|
this.defs = Object.assign(this.defs, tile)
|
|
return
|
|
}
|
|
this.defs[tile] = index
|
|
}
|
|
|
|
indexOf (tile) {
|
|
return this.defs[tile] || null
|
|
}
|
|
|
|
positionOf (tile) {
|
|
return this.tileAt(this.indexOf(tile))
|
|
}
|
|
}
|
|
|
|
class TileChunk {
|
|
constructor (ix, iy, size = 16, tileSize = 16) {
|
|
this.x = ix
|
|
this.y = iy
|
|
this.size = size
|
|
this.tile = tileSize
|
|
this.tiles = []
|
|
this.dirty = true
|
|
this.img = null
|
|
this._updated = false
|
|
}
|
|
|
|
generateMap (tileMap, heightMap) {
|
|
for (let i = 0; i < this.size * this.size; i++) {
|
|
let tileCoords = this.toXY(i)
|
|
let tileAbs = this.toAbs(tileCoords)
|
|
let y = Math.ceil(heightMap.getHeight(tileAbs.x) * 5 / 2) - 4
|
|
if (tileAbs.y < y) {
|
|
this.tiles.push(-1)
|
|
continue
|
|
}
|
|
if (tileAbs.y === y) {
|
|
this.tiles.push(tileMap.indexOf('GRASS_TOP'))
|
|
continue
|
|
}
|
|
if (tileAbs.y < y + 10) {
|
|
this.tiles.push(tileMap.indexOf('DIRT'))
|
|
continue
|
|
}
|
|
this.tiles.push(tileMap.indexOf('STONE'))
|
|
}
|
|
}
|
|
|
|
tileAt (i) {
|
|
return this.tiles[i]
|
|
}
|
|
|
|
tileAtXY (x, y) {
|
|
return this.tileAt(x + this.size * y)
|
|
}
|
|
|
|
toXY (i) {
|
|
return { x: i % this.size, y: Math.floor(i / this.size) }
|
|
}
|
|
|
|
toAbs (x, y) {
|
|
if (typeof x === 'object') {
|
|
y = x.y
|
|
x = x.x
|
|
}
|
|
return { x: this.x * this.size + x, y: this.y * this.size + y }
|
|
}
|
|
|
|
get absPos () {
|
|
return { x: this.x * this.size * this.tile, y: this.y * this.size * this.tile }
|
|
}
|
|
|
|
draw (view, map) {
|
|
// Create a cached image of the chunk
|
|
if (this.dirty || !this.img) {
|
|
cacheFactory.prepare(this.size * this.tile, this.size * this.tile)
|
|
for (let i in this.tiles) {
|
|
let tilei = this.tiles[i]
|
|
if (tilei === -1) continue
|
|
let coords = this.toXY(parseInt(i))
|
|
let tileCoords = map.tileAt(tilei)
|
|
cacheFactory.ctx.drawImage(map.image, tileCoords.x, tileCoords.y, map.tile, map.tile,
|
|
coords.x * this.tile, coords.y * this.tile, this.tile, this.tile)
|
|
}
|
|
this.img = cacheFactory.capture()
|
|
this.dirty = false
|
|
this._updated = true
|
|
return
|
|
}
|
|
// Draw the cached image
|
|
let p = this.absPos
|
|
ctx.drawImage(this.img, p.x - view.x, p.y - view.y)
|
|
}
|
|
|
|
update (dt) {
|
|
|
|
}
|
|
}
|
|
|
|
class World {
|
|
constructor (heightMap, tileMaps, chunkSize = 16, tileSize = 16) {
|
|
this.heightMap = heightMap
|
|
this.chunkSize = chunkSize
|
|
this.tileSize = tileSize
|
|
this.tileMaps = tileMaps
|
|
this.chunks = []
|
|
|
|
// Debug info
|
|
this._lastDrawCount = 0
|
|
this._lastUpdateCount = 0
|
|
}
|
|
|
|
getChunk (x, y) {
|
|
for (let i in this.chunks) {
|
|
let chunk = this.chunks[i]
|
|
if (chunk && chunk.x === x && chunk.y === y) return chunk
|
|
}
|
|
return null
|
|
}
|
|
|
|
update (dt, vp) {
|
|
let posPoint = vp.chunkIn(this.chunkSize * this.tileSize)
|
|
for (let x = posPoint.x - 4; x < posPoint.x + 5; x++) {
|
|
for (let y = posPoint.y - 4; y < posPoint.y + 5; y++) {
|
|
if (x < 0 || y < 0) continue
|
|
let exists = this.getChunk(x, y)
|
|
if (!exists) {
|
|
let n = new TileChunk(x, y, this.chunkSize, this.tileSize)
|
|
n.generateMap(this.tileMaps.GROUND, this.heightMap)
|
|
this.chunks.push(n)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
for (let i in this.chunks) {
|
|
this.chunks[i].update(dt)
|
|
}
|
|
}
|
|
|
|
draw (vp) {
|
|
this._lastDrawCount = 0
|
|
this._lastUpdateCount = 0
|
|
for (let i in this.chunks) {
|
|
let chunk = this.chunks[i]
|
|
let absPos = chunk.absPos
|
|
let chunkSize = chunk.size * this.tileSize
|
|
if (absPos.x > vp.x + vp.width || absPos.x + chunkSize < vp.x ||
|
|
absPos.y > vp.y + vp.height || absPos.y + chunkSize < vp.y) continue
|
|
chunk._updated = false
|
|
chunk.draw(vp, this.tileMaps.GROUND)
|
|
if (chunk._updated) this._lastUpdateCount++
|
|
this._lastDrawCount++
|
|
}
|
|
}
|
|
}
|
|
|
|
export { TileMap, TileChunk, World }
|