Compare commits
No commits in common. "94b2c6b140f82a47e803a5ecbc406558ff935c91" and "b2624eb989572e62864fa3deb2c6699414356a84" have entirely different histories.
94b2c6b140
...
b2624eb989
127
rooms/sample.tmj
127
rooms/sample.tmj
@ -33,134 +33,13 @@
|
|||||||
"x":0,
|
"x":0,
|
||||||
"y":0
|
"y":0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"draworder":"topdown",
|
|
||||||
"id":3,
|
|
||||||
"name":"Object Layer 1",
|
|
||||||
"objects":[
|
|
||||||
{
|
|
||||||
"height":64,
|
|
||||||
"id":1,
|
|
||||||
"name":"hi_box",
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"color",
|
|
||||||
"type":"string",
|
|
||||||
"value":"red"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name":"event",
|
|
||||||
"type":"string",
|
|
||||||
"value":"change_color"
|
|
||||||
}],
|
|
||||||
"rotation":0,
|
|
||||||
"type":"",
|
|
||||||
"visible":true,
|
|
||||||
"width":64,
|
|
||||||
"x":128,
|
|
||||||
"y":256
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"height":64,
|
|
||||||
"id":4,
|
|
||||||
"name":"low_box",
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"color",
|
|
||||||
"type":"string",
|
|
||||||
"value":"green"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name":"event",
|
|
||||||
"type":"string",
|
|
||||||
"value":"change_color"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name":"interactEvent",
|
|
||||||
"type":"string",
|
|
||||||
"value":"log_test"
|
|
||||||
}],
|
|
||||||
"rotation":0,
|
|
||||||
"type":"",
|
|
||||||
"visible":true,
|
|
||||||
"width":64,
|
|
||||||
"x":128,
|
|
||||||
"y":384
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"height":46.3794477161778,
|
|
||||||
"id":5,
|
|
||||||
"name":"sign_crate",
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name":"interactEvent",
|
|
||||||
"type":"string",
|
|
||||||
"value":"show_message"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name":"messageText",
|
|
||||||
"type":"string",
|
|
||||||
"value":"I'm just a humble box!\nIt's possible to say more than one thing you know."
|
|
||||||
}],
|
|
||||||
"rotation":0,
|
|
||||||
"type":"",
|
|
||||||
"visible":true,
|
|
||||||
"width":41.2588439219327,
|
|
||||||
"x":331.477887674811,
|
|
||||||
"y":401.217123575356
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"height":37.6264667354163,
|
|
||||||
"id":6,
|
|
||||||
"name":"",
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}],
|
|
||||||
"rotation":0,
|
|
||||||
"type":"",
|
|
||||||
"visible":true,
|
|
||||||
"width":23.6907383148917,
|
|
||||||
"x":403.02126592157,
|
|
||||||
"y":408.316842721369
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"height":35.6754647565428,
|
|
||||||
"id":7,
|
|
||||||
"name":"",
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}],
|
|
||||||
"rotation":0,
|
|
||||||
"type":"",
|
|
||||||
"visible":true,
|
|
||||||
"width":30.3798879567435,
|
|
||||||
"x":656.930237743527,
|
|
||||||
"y":411.661417542295
|
|
||||||
}],
|
|
||||||
"opacity":1,
|
|
||||||
"type":"objectgroup",
|
|
||||||
"visible":true,
|
|
||||||
"x":0,
|
|
||||||
"y":0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
182, 0, 0, 0, 0, 188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 189, 229, 0, 0, 0, 190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 189, 229, 0, 0, 0, 190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
@ -185,8 +64,8 @@
|
|||||||
"x":0,
|
"x":0,
|
||||||
"y":0
|
"y":0
|
||||||
}],
|
}],
|
||||||
"nextlayerid":4,
|
"nextlayerid":3,
|
||||||
"nextobjectid":8,
|
"nextobjectid":1,
|
||||||
"orientation":"orthogonal",
|
"orientation":"orthogonal",
|
||||||
"renderorder":"right-down",
|
"renderorder":"right-down",
|
||||||
"tiledversion":"1.11.2",
|
"tiledversion":"1.11.2",
|
||||||
|
@ -12,12 +12,13 @@ const ROOM_ASSETS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class Assets {
|
export default class Assets {
|
||||||
constructor(game) {
|
constructor() {
|
||||||
this.game = game
|
|
||||||
this.assetMap = {}
|
this.assetMap = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
get(assetName) {
|
get(assetName) {
|
||||||
|
console.log("getting", assetName)
|
||||||
|
console.log("from", this.assetMap)
|
||||||
return this.assetMap[assetName]
|
return this.assetMap[assetName]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,6 +44,7 @@ export default class Assets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadImage(name, path) {
|
loadImage(name, path) {
|
||||||
|
console.log(name, path)
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const img = new Image()
|
const img = new Image()
|
||||||
this.assetMap[name] = img
|
this.assetMap[name] = img
|
||||||
@ -53,13 +55,13 @@ export default class Assets {
|
|||||||
|
|
||||||
loadTileset(name, path) {
|
loadTileset(name, path) {
|
||||||
return fetch(path).then(rsp => rsp.json()).then(json => {
|
return fetch(path).then(rsp => rsp.json()).then(json => {
|
||||||
return this.assetMap[name] = new Tileset(this.game, json, name)
|
return this.assetMap[name] = new Tileset(json, name)
|
||||||
}).then(tileset => this.loadImages(tileset.imagesToLoad))
|
}).then(tileset => this.loadImages(tileset.imagesToLoad))
|
||||||
}
|
}
|
||||||
|
|
||||||
loadRoom(name, path) {
|
loadRoom(name, path) {
|
||||||
return fetch(path).then(rsp => rsp.json()).then(json => {
|
return fetch(path).then(rsp => rsp.json()).then(json => {
|
||||||
return this.assetMap[name] = new Room(this.game, json, name)
|
return this.assetMap[name] = new Room(json, name)
|
||||||
}).then(room => this.loadTilesets(room.tilesetsToLoad))
|
}).then(room => this.loadTilesets(room.tilesetsToLoad))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
21
src/event.js
21
src/event.js
@ -1,21 +0,0 @@
|
|||||||
export default class Event {
|
|
||||||
constructor(name, action) {
|
|
||||||
this.name = name
|
|
||||||
this.action = action
|
|
||||||
this.triggered = false
|
|
||||||
this.triggeredThisFrame = false
|
|
||||||
}
|
|
||||||
|
|
||||||
trigger(object) {
|
|
||||||
this.triggeredThisFrame = true
|
|
||||||
if (!this.triggered) {
|
|
||||||
this.triggered = true
|
|
||||||
this.action(object)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nextFrame() {
|
|
||||||
this.triggered = this.triggeredThisFrame
|
|
||||||
this.triggeredThisFrame = false
|
|
||||||
}
|
|
||||||
}
|
|
60
src/game.js
60
src/game.js
@ -1,90 +1,40 @@
|
|||||||
import Player from "./player.js"
|
import Player from "./player.js"
|
||||||
import Input from "./input.js"
|
import Input from "./input.js"
|
||||||
import Event from "./event.js"
|
|
||||||
import Message from "./message.js"
|
|
||||||
|
|
||||||
import { average } from "./util.js"
|
|
||||||
|
|
||||||
export default class Game {
|
export default class Game {
|
||||||
constructor(canvas) {
|
constructor(canvas) {
|
||||||
this.canvas = canvas
|
this.canvas = canvas
|
||||||
this.ctx = canvas.getContext("2d")
|
this.ctx = canvas.getContext("2d")
|
||||||
this.timestamp = 0
|
this.timestamp = 0
|
||||||
this.player = new Player(this, 200, 200)
|
this.actors = []
|
||||||
this.actors = [this.player]
|
this.actors.push(new Player(this, 200, 200))
|
||||||
|
|
||||||
this.input = new Input().initialize()
|
this.input = new Input().initialize()
|
||||||
|
|
||||||
this.currentRoom = null
|
this.currentRoom = null
|
||||||
this.events = {
|
|
||||||
"log_test": new Event("log_test", () => console.log("Log events work!")),
|
|
||||||
"change_color": new Event("change_color", object => object.setProperty("color", "blue")),
|
|
||||||
"show_message": new Event("show_message", object => this.message = new Message(this, object.getProperty("messageText")))
|
|
||||||
}
|
|
||||||
|
|
||||||
this.message = null
|
|
||||||
|
|
||||||
this.fpsBuffer = [60, 60, 60, 60, 60, 60, 60, 60, 60, 60]
|
|
||||||
}
|
|
||||||
|
|
||||||
triggerEvent(eventName, object) {
|
|
||||||
const event = this.events[eventName]
|
|
||||||
if (event) event.trigger(object)
|
|
||||||
else console.error("Unknown event " + eventName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
this.loadRoom(this.assets.get("sampleRoom"))
|
this.currentRoom = this.assets.get("sampleRoom")
|
||||||
requestAnimationFrame(this.loop.bind(this))
|
requestAnimationFrame(this.loop.bind(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
loadRoom(room) {
|
|
||||||
this.currentRoom = room
|
|
||||||
this.currentRoom.objects.forEach(roomObject => this.actors.push(roomObject))
|
|
||||||
}
|
|
||||||
|
|
||||||
closeMessage(message) {
|
|
||||||
this.message = null
|
|
||||||
}
|
|
||||||
|
|
||||||
loop(timestamp) {
|
loop(timestamp) {
|
||||||
this.dt = timestamp - this.timestamp
|
const dt = timestamp - this.timestamp
|
||||||
const fps = 1000 / this.dt
|
|
||||||
this.fpsBuffer.pop()
|
|
||||||
this.fpsBuffer.unshift(fps)
|
|
||||||
this.timestamp = timestamp
|
this.timestamp = timestamp
|
||||||
this.tick(this.dt)
|
this.tick(dt)
|
||||||
this.draw()
|
this.draw()
|
||||||
|
|
||||||
requestAnimationFrame(this.loop.bind(this))
|
requestAnimationFrame(this.loop.bind(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
tick(dt) {
|
tick(dt) {
|
||||||
if (this.message) {
|
|
||||||
this.message?.tick(dt)
|
|
||||||
} else {
|
|
||||||
this.actors.forEach(actor => actor.tick(dt))
|
this.actors.forEach(actor => actor.tick(dt))
|
||||||
Object.values(this.events).forEach(e => e.nextFrame())
|
|
||||||
}
|
|
||||||
this.input.tick()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
const { canvas, ctx } = this
|
const { canvas, ctx } = this
|
||||||
this.currentRoom.draw(ctx)
|
this.currentRoom.draw(ctx)
|
||||||
this.actors.forEach(actor => actor.draw(ctx))
|
this.actors.forEach(actor => actor.draw(ctx))
|
||||||
this.message?.draw(ctx)
|
|
||||||
this.drawFps(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
drawFps(ctx) {
|
|
||||||
ctx.fillStyle = "white"
|
|
||||||
ctx.fillRect(ctx.canvas.width, 0, -25, 20)
|
|
||||||
ctx.strokeStyle = "black"
|
|
||||||
ctx.textBaseline = "top"
|
|
||||||
ctx.textAlign = "right"
|
|
||||||
ctx.font = "bold 20px serif"
|
|
||||||
ctx.fillText(Math.round(average(this.fpsBuffer)), ctx.canvas.width, 0)
|
|
||||||
ctx.strokeText(Math.round(average(this.fpsBuffer)), ctx.canvas.width, 0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ document.addEventListener("DOMContentLoaded", async e => {
|
|||||||
const canvas = document.getElementById("game-canvas")
|
const canvas = document.getElementById("game-canvas")
|
||||||
const game = new Game(canvas)
|
const game = new Game(canvas)
|
||||||
|
|
||||||
game.assets = new Assets(game)
|
game.assets = new Assets()
|
||||||
await game.assets.load()
|
await game.assets.load()
|
||||||
|
|
||||||
game.start()
|
game.start()
|
||||||
|
18
src/input.js
18
src/input.js
@ -12,17 +12,11 @@ export default class Input {
|
|||||||
this.inputsToKeys = Object.fromEntries(Object.keys(this.keysToInputs).map(key => [this.keysToInputs[key], key]))
|
this.inputsToKeys = Object.fromEntries(Object.keys(this.keysToInputs).map(key => [this.keysToInputs[key], key]))
|
||||||
|
|
||||||
this.inputPressed = Object.fromEntries(Object.keys(this.inputsToKeys).map(key => [key, false]))
|
this.inputPressed = Object.fromEntries(Object.keys(this.inputsToKeys).map(key => [key, false]))
|
||||||
this.inputJustPressed = Object.fromEntries(Object.keys(this.inputsToKeys).map(key => [key, false]))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize() {
|
initialize() {
|
||||||
window.addEventListener("keydown", key => {
|
window.addEventListener("keydown", key => this.inputPressed[this.keyFromInput(key.key)] = true)
|
||||||
this.inputJustPressed[this.keyFromInput(key.key)] = true
|
window.addEventListener("keyup", key => this.inputPressed[this.keyFromInput(key.key)] = false)
|
||||||
this.inputPressed[this.keyFromInput(key.key)] = true
|
|
||||||
})
|
|
||||||
window.addEventListener("keyup", key => {
|
|
||||||
this.inputPressed[this.keyFromInput(key.key)] = false
|
|
||||||
})
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,14 +24,6 @@ export default class Input {
|
|||||||
return !!this.inputPressed[inputName]
|
return !!this.inputPressed[inputName]
|
||||||
}
|
}
|
||||||
|
|
||||||
isInputJustPressed(inputName) {
|
|
||||||
return !!this.inputJustPressed[inputName]
|
|
||||||
}
|
|
||||||
|
|
||||||
tick() {
|
|
||||||
this.inputJustPressed = Object.fromEntries(Object.keys(this.inputsToKeys).map(key => [key, false]))
|
|
||||||
}
|
|
||||||
|
|
||||||
keyFromInput(input) {
|
keyFromInput(input) {
|
||||||
return this.keysToInputs[input]
|
return this.keysToInputs[input]
|
||||||
}
|
}
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
export default class Message {
|
|
||||||
constructor(game, text) {
|
|
||||||
this.game = game
|
|
||||||
this.text = text.split("\n")
|
|
||||||
this.currentText = this.text.shift()
|
|
||||||
this.textColor = "white"
|
|
||||||
this.backgroundColor = "black"
|
|
||||||
this.textIndex = 0
|
|
||||||
this.textProgress = 0.0
|
|
||||||
this.textSpeed = 0.08 // seconds per character
|
|
||||||
this.backgroundHeight = 40
|
|
||||||
this.textSize = 30
|
|
||||||
}
|
|
||||||
|
|
||||||
tick(dt) {
|
|
||||||
this.textProgress += (dt / 1000.0) / this.textSpeed
|
|
||||||
this.textIndex = Math.floor(this.textProgress)
|
|
||||||
|
|
||||||
const ijp = this.game.input.isInputJustPressed("interact")
|
|
||||||
if (ijp) {
|
|
||||||
if (this.messageComplete()) {
|
|
||||||
this.game.closeMessage(this)
|
|
||||||
} else if (this.lineComplete()) {
|
|
||||||
this.currentText = this.text.shift()
|
|
||||||
this.textProgress = 0.0
|
|
||||||
this.textIndex = 0
|
|
||||||
} else {
|
|
||||||
this.textProgress = this.currentText.length
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
draw(ctx) {
|
|
||||||
ctx.fillStyle = this.backgroundColor
|
|
||||||
ctx.fillRect(0, 0, ctx.canvas.width, this.backgroundHeight)
|
|
||||||
ctx.font = `bold ${this.textSize}px sans-serif`
|
|
||||||
ctx.textBaseline = "top"
|
|
||||||
ctx.textAlign = "left"
|
|
||||||
ctx.fillStyle = this.textColor
|
|
||||||
ctx.fillText(this.currentText.substring(0, this.textIndex), 5, 5)
|
|
||||||
if (this.messageComplete()) {
|
|
||||||
ctx.fillRect(
|
|
||||||
ctx.canvas.width - 20,
|
|
||||||
this.backgroundHeight - 20,
|
|
||||||
10, 10
|
|
||||||
)
|
|
||||||
} else if (this.lineComplete()) {
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.moveTo(ctx.canvas.width - 20, this.backgroundHeight - 20)
|
|
||||||
ctx.lineTo(ctx.canvas.width - 20, this.backgroundHeight - 10)
|
|
||||||
ctx.lineTo(ctx.canvas.width - 15, this.backgroundHeight - 15)
|
|
||||||
ctx.lineTo(ctx.canvas.width - 20, this.backgroundHeight - 20)
|
|
||||||
ctx.fill()
|
|
||||||
ctx.closePath()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lineComplete() {
|
|
||||||
return this.textIndex >= this.currentText.length + 3
|
|
||||||
}
|
|
||||||
|
|
||||||
messageComplete() {
|
|
||||||
return this.lineComplete() && !this.text.length
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,12 +7,11 @@ export default class Player extends Actor {
|
|||||||
this.x = x
|
this.x = x
|
||||||
this.y = y
|
this.y = y
|
||||||
this.width = 32
|
this.width = 32
|
||||||
this.height = 32
|
this.height = 64
|
||||||
this.xVel = 0
|
this.xVel = 0
|
||||||
this.yVel = 0
|
this.yVel = 0
|
||||||
this.color = "#56E"
|
this.color = "#56E"
|
||||||
this.playerDirection = { x: 0, y: 1 }
|
this.playerDirection = { x: 0, y: 1 }
|
||||||
this.interactHitbox = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tick(dt) {
|
tick(dt) {
|
||||||
@ -27,51 +26,16 @@ export default class Player extends Actor {
|
|||||||
this.x += this.xVel
|
this.x += this.xVel
|
||||||
this.y += this.yVel
|
this.y += this.yVel
|
||||||
|
|
||||||
if (this.collidesWithAbsolutelyAnything()) {
|
|
||||||
this.x -= this.xVel
|
|
||||||
this.y -= this.yVel
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isZeroVector(dir)) this.playerDirection = dir
|
if (!isZeroVector(dir)) this.playerDirection = dir
|
||||||
|
|
||||||
if (this.isInputPressed("interact")) this.createInteractHitbox()
|
|
||||||
else this.interactHitbox = null
|
|
||||||
}
|
|
||||||
|
|
||||||
collidesWithAbsolutelyAnything() {
|
|
||||||
return this.collidesWithTiles() || this.collidesWithObjects()
|
|
||||||
}
|
|
||||||
|
|
||||||
collidesWithObjects() {
|
|
||||||
const objects = this.game.currentRoom.objectsUnderRectangle(this)
|
|
||||||
return !!objects.find(object => object.collides())
|
|
||||||
}
|
|
||||||
|
|
||||||
collidesWithTiles() {
|
|
||||||
const tur = this.game.currentRoom.tilesUnderRectangle(this).filter(x => x)
|
|
||||||
const colliders = tur.filter(tile => tile.properties.find(prop => prop.name == "collides" && prop.value))
|
|
||||||
return !!colliders.length
|
|
||||||
}
|
|
||||||
|
|
||||||
createInteractHitbox() {
|
|
||||||
this.interactHitbox = {
|
|
||||||
width: this.width,
|
|
||||||
height: this.height,
|
|
||||||
x: this.x + (this.playerDirection.x * this.width / 2),
|
|
||||||
y: this.y + (this.playerDirection.y * this.height / 2),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isInputPressed(action) {
|
|
||||||
return this.game.input.isInputPressed.call(this.game.input, action)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inputDirection() {
|
inputDirection() {
|
||||||
|
const isInputPressed = this.game.input.isInputPressed.bind(this.game.input)
|
||||||
const dir = { x: 0, y: 0 }
|
const dir = { x: 0, y: 0 }
|
||||||
if (this.isInputPressed("up")) dir.y -= 1
|
if (isInputPressed("up")) dir.y -= 1
|
||||||
if (this.isInputPressed("down")) dir.y += 1
|
if (isInputPressed("down")) dir.y += 1
|
||||||
if (this.isInputPressed("left")) dir.x -= 1
|
if (isInputPressed("left")) dir.x -= 1
|
||||||
if (this.isInputPressed("right")) dir.x += 1
|
if (isInputPressed("right")) dir.x += 1
|
||||||
|
|
||||||
if (Math.abs(dir.x, dir.y) == 2) {
|
if (Math.abs(dir.x, dir.y) == 2) {
|
||||||
dir.x *= SQRT_OF_TWO
|
dir.x *= SQRT_OF_TWO
|
||||||
@ -83,11 +47,10 @@ export default class Player extends Actor {
|
|||||||
|
|
||||||
draw(ctx) {
|
draw(ctx) {
|
||||||
this.color = `rgb(128 ${(this.playerDirection.x * 128) + 128} ${(this.playerDirection.y * 128) + 128}`
|
this.color = `rgb(128 ${(this.playerDirection.x * 128) + 128} ${(this.playerDirection.y * 128) + 128}`
|
||||||
|
ctx.beginPath()
|
||||||
ctx.fillStyle = this.color
|
ctx.fillStyle = this.color
|
||||||
ctx.fillRect(this.x, this.y, this.width, this.height)
|
ctx.rect(this.x, this.y, this.width, this.height)
|
||||||
if (this.interactHitbox) {
|
ctx.fill()
|
||||||
ctx.fillStyle = "#FF000088"
|
ctx.closePath()
|
||||||
ctx.fillRect(this.interactHitbox.x, this.interactHitbox.y, this.interactHitbox.width, this.interactHitbox.height)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
61
src/room.js
61
src/room.js
@ -1,13 +1,8 @@
|
|||||||
import RoomObject from "./roomObject.js"
|
|
||||||
import { doRectanglesOverlap } from "./util.js"
|
|
||||||
|
|
||||||
export default class Room {
|
export default class Room {
|
||||||
constructor(game, json, name) {
|
constructor(json, name) {
|
||||||
this.game = game
|
|
||||||
this.json = json
|
this.json = json
|
||||||
this.name = name
|
this.name = name
|
||||||
const objectJson = this.objectLayers.map(layer => layer.objects).flat()
|
console.log(json)
|
||||||
this.objects = objectJson.map(RoomObject.fromJson.bind(null, this.game))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get tilesetsToLoad() {
|
get tilesetsToLoad() {
|
||||||
@ -19,6 +14,7 @@ export default class Room {
|
|||||||
}
|
}
|
||||||
|
|
||||||
populateTilesets(assets) {
|
populateTilesets(assets) {
|
||||||
|
console.log(this.json)
|
||||||
this.tilesets = this.json.tilesets.map((tileset, index) => {
|
this.tilesets = this.json.tilesets.map((tileset, index) => {
|
||||||
const ts = assets.get(`${this.name}-${index}`)
|
const ts = assets.get(`${this.name}-${index}`)
|
||||||
ts.populateImage(assets)
|
ts.populateImage(assets)
|
||||||
@ -27,46 +23,7 @@ export default class Room {
|
|||||||
}
|
}
|
||||||
|
|
||||||
draw(ctx) {
|
draw(ctx) {
|
||||||
this.tileLayers.forEach(this.drawTileLayer.bind(this, ctx))
|
this.json.layers.forEach(layer => {
|
||||||
}
|
|
||||||
|
|
||||||
drawLayer(ctx, layer) {
|
|
||||||
if (layer.type == "tilelayer") this.drawTileLayer(ctx, layer)
|
|
||||||
}
|
|
||||||
|
|
||||||
get tileLayers() {
|
|
||||||
return this.json.layers.filter(layer => layer.type == "tilelayer")
|
|
||||||
}
|
|
||||||
|
|
||||||
get objectLayers() {
|
|
||||||
return this.json.layers.filter(layer => layer.type == "objectgroup")
|
|
||||||
}
|
|
||||||
|
|
||||||
objectsUnderRectangle(rect) {
|
|
||||||
return this.objects.filter(object => doRectanglesOverlap(object, rect))
|
|
||||||
}
|
|
||||||
|
|
||||||
tilesUnderRectangle(rect) {
|
|
||||||
return this.tileLayers.map(layer => this.tilesUnderRectangleInLayer(layer, rect)).flat()
|
|
||||||
}
|
|
||||||
|
|
||||||
tilesUnderRectangleInLayer(layer, rect) {
|
|
||||||
return [{ x: rect.x, y: rect.y },
|
|
||||||
{ x: rect.x + rect.width, y: rect.y },
|
|
||||||
{ x: rect.x, y: rect.y + rect.height },
|
|
||||||
{ x: rect.x + rect.width, y: rect.y + rect.height }
|
|
||||||
].map(point => {
|
|
||||||
const tileset = this.tilesets[0]
|
|
||||||
const { x, y } = point
|
|
||||||
const tileX = Math.floor(x / tileset.tileWidth)
|
|
||||||
const tileY = Math.floor(y / tileset.tileHeight)
|
|
||||||
const index = tileX + (tileY * layer.width)
|
|
||||||
const tileIndex = layer.data[index] - 1
|
|
||||||
return tileset.tileAt(tileIndex)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
drawTileLayer(ctx, layer) {
|
|
||||||
for (let y = 0; y < layer.height; y++) {
|
for (let y = 0; y < layer.height; y++) {
|
||||||
for (let x = 0; x < layer.width; x++) {
|
for (let x = 0; x < layer.width; x++) {
|
||||||
const index = x + (y * layer.width)
|
const index = x + (y * layer.width)
|
||||||
@ -84,16 +41,8 @@ export default class Room {
|
|||||||
this.json.tilewidth,
|
this.json.tilewidth,
|
||||||
this.json.tileheight
|
this.json.tileheight
|
||||||
)
|
)
|
||||||
if (tileset.collides(tileIndex)) {
|
|
||||||
ctx.fillStyle = "#aa660088"
|
|
||||||
ctx.fillRect(
|
|
||||||
x * this.json.tilewidth,
|
|
||||||
y * this.json.tileheight,
|
|
||||||
this.json.tilewidth,
|
|
||||||
this.json.tileheight
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
import { doRectanglesOverlap } from "./util.js"
|
|
||||||
|
|
||||||
export default class RoomObject {
|
|
||||||
constructor(game) {
|
|
||||||
this.game = game
|
|
||||||
}
|
|
||||||
|
|
||||||
static fromJson(game, json) {
|
|
||||||
const roomObject = new RoomObject(game)
|
|
||||||
Object.entries(json).forEach(([key, value]) => roomObject[key] = value)
|
|
||||||
return roomObject
|
|
||||||
}
|
|
||||||
|
|
||||||
getProperty(name) {
|
|
||||||
const property = this.properties.find(p => p.name == name)
|
|
||||||
if (!property) {
|
|
||||||
// console.error(`Unknown property ${name} on ${this.name}`)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return property.value
|
|
||||||
}
|
|
||||||
|
|
||||||
setProperty(name, value) {
|
|
||||||
const p = this.properties.find(p => p.name == name)
|
|
||||||
if (p) {
|
|
||||||
p.value = value
|
|
||||||
} else {
|
|
||||||
this.properties[name] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tick(dt) {
|
|
||||||
const { player } = this.game
|
|
||||||
if (doRectanglesOverlap(player, this)) {
|
|
||||||
const eventName = this.getProperty.call(this, "event")
|
|
||||||
if (eventName) this.game.triggerEvent(eventName, this)
|
|
||||||
}
|
|
||||||
if (player.interactHitbox && doRectanglesOverlap(player.interactHitbox, this)) {
|
|
||||||
const eventName = this.getProperty("interactEvent")
|
|
||||||
if (eventName) this.game.triggerEvent(eventName, this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
draw(ctx) {
|
|
||||||
ctx.fillStyle = this.getProperty("color") || "#00000000"
|
|
||||||
ctx.fillRect(this.x, this.y, this.width, this.height)
|
|
||||||
}
|
|
||||||
|
|
||||||
collides() {
|
|
||||||
return this.getProperty("collides") || false
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +1,7 @@
|
|||||||
export default class Tileset {
|
export default class Tileset {
|
||||||
constructor(game, json, name) {
|
constructor(json, name) {
|
||||||
this.game = game
|
|
||||||
this.json = json
|
this.json = json
|
||||||
this.name = name
|
this.name = name
|
||||||
this.tiles = json.tiles
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get imagesToLoad() {
|
get imagesToLoad() {
|
||||||
@ -34,15 +32,4 @@ export default class Tileset {
|
|||||||
(Math.floor(index / this.columns) * this.tileHeight)
|
(Math.floor(index / this.columns) * this.tileHeight)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
tileAt(index) {
|
|
||||||
return this.tiles.find(tile => tile.id == index)
|
|
||||||
}
|
|
||||||
|
|
||||||
collides(index) {
|
|
||||||
const tile = this.tileAt(index)
|
|
||||||
if (!tile) return
|
|
||||||
|
|
||||||
return tile.properties.find(prop => prop.name == "collides").value == "true"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
24
src/util.js
24
src/util.js
@ -2,29 +2,7 @@ const SQRT_OF_TWO = Math.sqrt(2)
|
|||||||
|
|
||||||
const isZeroVector = vector => !vector.x && !vector.y
|
const isZeroVector = vector => !vector.x && !vector.y
|
||||||
|
|
||||||
const doRectanglesOverlap = (rect1, rect2) => {
|
|
||||||
return (
|
|
||||||
doLengthsOverlap({ x: rect1.x, width: rect1.width }, { x: rect2.x, width: rect2.width })
|
|
||||||
&&
|
|
||||||
doLengthsOverlap({ x: rect1.y, width: rect1.height }, { x: rect2.y, width: rect2.height })
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const doLengthsOverlap = (l1, l2) => {
|
|
||||||
return !((l1.x + l1.width < l2.x) || (l2.x + l2.width) < l1.x)
|
|
||||||
}
|
|
||||||
|
|
||||||
function sum(array) {
|
|
||||||
return array.reduce((a, b) => a + b, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
function average(array) {
|
|
||||||
return sum(array) / array.length
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
SQRT_OF_TWO,
|
SQRT_OF_TWO,
|
||||||
isZeroVector,
|
isZeroVector
|
||||||
doRectanglesOverlap,
|
|
||||||
sum, average
|
|
||||||
}
|
}
|
||||||
|
@ -8,358 +8,6 @@
|
|||||||
"tilecount":260,
|
"tilecount":260,
|
||||||
"tiledversion":"1.11.2",
|
"tiledversion":"1.11.2",
|
||||||
"tileheight":64,
|
"tileheight":64,
|
||||||
"tiles":[
|
|
||||||
{
|
|
||||||
"id":60,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":61,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":62,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":63,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":64,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":65,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":66,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":80,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":81,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":82,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":83,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":84,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":85,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":86,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":100,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":101,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":102,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":103,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":144,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":145,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":146,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":164,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":165,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":166,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":180,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":182,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":184,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":200,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":201,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":202,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":203,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":204,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":205,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":220,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":221,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":222,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":223,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":224,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id":225,
|
|
||||||
"properties":[
|
|
||||||
{
|
|
||||||
"name":"collides",
|
|
||||||
"type":"bool",
|
|
||||||
"value":true
|
|
||||||
}]
|
|
||||||
}],
|
|
||||||
"tilewidth":64,
|
"tilewidth":64,
|
||||||
"type":"tileset",
|
"type":"tileset",
|
||||||
"version":"1.10"
|
"version":"1.10"
|
||||||
|
Loading…
Reference in New Issue
Block a user