From 479a150f9d4d04f5ef3ea4dadd7a20f73bdcd82f Mon Sep 17 00:00:00 2001 From: Mal Date: Mon, 24 Feb 2020 21:09:21 +0100 Subject: [PATCH] UserInterface with TextMessages implemented. --- js/module.js | 31 +++++++++++----------- js/ui/TextAlignment.js | 9 +++++++ js/{ => ui}/TextBox.js | 48 ++++++++++++++++++++++------------- js/{ => ui}/TextLine.js | 13 +++++----- js/ui/TextMessage.js | 24 ++++++++++++++++++ js/ui/TextMessageGisela.js | 10 ++++++++ js/ui/TextMessageMrCroc.js | 10 ++++++++ js/ui/UserInterface.js | 25 ++++++++++++++++++ js/ui/UserInterfaceElement.js | 38 +++++++++++++++++++++++++++ 9 files changed, 167 insertions(+), 41 deletions(-) create mode 100644 js/ui/TextAlignment.js rename js/{ => ui}/TextBox.js (65%) rename js/{ => ui}/TextLine.js (90%) create mode 100644 js/ui/TextMessage.js create mode 100644 js/ui/TextMessageGisela.js create mode 100644 js/ui/TextMessageMrCroc.js create mode 100644 js/ui/UserInterface.js create mode 100644 js/ui/UserInterfaceElement.js diff --git a/js/module.js b/js/module.js index 2c98144..3155ef1 100644 --- a/js/module.js +++ b/js/module.js @@ -12,7 +12,9 @@ import ImageLoader from "./ImageLoader.js"; import Level from "./Level.js"; import InterfaceEvent from "./events/InterfaceEvent.js"; import UrlParam from "./UrlParam.js"; -import TextBox from "./TextBox.js"; +import UserInterface from "./ui/UserInterface.js"; +import TextMessageGisela from "./ui/TextMessageGisela.js"; +import TextMessageMrCroc from "./ui/TextMessageMrCroc.js"; function MainLoop(timestamp) { @@ -105,10 +107,7 @@ function MainLoop(timestamp) architecture.draw(context, camera); mrCroc.draw(context, camera); gisela.draw(context, camera); - - if (gameFinished) { - textBoxGameFinished.draw(context, window.innerWidth * 0.5, window.innerHeight - 100); - } + userInterface.draw(context); lastRendered = timestamp; } @@ -123,7 +122,8 @@ function MainLoop(timestamp) lastTimestamp = undefined; lastRendered = undefined; textBoxGameFinished.updateLines(window.innerWidth - 40, context); - textBoxGameFinished.animate(); + textBoxGameFinished.animate(75); + userInterface.addTextBox(textBoxGameFinished); } window.requestAnimationFrame(MainLoop); @@ -157,7 +157,9 @@ let mrCroc, gisela, architecture; let camera = new Camera(); let gameFinished = false; let hasPlayerLeftArchitecture = false; +let textBoxGameStart; let textBoxGameFinished; +let userInterface = new UserInterface(); let KeyLeft = new Key('ArrowLeft'); let KeyRight = new Key('ArrowRight'); @@ -197,19 +199,16 @@ window.addEventListener( ); context = canvas.getContext('2d'); - textBoxGameFinished = new TextBox( + textBoxGameFinished = new TextMessageGisela( 'Gisela: "Thanks for showing up, Mr. Croc, but I\'m not in danger."', - window.innerWidth - 40, context ); - textBoxGameFinished.font = 'Silkscreen'; - textBoxGameFinished.verticalAlignment = 'bottom'; - textBoxGameFinished.alignment = 1; - textBoxGameFinished.hasShadow = true; - textBoxGameFinished.textSize = 48; - textBoxGameFinished.hasBorder = true; - textBoxGameFinished.colorText = 'yellow'; - textBoxGameFinished.colorBorder = 'black'; + + textBoxGameStart = new TextMessageMrCroc('Mr. Croc: "Where is Gisela? I have to find her!"', context); + textBoxGameStart.animate(75, 1000); + textBoxGameStart.show(1000); + textBoxGameStart.hide(10000); + userInterface.addTextBox(textBoxGameStart); architecture = RetroArchitecture.createFromData(level); camera.borderRight = architecture.columns * architecture.tileWidth; diff --git a/js/ui/TextAlignment.js b/js/ui/TextAlignment.js new file mode 100644 index 0000000..c8a525f --- /dev/null +++ b/js/ui/TextAlignment.js @@ -0,0 +1,9 @@ +const TextAlignment = { + LEFT: 0, + CENTER: 1, + RIGHT: 2, + TOP: 3, + BOTTOM: 4, +}; + +export default TextAlignment; \ No newline at end of file diff --git a/js/TextBox.js b/js/ui/TextBox.js similarity index 65% rename from js/TextBox.js rename to js/ui/TextBox.js index 1eedfe3..f1165bd 100644 --- a/js/TextBox.js +++ b/js/ui/TextBox.js @@ -1,20 +1,23 @@ import TextLine from "./TextLine.js"; +import TextAlignment from "./TextAlignment.js"; +import UserInterfaceElement from "./UserInterfaceElement.js"; -export default class TextBox +export default class TextBox extends UserInterfaceElement { constructor(text, width, context) { + super(); this.text = text; this.width = width; this.colorText = 'red'; this.colorShadow = 'black'; this.colorBorder = 'black'; - this.hasShadow = false; - this.hasBorder = false; + this.hasShadow = true; + this.hasBorder = true; this.font = 'Silkscreen'; - this.textSize = 32; - this.alignment = 0; - this.verticalAlignment = 'top'; + this.textSize = 48; + this.alignment = TextAlignment.CENTER; + this.verticalAlignment = TextAlignment.BOTTOM; this.lines = []; this.updateLines(width, context); @@ -26,25 +29,34 @@ export default class TextBox this.lines = this.getLinesForWidth(this.text, context, width) } - animate(msForChar = 100) + animate(msForChar = 100, timeoutMilliseconds = 0) { let milliseconds = 0; - for (let l = 0; l < this.lines.length; l++) { - this.lines[l].chars = 0; - setTimeout( - () => { - this.lines[l].animate(msForChar); - }, milliseconds - ); + setTimeout( + () => { + for (let l = 0; l < this.lines.length; l++) { + this.lines[l].chars = 0; + setTimeout( + () => { + this.lines[l].animate(msForChar); + }, milliseconds + ); - milliseconds += this.lines[l].text.length * msForChar; - } + milliseconds += this.lines[l].text.length * msForChar; + } + }, timeoutMilliseconds + ); } - draw(context, x, y) + draw(context, x = null, y = null) { - if (this.verticalAlignment === 'bottom') { + if (x === null && y === null) { + x = this.position.x; + y = this.position.y; + } + + if (this.verticalAlignment === TextAlignment.BOTTOM) { let currentHeight = y; for (let l = this.lines.length - 1; l >= 0; l--) { diff --git a/js/TextLine.js b/js/ui/TextLine.js similarity index 90% rename from js/TextLine.js rename to js/ui/TextLine.js index a7e8adb..e261947 100644 --- a/js/TextLine.js +++ b/js/ui/TextLine.js @@ -1,10 +1,9 @@ +import TextAlignment from "./TextAlignment.js"; + export default class TextLine { constructor(text) { - this.LEFT = 0; - this.CENTER = 1; - this.RIGHT = 2; this.text = text; this.estimatedTextWidth = null; this.colorText = 'red'; @@ -13,7 +12,7 @@ export default class TextLine this.font = 'sans-serif'; this.alphaText = 1.0; this.size = 32; - this.alignment = this.LEFT; + this.alignment = TextAlignment.LEFT; this.chars = this.text.length; this.hasShadow = false; this.hasBorder = false; @@ -44,12 +43,12 @@ export default class TextLine } switch (this.alignment) { - case this.LEFT: + case TextAlignment.LEFT: break; - case this.CENTER: + case TextAlignment.CENTER: x -= this.estimatedTextWidth * 0.5; break; - case this.RIGHT: + case TextAlignment.RIGHT: x -= this.estimatedTextWidth; break; } diff --git a/js/ui/TextMessage.js b/js/ui/TextMessage.js new file mode 100644 index 0000000..89092e7 --- /dev/null +++ b/js/ui/TextMessage.js @@ -0,0 +1,24 @@ +import TextBox from "./TextBox.js"; +import GeometryPoint from "../geometry/GeometryPoint.js"; + +export default class TextMessage extends TextBox +{ + constructor(text, context) { + super(text, window.innerWidth - 40, context); + this.update(); + this.context = context; + } + + update() + { + this.defaultWidth = window.innerWidth - 40; + this.defaultPosition = new GeometryPoint(window.innerWidth * 0.5, window.innerHeight - 100); + } + + render() + { + this.update(); + this.setPosition(this.defaultPosition.x, this.defaultPosition.y); + this.updateLines(this.defaultWidth, this.context); + } +} \ No newline at end of file diff --git a/js/ui/TextMessageGisela.js b/js/ui/TextMessageGisela.js new file mode 100644 index 0000000..5eb9fdc --- /dev/null +++ b/js/ui/TextMessageGisela.js @@ -0,0 +1,10 @@ +import TextMessage from "./TextMessage.js"; + +export default class TextMessageGisela extends TextMessage +{ + constructor(text, context) { + super(text, context); + this.colorText = '#ffd400'; + this.render(); + } +} \ No newline at end of file diff --git a/js/ui/TextMessageMrCroc.js b/js/ui/TextMessageMrCroc.js new file mode 100644 index 0000000..196d3f8 --- /dev/null +++ b/js/ui/TextMessageMrCroc.js @@ -0,0 +1,10 @@ +import TextMessage from "./TextMessage.js"; + +export default class TextMessageMrCroc extends TextMessage +{ + constructor(text, context) { + super(text, context); + this.colorText = '#15de00'; + this.render(); + } +} \ No newline at end of file diff --git a/js/ui/UserInterface.js b/js/ui/UserInterface.js new file mode 100644 index 0000000..68b0f97 --- /dev/null +++ b/js/ui/UserInterface.js @@ -0,0 +1,25 @@ +export default class UserInterface +{ + constructor() + { + this.textBoxes = []; + } + + addTextBox(textBox) + { + this.textBoxes.push(textBox); + + return this.textBoxes.length - 1; + } + + draw(context) + { + this.textBoxes.forEach( + (textBox) => { + if (textBox.isVisible) { + textBox.draw(context); + } + } + ) + } +} \ No newline at end of file diff --git a/js/ui/UserInterfaceElement.js b/js/ui/UserInterfaceElement.js new file mode 100644 index 0000000..e823f77 --- /dev/null +++ b/js/ui/UserInterfaceElement.js @@ -0,0 +1,38 @@ +import GeometryPoint from "../geometry/GeometryPoint.js"; + +export default class UserInterfaceElement +{ + constructor() + { + this.position = new GeometryPoint(0, 0); + this.isVisible = true; + } + + setPosition(x, y) + { + this.position.x = x; + this.position.y = y; + } + + hide(timeoutMilliseconds = 0) + { + setTimeout( + () => { + this.isVisible = false + }, timeoutMilliseconds + ); + } + + show(timeoutMilliseconds = 0) + { + if (timeoutMilliseconds > 0) { + this.isVisible = false; + } + + setTimeout( + () => { + this.isVisible = true; + }, timeoutMilliseconds + ); + } +} \ No newline at end of file