simple inventory and item system
This commit is contained in:
parent
71850fc7f9
commit
5a2ba57115
BIN
assets/item_dirt.png
Normal file
BIN
assets/item_dirt.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 681 B |
BIN
assets/item_grass.png
Normal file
BIN
assets/item_grass.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 478 B |
BIN
assets/item_stone.png
Normal file
BIN
assets/item_stone.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 510 B |
@ -111,7 +111,7 @@ class Debugging {
|
|||||||
ctx.closePath()
|
ctx.closePath()
|
||||||
ctx.stroke()
|
ctx.stroke()
|
||||||
|
|
||||||
// Draw colliders
|
/* Draw colliders
|
||||||
ctx.fillStyle = '#00aaff'
|
ctx.fillStyle = '#00aaff'
|
||||||
let collider = chunk.getLayer('col')
|
let collider = chunk.getLayer('col')
|
||||||
for (let i in collider.tiles) {
|
for (let i in collider.tiles) {
|
||||||
@ -119,7 +119,7 @@ class Debugging {
|
|||||||
if (collider.tiles[i] === 0) continue
|
if (collider.tiles[i] === 0) continue
|
||||||
ctx.fillRect(p.x * chunk.tile, p.y * chunk.tile, chunk.tile, chunk.tile)
|
ctx.fillRect(p.x * chunk.tile, p.y * chunk.tile, chunk.tile, chunk.tile)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// Chunk index
|
// Chunk index
|
||||||
ctx.fillStyle = '#fff'
|
ctx.fillStyle = '#fff'
|
||||||
ctx.fillText(chunk.x + ';' + chunk.y, 5, 16)
|
ctx.fillText(chunk.x + ';' + chunk.y, 5, 16)
|
||||||
|
114
src/index.js
114
src/index.js
@ -1,6 +1,8 @@
|
|||||||
/* global requestAnimationFrame */
|
/* global requestAnimationFrame */
|
||||||
import { canvas, ctx } from './canvas'
|
import { canvas, ctx } from './canvas'
|
||||||
import { TileMap, World } from './tiles'
|
import { Tile, TileMap, World } from './tiles'
|
||||||
|
import { ItemPlaceable } from './items'
|
||||||
|
import { Inventory } from './inventory'
|
||||||
import { HeightMap } from './heightmap'
|
import { HeightMap } from './heightmap'
|
||||||
import Debug from './debug'
|
import Debug from './debug'
|
||||||
import Player from './player'
|
import Player from './player'
|
||||||
@ -15,6 +17,7 @@ let fps = 0
|
|||||||
|
|
||||||
let vp = new Viewport(0, 0)
|
let vp = new Viewport(0, 0)
|
||||||
let p = new Player(800, 1200, 32, 64)
|
let p = new Player(800, 1200, 32, 64)
|
||||||
|
let inv = new Inventory(9)
|
||||||
|
|
||||||
let height = new HeightMap(0, 32, 16, 0)
|
let height = new HeightMap(0, 32, 16, 0)
|
||||||
let map = new TileMap('assets/ground.png', 32)
|
let map = new TileMap('assets/ground.png', 32)
|
||||||
@ -22,44 +25,56 @@ let map = new TileMap('assets/ground.png', 32)
|
|||||||
const chunkSize = 32
|
const chunkSize = 32
|
||||||
const tileSize = 16
|
const tileSize = 16
|
||||||
|
|
||||||
|
const dirtTile = new Tile('DIRT', 33)
|
||||||
|
const grassTile = new Tile('GRASS_TOP', 6)
|
||||||
|
const stoneTile = new Tile('STONE', 10)
|
||||||
|
|
||||||
|
const dirtItem = new ItemPlaceable(dirtTile, 'dirt', 'assets/item_dirt.png')
|
||||||
|
const grassItem = new ItemPlaceable(grassTile, 'dirt_with_grass', 'assets/item_grass.png')
|
||||||
|
const stoneItem = new ItemPlaceable(stoneTile, 'stone', 'assets/item_stone.png')
|
||||||
|
|
||||||
|
dirtTile.item = dirtItem
|
||||||
|
grassTile.item = grassItem
|
||||||
|
stoneTile.item = stoneItem
|
||||||
|
|
||||||
// Define dirt tiles
|
// Define dirt tiles
|
||||||
map.define({
|
map.register([
|
||||||
'DIRT_CORNER_TOP_LEFT': 0,
|
new Tile('DIRT_CORNER_TOP_LEFT', 0, true, dirtItem),
|
||||||
'DIRT_TOP': 1,
|
new Tile('DIRT_TOP', 1, true, dirtItem),
|
||||||
'DIRT_CORNER_TOP_RIGHT': 2,
|
new Tile('DIRT_CORNER_TOP_RIGHT', 2, true, dirtItem),
|
||||||
'DIRT_INNER_BOTTOM_RIGHT': 3,
|
new Tile('DIRT_INNER_BOTTOM_RIGHT', 3, true, dirtItem),
|
||||||
'DIRT_INNER_BOTTOM_LEFT': 4,
|
new Tile('DIRT_INNER_BOTTOM_LEFT', 4, true, dirtItem),
|
||||||
'DIRT_LEFT': 32,
|
new Tile('DIRT_LEFT', 32, true, dirtItem),
|
||||||
'DIRT': 33,
|
dirtTile,
|
||||||
'DIRT_RIGHT': 34,
|
new Tile('DIRT_RIGHT', 34, true, dirtItem),
|
||||||
'DIRT_INNER_TOP_RIGHT': 35,
|
new Tile('DIRT_INNER_TOP_RIGHT', 35, true, dirtItem),
|
||||||
'DIRT_INNER_TOP_LEFT': 36,
|
new Tile('DIRT_INNER_TOP_LEFT', 36, true, dirtItem),
|
||||||
'DIRT_CORNER_BOTTOM_LEFT': 64,
|
new Tile('DIRT_CORNER_BOTTOM_LEFT', 64, true, dirtItem),
|
||||||
'DIRT_BOTTOM': 65,
|
new Tile('DIRT_BOTTOM', 65, true, dirtItem),
|
||||||
'DIRT_CORNER_BOTTOM_RIGHT': 66
|
new Tile('DIRT_CORNER_BOTTOM_RIGHT', 66, true, dirtItem)
|
||||||
})
|
])
|
||||||
|
|
||||||
// Define grass tiles
|
// Define grass tiles
|
||||||
map.define({
|
map.register([
|
||||||
'GRASS_CORNER_TOP_LEFT': 5,
|
new Tile('GRASS_CORNER_TOP_LEFT', 5, true, dirtItem),
|
||||||
'GRASS_TOP': 6,
|
grassTile,
|
||||||
'GRASS_CORNER_TOP_RIGHT': 7,
|
new Tile('GRASS_CORNER_TOP_RIGHT', 7, true, dirtItem),
|
||||||
'GRASS_INNER_BOTTOM_RIGHT': 8,
|
new Tile('GRASS_INNER_BOTTOM_RIGHT', 8, true, dirtItem),
|
||||||
'GRASS_INNER_BOTTOM_LEFT': 9,
|
new Tile('GRASS_INNER_BOTTOM_LEFT', 9, true, dirtItem),
|
||||||
'GRASS_LEFT': 37,
|
new Tile('GRASS_LEFT', 37, true, dirtItem),
|
||||||
'GRASS_MID': 38,
|
new Tile('GRASS_RIGHT', 39, true, dirtItem),
|
||||||
'GRASS_RIGHT': 39,
|
new Tile('GRASS_INNER_TOP_RIGHT', 40, true, dirtItem),
|
||||||
'GRASS_INNER_TOP_RIGHT': 40,
|
new Tile('GRASS_INNER_TOP_LEFT', 41, true, dirtItem),
|
||||||
'GRASS_INNER_TOP_LEFT': 41,
|
new Tile('GRASS_CORNER_BOTTOM_LEFT', 69, true, dirtItem),
|
||||||
'GRASS_CORNER_BOTTOM_LEFT': 69,
|
new Tile('GRASS_BOTTOM', 70, true, dirtItem),
|
||||||
'GRASS_BOTTOM': 70,
|
new Tile('GRASS_CORNER_BOTTOM_RIGHT', 71, true, dirtItem)
|
||||||
'GRASS_CORNER_BOTTOM_RIGHT': 71
|
])
|
||||||
})
|
|
||||||
|
|
||||||
map.define({
|
// Define other tiles
|
||||||
'AIR': -1,
|
map.register([
|
||||||
'STONE': 10
|
new Tile('AIR', -1, false),
|
||||||
})
|
stoneTile
|
||||||
|
])
|
||||||
|
|
||||||
let world = new World(height, { GROUND: map }, chunkSize, tileSize, 32, 64)
|
let world = new World(height, { GROUND: map }, chunkSize, tileSize, 32, 64)
|
||||||
|
|
||||||
@ -68,15 +83,36 @@ function update (dt) {
|
|||||||
p.update(dt, vp, world)
|
p.update(dt, vp, world)
|
||||||
vp.update(dt, world)
|
vp.update(dt, world)
|
||||||
|
|
||||||
|
for (let i = 0; i < inv.size; i++) {
|
||||||
|
let pressed = Input.isPressed(i + 1)
|
||||||
|
if (pressed) {
|
||||||
|
inv.selected = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Input.mouse['btn0']) {
|
if (Input.mouse['btn0']) {
|
||||||
let mpin = world.pickMouse(vp, Input.mouse.pos)
|
let mpin = world.pickMouse(vp, Input.mouse.pos)
|
||||||
if (mpin.chunk) {
|
if (mpin.chunk) {
|
||||||
mpin.chunk.setTile('fg', mpin.tile, map.indexOf('DIRT'))
|
if (inv.isEmpty(inv.selected)) return
|
||||||
|
let tile = mpin.chunk.getTile('fg', mpin.tile)
|
||||||
|
if (tile !== -1) return
|
||||||
|
let itm = inv.getItem(inv.selected)
|
||||||
|
if (itm && itm.item.placeable) {
|
||||||
|
let success = mpin.chunk.setTile('fg', mpin.tile, itm.item.placeable.id)
|
||||||
|
if (success) {
|
||||||
|
inv.takeItem(inv.selected, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (Input.mouse['btn2']) {
|
} else if (Input.mouse['btn2']) {
|
||||||
let mpin = world.pickMouse(vp, Input.mouse.pos)
|
let mpin = world.pickMouse(vp, Input.mouse.pos)
|
||||||
if (mpin.chunk) {
|
if (mpin.chunk) {
|
||||||
mpin.chunk.setTile('fg', mpin.tile, map.indexOf('AIR'))
|
let tile = mpin.chunk.getTile('fg', mpin.tile)
|
||||||
|
if (tile === -1) return
|
||||||
|
let itile = map.getTileByID(tile)
|
||||||
|
let success = mpin.chunk.setTile('fg', mpin.tile, map.indexOf('AIR'))
|
||||||
|
if (success) inv.addItem(itile.item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,6 +121,7 @@ function draw () {
|
|||||||
world.draw(vp)
|
world.draw(vp)
|
||||||
p.draw(vp)
|
p.draw(vp)
|
||||||
Debug.draw(vp, world, fps)
|
Debug.draw(vp, world, fps)
|
||||||
|
inv.draw()
|
||||||
}
|
}
|
||||||
|
|
||||||
function step () {
|
function step () {
|
||||||
@ -131,7 +168,8 @@ function start () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadAll () {
|
async function loadAll () {
|
||||||
let images = ['assets/ground.png']
|
let images = ['assets/ground.png', 'assets/item_grass.png',
|
||||||
|
'assets/item_dirt.png', 'assets/item_stone.png']
|
||||||
for (let i in images) {
|
for (let i in images) {
|
||||||
await RES.loadImage(images[i])
|
await RES.loadImage(images[i])
|
||||||
}
|
}
|
||||||
|
89
src/inventory.js
Normal file
89
src/inventory.js
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import { canvas, ctx } from './canvas'
|
||||||
|
import { Item, ItemStack, MAX_STACK_SIZE } from './items'
|
||||||
|
|
||||||
|
const SLOT_SIZE = 32
|
||||||
|
|
||||||
|
class Inventory {
|
||||||
|
constructor (size) {
|
||||||
|
this.size = size
|
||||||
|
this.items = []
|
||||||
|
this.selected = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
addItem (i) {
|
||||||
|
if (typeof i === 'string' || i instanceof Item) i = ItemStack.new(i)
|
||||||
|
let addedTo = false
|
||||||
|
let leftover = null
|
||||||
|
for (let k in this.items) {
|
||||||
|
if (addedTo) break
|
||||||
|
let itm = this.items[k]
|
||||||
|
if (itm.name === i.name || itm.isEmpty()) {
|
||||||
|
if (itm.isEmpty()) itm.item = i.item
|
||||||
|
let addedCount = itm.count + i.count
|
||||||
|
if (addedCount > MAX_STACK_SIZE) {
|
||||||
|
let m = addedCount - MAX_STACK_SIZE
|
||||||
|
let n = itm.copy()
|
||||||
|
n.count = m
|
||||||
|
itm.count = MAX_STACK_SIZE
|
||||||
|
if (this.items.length >= this.size) {
|
||||||
|
leftover = n
|
||||||
|
addedTo = true
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
itm.count += i.count
|
||||||
|
addedTo = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!addedTo) {
|
||||||
|
if (this.items.length >= this.size) {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
this.items.push(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
return leftover
|
||||||
|
}
|
||||||
|
|
||||||
|
getItem (slot) {
|
||||||
|
if (this.isEmpty(slot)) return null
|
||||||
|
return this.items[slot]
|
||||||
|
}
|
||||||
|
|
||||||
|
takeItem (slot, count) {
|
||||||
|
if (this.isEmpty(slot)) return null
|
||||||
|
let i = this.items[slot]
|
||||||
|
if (!count || count > i.count) return i
|
||||||
|
i.count -= count
|
||||||
|
let copied = i.copy()
|
||||||
|
copied.count = count
|
||||||
|
return copied
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmpty (slot) {
|
||||||
|
if (!this.items[slot] || this.items[slot].isEmpty()) return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
draw () {
|
||||||
|
for (let i = 0; i < this.size; i++) {
|
||||||
|
let stack = this.items[i]
|
||||||
|
let x = canvas.width / 2 + i * (SLOT_SIZE + 8) - this.size / 2 * SLOT_SIZE
|
||||||
|
ctx.fillStyle = (this.selected === i) ? '#f00' : '#ddd'
|
||||||
|
ctx.fillRect(x, 16, SLOT_SIZE, SLOT_SIZE)
|
||||||
|
if (!stack || stack.isEmpty()) continue
|
||||||
|
ctx.drawImage(stack.item.image, x, 16, SLOT_SIZE, SLOT_SIZE)
|
||||||
|
ctx.font = '16px sans'
|
||||||
|
let measure = ctx.measureText(stack.count)
|
||||||
|
ctx.fillStyle = '#000'
|
||||||
|
ctx.fillText(stack.count, x + SLOT_SIZE / 2 - measure.width / 2, 8 + SLOT_SIZE)
|
||||||
|
ctx.fillStyle = '#fff'
|
||||||
|
ctx.fillText(stack.count, x + SLOT_SIZE / 2 - measure.width / 2 + 1, 8 + SLOT_SIZE + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Inventory }
|
87
src/items.js
Normal file
87
src/items.js
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import RES from './resource'
|
||||||
|
|
||||||
|
const MAX_STACK_SIZE = 999
|
||||||
|
|
||||||
|
const ItemRegistry = new (class ItemRegistry {
|
||||||
|
constructor () {
|
||||||
|
this.items = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
register (name, item) {
|
||||||
|
this.items[name] = item
|
||||||
|
}
|
||||||
|
|
||||||
|
get (name) {
|
||||||
|
return this.items[name]
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
|
||||||
|
class Item {
|
||||||
|
constructor (name, img, description) {
|
||||||
|
this.name = name
|
||||||
|
this._img = img
|
||||||
|
this.description = description
|
||||||
|
ItemRegistry.register(name, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
get image () {
|
||||||
|
return RES.loadImage(this._img, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ItemPlaceable extends Item {
|
||||||
|
constructor (tile, name, img, description) {
|
||||||
|
super(name, img, description)
|
||||||
|
this.placeable = tile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ItemStack {
|
||||||
|
static fromIString (str) {
|
||||||
|
if (typeof str !== 'string') return
|
||||||
|
let strpl = str.split(' ')
|
||||||
|
let iname = strpl[0]
|
||||||
|
let count = strpl[1]
|
||||||
|
let item = ItemRegistry.get(iname)
|
||||||
|
let istack = new ItemStack()
|
||||||
|
istack.item = item
|
||||||
|
istack.count = count || 1
|
||||||
|
return istack
|
||||||
|
}
|
||||||
|
|
||||||
|
static new (itemdef, count = 1, metadata) {
|
||||||
|
if (itemdef instanceof ItemStack) return itemdef.copy()
|
||||||
|
if (typeof itemdef === 'string') return ItemStack.fromIString(itemdef)
|
||||||
|
if (!(itemdef instanceof Item)) throw new Error('Invalid Item Definition!')
|
||||||
|
let istack = new ItemStack()
|
||||||
|
istack.item = itemdef
|
||||||
|
istack.count = count
|
||||||
|
istack.metadata = metadata
|
||||||
|
return istack
|
||||||
|
}
|
||||||
|
|
||||||
|
copy () {
|
||||||
|
return ItemStack.new(this.item, this.count, this.metadata)
|
||||||
|
}
|
||||||
|
|
||||||
|
get name () {
|
||||||
|
return this.item ? this.item.name : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmpty () {
|
||||||
|
return this.item === null || this.count === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
takeItem (c) {
|
||||||
|
let a = this.copy()
|
||||||
|
if (c > this.count) {
|
||||||
|
this.count = 0
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
this.count -= c
|
||||||
|
a.count = c
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Item, ItemPlaceable, ItemStack, ItemRegistry, MAX_STACK_SIZE }
|
@ -14,7 +14,7 @@ class Player {
|
|||||||
|
|
||||||
this.grounded = false
|
this.grounded = false
|
||||||
|
|
||||||
this.speed = 5
|
this.speed = 8
|
||||||
this.gravity = 1
|
this.gravity = 1
|
||||||
this.jumpPower = 20
|
this.jumpPower = 20
|
||||||
}
|
}
|
||||||
@ -35,8 +35,12 @@ class Player {
|
|||||||
let oldX = this.x
|
let oldX = this.x
|
||||||
this.x += this.mX
|
this.x += this.mX
|
||||||
if (oldX !== this.x && collider.collide(this)) {
|
if (oldX !== this.x && collider.collide(this)) {
|
||||||
this.x = oldX
|
this.mX = this.mX < 0 ? -1 : 1
|
||||||
this.mX = 0
|
this.x = oldX + this.mX
|
||||||
|
if (collider.collide(this)) {
|
||||||
|
this.x = oldX
|
||||||
|
this.mX = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
113
src/tiles.js
113
src/tiles.js
@ -6,11 +6,20 @@ import Debug from './debug'
|
|||||||
const cacheFactory = new ResourceCacheFactory()
|
const cacheFactory = new ResourceCacheFactory()
|
||||||
const UPDATE_RADIUS = 6
|
const UPDATE_RADIUS = 6
|
||||||
|
|
||||||
|
class Tile {
|
||||||
|
constructor (name, index, solid = true, item) {
|
||||||
|
this.name = name
|
||||||
|
this.id = index
|
||||||
|
this.solid = solid
|
||||||
|
this.item = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class TileMap {
|
class TileMap {
|
||||||
constructor (image, rows) {
|
constructor (image, rows) {
|
||||||
this._src = image
|
this._src = image
|
||||||
this.rows = rows
|
this.rows = rows
|
||||||
this.defs = {}
|
this.tiles = []
|
||||||
}
|
}
|
||||||
|
|
||||||
get height () {
|
get height () {
|
||||||
@ -33,16 +42,41 @@ class TileMap {
|
|||||||
return { x: (i % this.rows) * this.tile, y: Math.floor(i / this.rows) * this.tile }
|
return { x: (i % this.rows) * this.tile, y: Math.floor(i / this.rows) * this.tile }
|
||||||
}
|
}
|
||||||
|
|
||||||
define (tile, index) {
|
register (tile) {
|
||||||
if (typeof tile === 'object') {
|
if (typeof tile === 'object' && tile.length) {
|
||||||
this.defs = Object.assign(this.defs, tile)
|
for (let i in tile) {
|
||||||
|
this.register(tile[i])
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.defs[tile] = index
|
if (!(tile instanceof Tile)) return
|
||||||
|
this.tiles.push(tile)
|
||||||
|
}
|
||||||
|
|
||||||
|
getTileByName (tile) {
|
||||||
|
for (let i in this.tiles) {
|
||||||
|
let t = this.tiles[i]
|
||||||
|
if (t.name === tile) return t
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
getTileByID (id) {
|
||||||
|
for (let i in this.tiles) {
|
||||||
|
let t = this.tiles[i]
|
||||||
|
if (t.id === id) return t
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
isSolid (id) {
|
||||||
|
let t = this.getTileByID(id)
|
||||||
|
return t ? t.solid : false
|
||||||
}
|
}
|
||||||
|
|
||||||
indexOf (tile) {
|
indexOf (tile) {
|
||||||
return this.defs[tile] || null
|
let t = this.getTileByName(tile)
|
||||||
|
return t ? t.id : null
|
||||||
}
|
}
|
||||||
|
|
||||||
positionOf (tile) {
|
positionOf (tile) {
|
||||||
@ -51,7 +85,8 @@ class TileMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TileLayer {
|
class TileLayer {
|
||||||
constructor (name, size = 16, tileSize = 16) {
|
constructor (map, name, size = 16, tileSize = 16) {
|
||||||
|
this.map = map
|
||||||
this.name = name
|
this.name = name
|
||||||
this.size = size
|
this.size = size
|
||||||
this.tile = tileSize
|
this.tile = tileSize
|
||||||
@ -70,11 +105,16 @@ class TileLayer {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isSolid (i) {
|
||||||
|
return this.map.isSolid(i)
|
||||||
|
}
|
||||||
|
|
||||||
tileAt (i) {
|
tileAt (i) {
|
||||||
return this.tiles[i]
|
return this.tiles[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
tileAtXY (x, y) {
|
tileAtXY (x, y) {
|
||||||
|
if (x < 0 || x >= this.size || y < 0 || y >= this.size) return null
|
||||||
return this.tileAt(x + this.size * y)
|
return this.tileAt(x + this.size * y)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,13 +122,13 @@ class TileLayer {
|
|||||||
return { x: i % this.size, y: Math.floor(i / this.size) }
|
return { x: i % this.size, y: Math.floor(i / this.size) }
|
||||||
}
|
}
|
||||||
|
|
||||||
draw (ctx, view, map) {
|
draw (ctx, view) {
|
||||||
for (let i in this.tiles) {
|
for (let i in this.tiles) {
|
||||||
let tilei = this.tiles[i]
|
let tilei = this.tiles[i]
|
||||||
if (tilei === -1) continue
|
if (tilei === -1) continue
|
||||||
let coords = this.toXY(parseInt(i))
|
let coords = this.toXY(parseInt(i))
|
||||||
let tileCoords = map.tileAt(tilei)
|
let tileCoords = this.map.tileAt(tilei)
|
||||||
ctx.drawImage(map.image, tileCoords.x, tileCoords.y, map.tile, map.tile,
|
ctx.drawImage(this.map.image, tileCoords.x, tileCoords.y, this.map.tile, this.map.tile,
|
||||||
coords.x * this.tile, coords.y * this.tile, this.tile, this.tile)
|
coords.x * this.tile, coords.y * this.tile, this.tile, this.tile)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +153,7 @@ class TileLayer {
|
|||||||
|
|
||||||
class TilePhysicsLayer extends TileLayer {
|
class TilePhysicsLayer extends TileLayer {
|
||||||
constructor (size = 16, tileSize = 16) {
|
constructor (size = 16, tileSize = 16) {
|
||||||
super('col', size, tileSize)
|
super(null, 'col', size, tileSize)
|
||||||
this.empty = false
|
this.empty = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,12 +166,15 @@ class TilePhysicsLayer extends TileLayer {
|
|||||||
this.empty = true
|
this.empty = true
|
||||||
for (let i in tiles.tiles) {
|
for (let i in tiles.tiles) {
|
||||||
let t = tiles.tiles[i]
|
let t = tiles.tiles[i]
|
||||||
let p = tiles.toXY(parseInt(i))
|
// let p = tiles.toXY(parseInt(i))
|
||||||
if (t === -1) {
|
if (t === -1 || !tiles.isSolid(t)) {
|
||||||
this.tiles[i] = 0
|
this.tiles[i] = 0
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
this.empty = false
|
||||||
|
this.tiles[i] = 1
|
||||||
|
/*
|
||||||
|
// Surface tiles only
|
||||||
// If this tile has neighbors that are air but its not itself air, it has a collider
|
// If this tile has neighbors that are air but its not itself air, it has a collider
|
||||||
let l = tiles.tileAtXY(p.x - 1, p.y)
|
let l = tiles.tileAtXY(p.x - 1, p.y)
|
||||||
let r = tiles.tileAtXY(p.x + 1, p.y)
|
let r = tiles.tileAtXY(p.x + 1, p.y)
|
||||||
@ -145,6 +188,7 @@ class TilePhysicsLayer extends TileLayer {
|
|||||||
|
|
||||||
this.empty = false
|
this.empty = false
|
||||||
this.tiles[i] = 1
|
this.tiles[i] = 1
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,10 +199,10 @@ class TilePhysicsLayer extends TileLayer {
|
|||||||
let t = this.tiles[i]
|
let t = this.tiles[i]
|
||||||
if (t === 0) continue
|
if (t === 0) continue
|
||||||
let p = this.toXY(parseInt(i))
|
let p = this.toXY(parseInt(i))
|
||||||
let minX = p.x * chunk.tile + absPos.x
|
let minX = p.x * chunk.tile + absPos.x + 1
|
||||||
let minY = p.y * chunk.tile + absPos.y
|
let minY = p.y * chunk.tile + absPos.y + 1
|
||||||
let maxX = minX + chunk.tile
|
let maxX = minX + chunk.tile - 2
|
||||||
let maxY = minY + chunk.tile
|
let maxY = minY + chunk.tile - 2
|
||||||
|
|
||||||
// Intersection check
|
// Intersection check
|
||||||
if (minX > obj.x + obj.width || maxX < obj.x ||
|
if (minX > obj.x + obj.width || maxX < obj.x ||
|
||||||
@ -185,8 +229,8 @@ class Chunk {
|
|||||||
|
|
||||||
generateMap (tileMap, heightMap) {
|
generateMap (tileMap, heightMap) {
|
||||||
this.layers = []
|
this.layers = []
|
||||||
let bgLayer = new TileLayer('bg', this.size, this.tile)
|
let bgLayer = new TileLayer(tileMap, 'bg', this.size, this.tile)
|
||||||
let fgLayer = new TileLayer('fg', this.size, this.tile)
|
let fgLayer = new TileLayer(tileMap, 'fg', this.size, this.tile)
|
||||||
let clLayer = new TilePhysicsLayer(this.size, this.tile)
|
let clLayer = new TilePhysicsLayer(this.size, this.tile)
|
||||||
for (let i = 0; i < this.size * this.size; i++) {
|
for (let i = 0; i < this.size * this.size; i++) {
|
||||||
let tileCoords = fgLayer.toXY(i)
|
let tileCoords = fgLayer.toXY(i)
|
||||||
@ -214,7 +258,6 @@ class Chunk {
|
|||||||
fgLayer.tiles.push(tileMap.indexOf('STONE'))
|
fgLayer.tiles.push(tileMap.indexOf('STONE'))
|
||||||
bgLayer.tiles.push(tileMap.indexOf('STONE'))
|
bgLayer.tiles.push(tileMap.indexOf('STONE'))
|
||||||
}
|
}
|
||||||
|
|
||||||
clLayer.generateFromTiles(fgLayer)
|
clLayer.generateFromTiles(fgLayer)
|
||||||
this.layers.push(bgLayer)
|
this.layers.push(bgLayer)
|
||||||
this.layers.push(fgLayer)
|
this.layers.push(fgLayer)
|
||||||
@ -230,8 +273,18 @@ class Chunk {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTile (layer, x, y) {
|
||||||
|
if (typeof x === 'object') {
|
||||||
|
y = x.y
|
||||||
|
x = x.x
|
||||||
|
}
|
||||||
|
let l = this.getLayer(layer)
|
||||||
|
if (!l) return null
|
||||||
|
return l.tileAtXY(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
setTile (layer, x, y, tile) {
|
setTile (layer, x, y, tile) {
|
||||||
if (!tile && typeof x !== 'object') {
|
if (!tile && typeof x === 'object') {
|
||||||
tile = y
|
tile = y
|
||||||
y = x.y
|
y = x.y
|
||||||
x = x.x
|
x = x.x
|
||||||
@ -260,7 +313,7 @@ class Chunk {
|
|||||||
return this.size * this.tile
|
return this.size * this.tile
|
||||||
}
|
}
|
||||||
|
|
||||||
draw (view, map) {
|
draw (view) {
|
||||||
if (this.img) {
|
if (this.img) {
|
||||||
// Draw the cached image
|
// Draw the cached image
|
||||||
let p = this.absPos
|
let p = this.absPos
|
||||||
@ -273,19 +326,19 @@ class Chunk {
|
|||||||
// Draw all layers
|
// Draw all layers
|
||||||
for (let i in this.layers) {
|
for (let i in this.layers) {
|
||||||
let layer = this.layers[i]
|
let layer = this.layers[i]
|
||||||
layer.draw(cacheFactory.ctx, view, map)
|
layer.draw(cacheFactory.ctx, view)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update collision
|
||||||
|
let cl = this.getLayer('col')
|
||||||
|
if (cl) cl.generateFromTiles(this.getLayer('fg'))
|
||||||
|
|
||||||
// Draw a debug grid when enabled
|
// Draw a debug grid when enabled
|
||||||
Debug.chunkGrid(cacheFactory.ctx, this, view)
|
Debug.chunkGrid(cacheFactory.ctx, this, view)
|
||||||
|
|
||||||
// Create cached image
|
// Create cached image
|
||||||
this.img = cacheFactory.capture()
|
this.img = cacheFactory.capture()
|
||||||
|
|
||||||
// Update collision
|
|
||||||
let cl = this.getLayer('col')
|
|
||||||
if (cl) cl.generateFromTiles(this.getLayer('fg'))
|
|
||||||
|
|
||||||
// Don't update again next tick
|
// Don't update again next tick
|
||||||
this.dirty = false
|
this.dirty = false
|
||||||
this._updated = true
|
this._updated = true
|
||||||
@ -392,7 +445,7 @@ class World {
|
|||||||
if (absPos.x > vp.x + vp.width + this.tileSize || absPos.x + chunk.fullSize < vp.x - this.tileSize ||
|
if (absPos.x > vp.x + vp.width + this.tileSize || absPos.x + chunk.fullSize < vp.x - this.tileSize ||
|
||||||
absPos.y > vp.y + vp.height + this.tileSize || absPos.y + chunk.fullSize < vp.y - this.tileSize) continue
|
absPos.y > vp.y + vp.height + this.tileSize || absPos.y + chunk.fullSize < vp.y - this.tileSize) continue
|
||||||
chunk._updated = false
|
chunk._updated = false
|
||||||
chunk.draw(vp, this.tileMaps.GROUND)
|
chunk.draw(vp)
|
||||||
if (chunk._updated) this._lastUpdateCount++
|
if (chunk._updated) this._lastUpdateCount++
|
||||||
this._lastDrawCount++
|
this._lastDrawCount++
|
||||||
}
|
}
|
||||||
@ -408,4 +461,4 @@ class World {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { TileMap, Chunk, World }
|
export { Tile, TileMap, Chunk, World }
|
||||||
|
Loading…
Reference in New Issue
Block a user