From 56e6a728c3d1f805593c9b1748344c0d48fea8b9 Mon Sep 17 00:00:00 2001 From: Bill Rossi Date: Sat, 7 Jun 2025 09:28:18 -0400 Subject: [PATCH] Messages! --- rooms/sample.tmj | 5 +++++ src/game.js | 21 +++++++++++++++++---- src/input.js | 18 ++++++++++++++++-- src/message.js | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 6 deletions(-) create mode 100644 src/message.js diff --git a/rooms/sample.tmj b/rooms/sample.tmj index d961a58..cf54ceb 100644 --- a/rooms/sample.tmj +++ b/rooms/sample.tmj @@ -96,6 +96,11 @@ "name":"interactEvent", "type":"string", "value":"show_message" + }, + { + "name":"messageText", + "type":"string", + "value":"I'm just a humble box!" }], "rotation":0, "type":"", diff --git a/src/game.js b/src/game.js index a8fc7c7..f253ef5 100644 --- a/src/game.js +++ b/src/game.js @@ -1,6 +1,7 @@ import Player from "./player.js" import Input from "./input.js" import Event from "./event.js" +import Message from "./message.js" export default class Game { constructor(canvas) { @@ -16,8 +17,10 @@ export default class Game { 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 => console.log("Message from " + object.name)) + "show_message": new Event("show_message", object => this.message = new Message(this, object.getProperty("messageText"))) } + + this.message = null } triggerEvent(eventName, object) { @@ -36,9 +39,13 @@ export default class Game { this.currentRoom.objects.forEach(roomObject => this.actors.push(roomObject)) } + closeMessage(message) { + this.message = null + } + loop(timestamp) { const dt = timestamp - this.timestamp - this.timestamp = timestamp + this.timestamp= timestamp this.tick(dt) this.draw() @@ -46,13 +53,19 @@ export default class Game { } tick(dt) { - this.actors.forEach(actor => actor.tick(dt)) - Object.values(this.events).forEach(e => e.nextFrame()) + if (this.message) { + this.message?.tick(dt) + } else { + this.actors.forEach(actor => actor.tick(dt)) + Object.values(this.events).forEach(e => e.nextFrame()) + } + this.input.tick() } draw() { const { canvas, ctx } = this this.currentRoom.draw(ctx) this.actors.forEach(actor => actor.draw(ctx)) + this.message?.draw(ctx) } } diff --git a/src/input.js b/src/input.js index 8d4d035..85f50e8 100644 --- a/src/input.js +++ b/src/input.js @@ -12,11 +12,17 @@ export default class Input { 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.inputJustPressed = Object.fromEntries(Object.keys(this.inputsToKeys).map(key => [key, false])) } initialize() { - window.addEventListener("keydown", key => this.inputPressed[this.keyFromInput(key.key)] = true) - window.addEventListener("keyup", key => this.inputPressed[this.keyFromInput(key.key)] = false) + window.addEventListener("keydown", key => { + this.inputJustPressed[this.keyFromInput(key.key)] = true + this.inputPressed[this.keyFromInput(key.key)] = true + }) + window.addEventListener("keyup", key => { + this.inputPressed[this.keyFromInput(key.key)] = false + }) return this } @@ -24,6 +30,14 @@ export default class Input { 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) { return this.keysToInputs[input] } diff --git a/src/message.js b/src/message.js new file mode 100644 index 0000000..ea68330 --- /dev/null +++ b/src/message.js @@ -0,0 +1,47 @@ +export default class Message { + constructor(game, text) { + this.game = game + this.text = text + 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 { + this.textProgress = this.text.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.fillStyle = this.textColor + ctx.fillText(this.text.substring(0, this.textIndex), 5, 5) + if (this.messageComplete()) { + ctx.fillRect( + ctx.canvas.width - 20, + this.backgroundHeight - 20, + 10, 10 + ) + } + } + + messageComplete() { + return this.textIndex >= this.text.length + 3 + } +}