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