item entities
This commit is contained in:
parent
5a2ba57115
commit
71eaa328a4
@ -24,7 +24,8 @@ class Debugging {
|
|||||||
ctx.fillText('active ' + world._active.length, 4, 16 * 7)
|
ctx.fillText('active ' + world._active.length, 4, 16 * 7)
|
||||||
// Mouse
|
// Mouse
|
||||||
let mpos = Input.mouse.pos
|
let mpos = Input.mouse.pos
|
||||||
let mpin = world.pickMouse(vp, mpos)
|
let mabs = { x: mpos.x + vp.x, y: mpos.y + vp.y }
|
||||||
|
let mpin = world.gridPosition(mabs)
|
||||||
ctx.fillText('mouse (x: ' + mpos.x + '; y: ' + mpos.y + ')', 4, 16 * 9)
|
ctx.fillText('mouse (x: ' + mpos.x + '; y: ' + mpos.y + ')', 4, 16 * 9)
|
||||||
if (mpin.chunk) {
|
if (mpin.chunk) {
|
||||||
ctx.fillText('mouse-in-chunk (x: ' + mpin.chunk.x + '; y: ' + mpin.chunk.y + ')', 4, 16 * 10)
|
ctx.fillText('mouse-in-chunk (x: ' + mpin.chunk.x + '; y: ' + mpin.chunk.y + ')', 4, 16 * 10)
|
||||||
|
214
src/entity.js
Normal file
214
src/entity.js
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
import { ctx } from './canvas'
|
||||||
|
import { ItemRegistry, ItemStack } from './items'
|
||||||
|
|
||||||
|
class PhysicsEntity {
|
||||||
|
constructor (x, y, w, h) {
|
||||||
|
this.x = x
|
||||||
|
this.y = y
|
||||||
|
|
||||||
|
this.width = w
|
||||||
|
this.height = h
|
||||||
|
|
||||||
|
this.mX = 0
|
||||||
|
this.mY = 0
|
||||||
|
|
||||||
|
this.grounded = false
|
||||||
|
|
||||||
|
this.speed = 8
|
||||||
|
this.gravity = 1
|
||||||
|
this.jumpPower = 20
|
||||||
|
|
||||||
|
this.dead = false
|
||||||
|
}
|
||||||
|
|
||||||
|
moveAndSlide (collider) {
|
||||||
|
// y collision
|
||||||
|
if (this.mY !== 0) {
|
||||||
|
let oldY = this.y
|
||||||
|
this.y += this.mY
|
||||||
|
if (oldY !== this.y && collider.collide(this)) {
|
||||||
|
if (this.y > oldY) this.grounded = true
|
||||||
|
this.y = oldY
|
||||||
|
this.mY = 0
|
||||||
|
} else {
|
||||||
|
this.grounded = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// x collision
|
||||||
|
if (this.mX !== 0) {
|
||||||
|
let oldX = this.x
|
||||||
|
this.x += this.mX
|
||||||
|
if (oldX !== this.x && collider.collide(this)) {
|
||||||
|
this.mX = this.mX < 0 ? -1 : 1
|
||||||
|
this.x = oldX + this.mX
|
||||||
|
if (collider.collide(this)) {
|
||||||
|
this.x = oldX
|
||||||
|
this.mX = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update (dt, vp, world) {
|
||||||
|
this.mY += this.gravity
|
||||||
|
|
||||||
|
this.moveAndSlide(world)
|
||||||
|
}
|
||||||
|
|
||||||
|
draw (vp) {
|
||||||
|
ctx.fillStyle = '#f00'
|
||||||
|
ctx.fillRect(this.x - vp.x, this.y - vp.y, this.width, this.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
collide (ent) {
|
||||||
|
if (!(ent instanceof PhysicsEntity)) return null
|
||||||
|
|
||||||
|
// Intersection check
|
||||||
|
if (this.x > ent.x + ent.width || this.x + this.width < ent.x ||
|
||||||
|
this.y > ent.y + ent.height || this.y + this.height < ent.y) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
distance (ent) {
|
||||||
|
if (!(ent instanceof PhysicsEntity)) return null
|
||||||
|
let d1 = { x: ent.x + ent.width / 2, y: ent.y + ent.height / 2 }
|
||||||
|
let d2 = { x: this.x + this.width / 2, y: this.y + this.height / 2 }
|
||||||
|
let dist = Math.floor(Math.sqrt(Math.pow(d1.x - d2.x, 2) + Math.pow(d1.y - d2.y, 2)))
|
||||||
|
return dist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ITEM_LIFE = 120
|
||||||
|
const ITEM_MERGE_DISTANCE = 60
|
||||||
|
const ITEM_BOB_FACTOR = 5
|
||||||
|
|
||||||
|
class ItemEntity extends PhysicsEntity {
|
||||||
|
constructor (istr, x, y) {
|
||||||
|
super(x, y, 16, 16)
|
||||||
|
this.istr = istr
|
||||||
|
|
||||||
|
this._mergeTick = 0
|
||||||
|
this._life = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
get name () {
|
||||||
|
if (this.istr === '') return ''
|
||||||
|
return this.istr.split(' ')[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
get count () {
|
||||||
|
if (this.istr === '') return ''
|
||||||
|
let c = parseInt(this.istr.split(' ')[1])
|
||||||
|
return isNaN(c) ? 0 : c
|
||||||
|
}
|
||||||
|
|
||||||
|
get item () {
|
||||||
|
let itm = ItemRegistry.get(this.name)
|
||||||
|
return itm
|
||||||
|
}
|
||||||
|
|
||||||
|
static new (itemStack, x, y) {
|
||||||
|
if (!(itemStack instanceof ItemStack)) return null
|
||||||
|
return new ItemEntity(itemStack.toString(), x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
mergeNearby (vp, world) {
|
||||||
|
let entLayer = world.getLayer('ents')
|
||||||
|
if (!entLayer) return
|
||||||
|
let active = entLayer.getActiveEntities(vp, world)
|
||||||
|
for (let i in active) {
|
||||||
|
let ent = active[i]
|
||||||
|
if (ent.dead) continue
|
||||||
|
if (ent === this) continue
|
||||||
|
if (!(ent instanceof ItemEntity)) continue
|
||||||
|
if (ent.name !== this.name) continue
|
||||||
|
let dist = Math.floor(Math.sqrt(Math.pow(ent.x - this.x, 2) + Math.pow(ent.y - this.y, 2)))
|
||||||
|
if (dist > ITEM_MERGE_DISTANCE) continue
|
||||||
|
this.istr = this.name + ' ' + (this.count + ent.count)
|
||||||
|
this._life = 0
|
||||||
|
ent.dead = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update (dt, vp, world) {
|
||||||
|
if (this.dead) return
|
||||||
|
this._mergeTick++
|
||||||
|
this._life += 1 * dt
|
||||||
|
if (this._mergeTick >= 60) {
|
||||||
|
this._mergeTick = 0
|
||||||
|
this.mergeNearby(vp, world)
|
||||||
|
}
|
||||||
|
if (this._life > ITEM_LIFE) {
|
||||||
|
this.dead = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
super.update(dt, vp, world)
|
||||||
|
}
|
||||||
|
|
||||||
|
draw (vp, world) {
|
||||||
|
let i = this.item
|
||||||
|
let b = Math.sin((this._life / ITEM_BOB_FACTOR) / Math.PI * 180)
|
||||||
|
if (!i) return
|
||||||
|
ctx.drawImage(i.image, this.x - vp.x, this.y - vp.y + b, this.width, this.height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EntityLayer {
|
||||||
|
constructor (name) {
|
||||||
|
this.name = name
|
||||||
|
this.entities = []
|
||||||
|
}
|
||||||
|
|
||||||
|
getActiveEntities (vp, world, cleanup = false) {
|
||||||
|
let active = []
|
||||||
|
let alive = []
|
||||||
|
for (let i in this.entities) {
|
||||||
|
let ent = this.entities[i]
|
||||||
|
if (ent.dead) {
|
||||||
|
continue
|
||||||
|
} else if (cleanup) {
|
||||||
|
alive.push(ent)
|
||||||
|
}
|
||||||
|
let entInChunk = world.gridPosition(vp, ent)
|
||||||
|
if (!entInChunk || !entInChunk.chunk) continue
|
||||||
|
let entChunk
|
||||||
|
for (let i in world._active) {
|
||||||
|
let chunk = world._active[i]
|
||||||
|
if (chunk.x === entInChunk.chunk.x && chunk.y === entInChunk.chunk.y) {
|
||||||
|
entChunk = chunk
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!entChunk) continue
|
||||||
|
ent._chunk = entChunk
|
||||||
|
active.push(ent)
|
||||||
|
}
|
||||||
|
if (cleanup) this.entities = alive
|
||||||
|
return active
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update active entities and clean up dead ones
|
||||||
|
update (dt, vp, world) {
|
||||||
|
let active = this.getActiveEntities(vp, world, true)
|
||||||
|
for (let i in active) {
|
||||||
|
let ent = active[i]
|
||||||
|
ent.update(dt, vp, world, ent._chunk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
draw (vp, world) {
|
||||||
|
let active = this.getActiveEntities(vp, world)
|
||||||
|
for (let i in active) {
|
||||||
|
let ent = active[i]
|
||||||
|
if (ent.x > vp.x + vp.width + ent.width || ent.x + ent._chunk.fullSize < vp.x - ent.width ||
|
||||||
|
ent.y > vp.y + vp.height + ent.height || ent.y + ent._chunk.fullSize < vp.y - ent.height) continue
|
||||||
|
ent.draw(vp, world)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ItemEntity, PhysicsEntity, EntityLayer }
|
93
src/index.js
93
src/index.js
@ -1,14 +1,14 @@
|
|||||||
/* global requestAnimationFrame */
|
/* global requestAnimationFrame */
|
||||||
import { canvas, ctx } from './canvas'
|
import { canvas, ctx } from './canvas'
|
||||||
import { Tile, TileMap, World } from './tiles'
|
import { World } from './tiles'
|
||||||
import { ItemPlaceable } from './items'
|
// 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'
|
||||||
import Input from './input'
|
import Input from './input'
|
||||||
import Viewport from './viewport'
|
import Viewport from './viewport'
|
||||||
import RES from './resource'
|
import RES from './resource'
|
||||||
|
import map from './register'
|
||||||
|
|
||||||
let playing = false
|
let playing = false
|
||||||
let frameTime = 0
|
let frameTime = 0
|
||||||
@ -17,111 +17,24 @@ 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)
|
|
||||||
|
|
||||||
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
|
|
||||||
map.register([
|
|
||||||
new Tile('DIRT_CORNER_TOP_LEFT', 0, true, dirtItem),
|
|
||||||
new Tile('DIRT_TOP', 1, true, dirtItem),
|
|
||||||
new Tile('DIRT_CORNER_TOP_RIGHT', 2, true, dirtItem),
|
|
||||||
new Tile('DIRT_INNER_BOTTOM_RIGHT', 3, true, dirtItem),
|
|
||||||
new Tile('DIRT_INNER_BOTTOM_LEFT', 4, true, dirtItem),
|
|
||||||
new Tile('DIRT_LEFT', 32, true, dirtItem),
|
|
||||||
dirtTile,
|
|
||||||
new Tile('DIRT_RIGHT', 34, true, dirtItem),
|
|
||||||
new Tile('DIRT_INNER_TOP_RIGHT', 35, true, dirtItem),
|
|
||||||
new Tile('DIRT_INNER_TOP_LEFT', 36, true, dirtItem),
|
|
||||||
new Tile('DIRT_CORNER_BOTTOM_LEFT', 64, true, dirtItem),
|
|
||||||
new Tile('DIRT_BOTTOM', 65, true, dirtItem),
|
|
||||||
new Tile('DIRT_CORNER_BOTTOM_RIGHT', 66, true, dirtItem)
|
|
||||||
])
|
|
||||||
|
|
||||||
// Define grass tiles
|
|
||||||
map.register([
|
|
||||||
new Tile('GRASS_CORNER_TOP_LEFT', 5, true, dirtItem),
|
|
||||||
grassTile,
|
|
||||||
new Tile('GRASS_CORNER_TOP_RIGHT', 7, true, dirtItem),
|
|
||||||
new Tile('GRASS_INNER_BOTTOM_RIGHT', 8, true, dirtItem),
|
|
||||||
new Tile('GRASS_INNER_BOTTOM_LEFT', 9, true, dirtItem),
|
|
||||||
new Tile('GRASS_LEFT', 37, true, dirtItem),
|
|
||||||
new Tile('GRASS_RIGHT', 39, true, dirtItem),
|
|
||||||
new Tile('GRASS_INNER_TOP_RIGHT', 40, true, dirtItem),
|
|
||||||
new Tile('GRASS_INNER_TOP_LEFT', 41, true, dirtItem),
|
|
||||||
new Tile('GRASS_CORNER_BOTTOM_LEFT', 69, true, dirtItem),
|
|
||||||
new Tile('GRASS_BOTTOM', 70, true, dirtItem),
|
|
||||||
new Tile('GRASS_CORNER_BOTTOM_RIGHT', 71, true, dirtItem)
|
|
||||||
])
|
|
||||||
|
|
||||||
// Define other tiles
|
|
||||||
map.register([
|
|
||||||
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)
|
||||||
|
|
||||||
function update (dt) {
|
function update (dt) {
|
||||||
world.update(dt, vp)
|
world.update(dt, vp)
|
||||||
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']) {
|
|
||||||
let mpin = world.pickMouse(vp, Input.mouse.pos)
|
|
||||||
if (mpin.chunk) {
|
|
||||||
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']) {
|
|
||||||
let mpin = world.pickMouse(vp, Input.mouse.pos)
|
|
||||||
if (mpin.chunk) {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function draw () {
|
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 () {
|
||||||
|
16
src/items.js
16
src/items.js
@ -36,16 +36,22 @@ class ItemPlaceable extends Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ItemTool extends Item {
|
||||||
|
use (dt, world, player) {}
|
||||||
|
|
||||||
|
useSecondary (dt, world, player) {}
|
||||||
|
}
|
||||||
|
|
||||||
class ItemStack {
|
class ItemStack {
|
||||||
static fromIString (str) {
|
static fromIString (str) {
|
||||||
if (typeof str !== 'string') return
|
if (typeof str !== 'string') return
|
||||||
let strpl = str.split(' ')
|
let strpl = str.split(' ')
|
||||||
let iname = strpl[0]
|
let iname = strpl[0]
|
||||||
let count = strpl[1]
|
let count = parseInt(strpl[1])
|
||||||
let item = ItemRegistry.get(iname)
|
let item = ItemRegistry.get(iname)
|
||||||
let istack = new ItemStack()
|
let istack = new ItemStack()
|
||||||
istack.item = item
|
istack.item = item
|
||||||
istack.count = count || 1
|
istack.count = isNaN(count) ? 1 : count
|
||||||
return istack
|
return istack
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +88,10 @@ class ItemStack {
|
|||||||
a.count = c
|
a.count = c
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toString () {
|
||||||
|
return this.name + ' ' + this.count + (this.metadata ? ' ' + JSON.stringify(this.metadata) : '')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Item, ItemPlaceable, ItemStack, ItemRegistry, MAX_STACK_SIZE }
|
export { Item, ItemPlaceable, ItemTool, ItemStack, ItemRegistry, MAX_STACK_SIZE }
|
||||||
|
107
src/player.js
107
src/player.js
@ -1,50 +1,54 @@
|
|||||||
import { ctx } from './canvas'
|
import { ctx } from './canvas'
|
||||||
|
import { PhysicsEntity, ItemEntity } from './entity'
|
||||||
|
import { ItemStack } from './items'
|
||||||
|
import { Inventory } from './inventory'
|
||||||
import Input from './input'
|
import Input from './input'
|
||||||
|
|
||||||
class Player {
|
class Player extends PhysicsEntity {
|
||||||
constructor (x, y, w, h) {
|
constructor (x, y, w, h) {
|
||||||
this.x = x
|
super(x, y, w, h)
|
||||||
this.y = y
|
|
||||||
|
|
||||||
this.width = w
|
|
||||||
this.height = h
|
|
||||||
|
|
||||||
this.mX = 0
|
|
||||||
this.mY = 0
|
|
||||||
|
|
||||||
this.grounded = false
|
|
||||||
|
|
||||||
this.speed = 8
|
this.speed = 8
|
||||||
this.gravity = 1
|
this.gravity = 1
|
||||||
this.jumpPower = 20
|
this.jumpPower = 20
|
||||||
|
|
||||||
|
this.inv = new Inventory(9)
|
||||||
|
this.itemPickUpDistance = 40
|
||||||
}
|
}
|
||||||
|
|
||||||
moveAndSlide (collider) {
|
handleTool (dt, vp, world) {
|
||||||
// y collision
|
let mabs = { x: Input.mouse.pos.x + vp.x, y: Input.mouse.pos.y + vp.y }
|
||||||
let oldY = this.y
|
let mpin = world.gridPosition(mabs)
|
||||||
this.y += this.mY
|
if (Input.mouse['btn0']) {
|
||||||
if (oldY !== this.y && collider.collide(this)) {
|
if (mpin.chunk) {
|
||||||
if (this.y > oldY) this.grounded = true
|
if (this.inv.isEmpty(this.inv.selected)) return
|
||||||
this.y = oldY
|
let tile = mpin.chunk.getTile('fg', mpin.tile)
|
||||||
this.mY = 0
|
if (tile !== -1) return
|
||||||
} else {
|
let itm = this.inv.getItem(this.inv.selected)
|
||||||
this.grounded = false
|
if (itm && itm.item.placeable) {
|
||||||
}
|
let success = mpin.chunk.setTile('fg', mpin.tile, itm.item.placeable.id)
|
||||||
|
if (success) {
|
||||||
// x collision
|
this.inv.takeItem(this.inv.selected, 1)
|
||||||
let oldX = this.x
|
}
|
||||||
this.x += this.mX
|
}
|
||||||
if (oldX !== this.x && collider.collide(this)) {
|
}
|
||||||
this.mX = this.mX < 0 ? -1 : 1
|
} else if (Input.mouse['btn2']) {
|
||||||
this.x = oldX + this.mX
|
if (mpin.chunk) {
|
||||||
if (collider.collide(this)) {
|
let layer = mpin.chunk.getLayer('fg')
|
||||||
this.x = oldX
|
let tile = layer.tileAtXY(mpin.tile.x, mpin.tile.y)
|
||||||
this.mX = 0
|
if (tile === -1) return
|
||||||
|
let itile = layer.map.getTileByID(tile)
|
||||||
|
let success = mpin.chunk.setTile('fg', mpin.tile, layer.map.indexOf('AIR'))
|
||||||
|
if (success) {
|
||||||
|
let e = ItemEntity.new(ItemStack.new(itile.item, 1), mabs.x - 8, mabs.y - 8)
|
||||||
|
let p = world.getLayer('ents')
|
||||||
|
p.entities.push(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update (dt, vp, world) {
|
handleMovement (dt, vp, world) {
|
||||||
this.mY += this.gravity
|
this.mY += this.gravity
|
||||||
if (Input.isDown('a')) {
|
if (Input.isDown('a')) {
|
||||||
this.mX = -this.speed
|
this.mX = -this.speed
|
||||||
@ -64,9 +68,46 @@ class Player {
|
|||||||
vp.y = parseInt(this.y - vp.height / 2)
|
vp.y = parseInt(this.y - vp.height / 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleInventory () {
|
||||||
|
for (let i = 0; i < this.inv.size; i++) {
|
||||||
|
let pressed = Input.isPressed(i + 1)
|
||||||
|
if (pressed) {
|
||||||
|
this.inv.selected = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pickUp (itemEntity) {
|
||||||
|
let istr = itemEntity.istr
|
||||||
|
let istack = ItemStack.new(istr)
|
||||||
|
this.inv.addItem(istack)
|
||||||
|
itemEntity.dead = true
|
||||||
|
}
|
||||||
|
|
||||||
|
handleWorldEntities (dt, vp, world) {
|
||||||
|
let entities = world.getLayer('ents')
|
||||||
|
if (!entities) return
|
||||||
|
let active = entities.getActiveEntities(vp, world)
|
||||||
|
for (let i in active) {
|
||||||
|
let ent = active[i]
|
||||||
|
if (!(ent instanceof ItemEntity)) continue
|
||||||
|
if (ent.distance(this) > this.itemPickUpDistance) continue
|
||||||
|
this.pickUp(ent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update (dt, vp, world) {
|
||||||
|
this.handleTool(dt, vp, world)
|
||||||
|
this.handleWorldEntities(dt, vp, world)
|
||||||
|
this.handleInventory()
|
||||||
|
this.handleMovement(dt, vp, world)
|
||||||
|
}
|
||||||
|
|
||||||
draw (vp) {
|
draw (vp) {
|
||||||
ctx.fillStyle = '#f00'
|
ctx.fillStyle = '#f00'
|
||||||
ctx.fillRect(this.x - vp.x, this.y - vp.y, this.width, this.height)
|
ctx.fillRect(this.x - vp.x, this.y - vp.y, this.width, this.height)
|
||||||
|
this.inv.draw()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
60
src/register.js
Normal file
60
src/register.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { Tile, TileMap } from './tiles'
|
||||||
|
import { ItemPlaceable } from './items'
|
||||||
|
|
||||||
|
const map = new TileMap('assets/ground.png', 32)
|
||||||
|
|
||||||
|
// Basic tiles
|
||||||
|
const dirtTile = new Tile('DIRT', 33)
|
||||||
|
const grassTile = new Tile('GRASS_TOP', 6)
|
||||||
|
const stoneTile = new Tile('STONE', 10)
|
||||||
|
|
||||||
|
// Items for basic tiles
|
||||||
|
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')
|
||||||
|
|
||||||
|
// Set the items
|
||||||
|
dirtTile.item = dirtItem
|
||||||
|
grassTile.item = grassItem
|
||||||
|
stoneTile.item = stoneItem
|
||||||
|
|
||||||
|
// Register dirt tiles
|
||||||
|
map.register([
|
||||||
|
new Tile('DIRT_CORNER_TOP_LEFT', 0, true, dirtItem),
|
||||||
|
new Tile('DIRT_TOP', 1, true, dirtItem),
|
||||||
|
new Tile('DIRT_CORNER_TOP_RIGHT', 2, true, dirtItem),
|
||||||
|
new Tile('DIRT_INNER_BOTTOM_RIGHT', 3, true, dirtItem),
|
||||||
|
new Tile('DIRT_INNER_BOTTOM_LEFT', 4, true, dirtItem),
|
||||||
|
new Tile('DIRT_LEFT', 32, true, dirtItem),
|
||||||
|
dirtTile,
|
||||||
|
new Tile('DIRT_RIGHT', 34, true, dirtItem),
|
||||||
|
new Tile('DIRT_INNER_TOP_RIGHT', 35, true, dirtItem),
|
||||||
|
new Tile('DIRT_INNER_TOP_LEFT', 36, true, dirtItem),
|
||||||
|
new Tile('DIRT_CORNER_BOTTOM_LEFT', 64, true, dirtItem),
|
||||||
|
new Tile('DIRT_BOTTOM', 65, true, dirtItem),
|
||||||
|
new Tile('DIRT_CORNER_BOTTOM_RIGHT', 66, true, dirtItem)
|
||||||
|
])
|
||||||
|
|
||||||
|
// Register grass tiles
|
||||||
|
map.register([
|
||||||
|
new Tile('GRASS_CORNER_TOP_LEFT', 5, true, grassItem),
|
||||||
|
grassTile,
|
||||||
|
new Tile('GRASS_CORNER_TOP_RIGHT', 7, true, grassItem),
|
||||||
|
new Tile('GRASS_INNER_BOTTOM_RIGHT', 8, true, grassItem),
|
||||||
|
new Tile('GRASS_INNER_BOTTOM_LEFT', 9, true, grassItem),
|
||||||
|
new Tile('GRASS_LEFT', 37, true, grassItem),
|
||||||
|
new Tile('GRASS_RIGHT', 39, true, grassItem),
|
||||||
|
new Tile('GRASS_INNER_TOP_RIGHT', 40, true, grassItem),
|
||||||
|
new Tile('GRASS_INNER_TOP_LEFT', 41, true, grassItem),
|
||||||
|
new Tile('GRASS_CORNER_BOTTOM_LEFT', 69, true, grassItem),
|
||||||
|
new Tile('GRASS_BOTTOM', 70, true, grassItem),
|
||||||
|
new Tile('GRASS_CORNER_BOTTOM_RIGHT', 71, true, grassItem)
|
||||||
|
])
|
||||||
|
|
||||||
|
// Register other tiles
|
||||||
|
map.register([
|
||||||
|
new Tile('AIR', -1, false),
|
||||||
|
stoneTile
|
||||||
|
])
|
||||||
|
|
||||||
|
export default map
|
35
src/tiles.js
35
src/tiles.js
@ -2,6 +2,7 @@ import { ctx, ResourceCacheFactory } from './canvas'
|
|||||||
import { distanceTo } from './utils'
|
import { distanceTo } from './utils'
|
||||||
import Resource from './resource'
|
import Resource from './resource'
|
||||||
import Debug from './debug'
|
import Debug from './debug'
|
||||||
|
import { EntityLayer } from './entity'
|
||||||
|
|
||||||
const cacheFactory = new ResourceCacheFactory()
|
const cacheFactory = new ResourceCacheFactory()
|
||||||
const UPDATE_RADIUS = 6
|
const UPDATE_RADIUS = 6
|
||||||
@ -365,6 +366,7 @@ class World {
|
|||||||
this.tileSize = tileSize
|
this.tileSize = tileSize
|
||||||
this.tileMaps = tileMaps
|
this.tileMaps = tileMaps
|
||||||
this.chunks = []
|
this.chunks = []
|
||||||
|
this.layers = []
|
||||||
this.height = height
|
this.height = height
|
||||||
this.width = width
|
this.width = width
|
||||||
|
|
||||||
@ -376,6 +378,9 @@ class World {
|
|||||||
this._lastDrawCount = 0
|
this._lastDrawCount = 0
|
||||||
this._lastUpdateCount = 0
|
this._lastUpdateCount = 0
|
||||||
this._active = []
|
this._active = []
|
||||||
|
|
||||||
|
// Create world layers
|
||||||
|
this.layers.push(new EntityLayer('ents'))
|
||||||
}
|
}
|
||||||
|
|
||||||
getChunk (x, y) {
|
getChunk (x, y) {
|
||||||
@ -386,6 +391,14 @@ class World {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLayer (name) {
|
||||||
|
for (let i in this.layers) {
|
||||||
|
let layer = this.layers[i]
|
||||||
|
if (layer.name === name) return layer
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
update (dt, vp) {
|
update (dt, vp) {
|
||||||
this._active = []
|
this._active = []
|
||||||
let posPoint = vp.chunkIn(this.chunkSize * this.tileSize)
|
let posPoint = vp.chunkIn(this.chunkSize * this.tileSize)
|
||||||
@ -403,6 +416,7 @@ class World {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update chunks
|
||||||
for (let i in this.chunks) {
|
for (let i in this.chunks) {
|
||||||
this.chunks[i].update(dt)
|
this.chunks[i].update(dt)
|
||||||
}
|
}
|
||||||
@ -416,22 +430,26 @@ class World {
|
|||||||
let chunk = this.chunks[i]
|
let chunk = this.chunks[i]
|
||||||
let pos = chunk.absPos
|
let pos = chunk.absPos
|
||||||
let distance = distanceTo(vp.adjustCentered, pos)
|
let distance = distanceTo(vp.adjustCentered, pos)
|
||||||
if (distance <= chunk.fullSize * UPDATE_RADIUS) {
|
if (distance <= chunk.fullSize * UPDATE_RADIUS || chunk.modified) {
|
||||||
// Keep chunk
|
// Keep chunk
|
||||||
keep.push(chunk)
|
keep.push(chunk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.chunks = keep
|
this.chunks = keep
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update layers
|
||||||
|
for (let i in this.layers) {
|
||||||
|
this.layers[i].update(dt, vp, this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pickMouse (vp, mousePos) {
|
gridPosition (pos) {
|
||||||
let a = this.chunkSize * this.tileSize
|
let a = this.chunkSize * this.tileSize
|
||||||
let abs = { x: mousePos.x + vp.x, y: mousePos.y + vp.y }
|
let chunk = { x: Math.floor(pos.x / a), y: Math.floor(pos.y / a) }
|
||||||
let chunk = { x: Math.floor(abs.x / a), y: Math.floor(abs.y / a) }
|
|
||||||
let tile = {
|
let tile = {
|
||||||
x: Math.floor(abs.x / this.tileSize - chunk.x * this.chunkSize),
|
x: Math.floor(pos.x / this.tileSize - chunk.x * this.chunkSize),
|
||||||
y: Math.floor(abs.y / this.tileSize - chunk.y * this.chunkSize)
|
y: Math.floor(pos.y / this.tileSize - chunk.y * this.chunkSize)
|
||||||
}
|
}
|
||||||
return { chunk: this.getChunk(chunk.x, chunk.y), tile }
|
return { chunk: this.getChunk(chunk.x, chunk.y), tile }
|
||||||
}
|
}
|
||||||
@ -449,6 +467,11 @@ class World {
|
|||||||
if (chunk._updated) this._lastUpdateCount++
|
if (chunk._updated) this._lastUpdateCount++
|
||||||
this._lastDrawCount++
|
this._lastDrawCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw layers
|
||||||
|
for (let i in this.layers) {
|
||||||
|
this.layers[i].draw(vp, this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
collide (obj) {
|
collide (obj) {
|
||||||
|
Loading…
Reference in New Issue
Block a user