mirror of
https://git.leinelab.org/Mal/mr-crocs-adventures.git
synced 2025-09-11 02:57:36 +02:00
UserInterface with TextMessages implemented.
This commit is contained in:
9
js/ui/TextAlignment.js
Normal file
9
js/ui/TextAlignment.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const TextAlignment = {
|
||||
LEFT: 0,
|
||||
CENTER: 1,
|
||||
RIGHT: 2,
|
||||
TOP: 3,
|
||||
BOTTOM: 4,
|
||||
};
|
||||
|
||||
export default TextAlignment;
|
||||
118
js/ui/TextBox.js
Normal file
118
js/ui/TextBox.js
Normal file
@@ -0,0 +1,118 @@
|
||||
import TextLine from "./TextLine.js";
|
||||
import TextAlignment from "./TextAlignment.js";
|
||||
import UserInterfaceElement from "./UserInterfaceElement.js";
|
||||
|
||||
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 = true;
|
||||
this.hasBorder = true;
|
||||
this.font = 'Silkscreen';
|
||||
this.textSize = 48;
|
||||
this.alignment = TextAlignment.CENTER;
|
||||
this.verticalAlignment = TextAlignment.BOTTOM;
|
||||
this.lines = [];
|
||||
|
||||
this.updateLines(width, context);
|
||||
}
|
||||
|
||||
updateLines(width, context)
|
||||
{
|
||||
context.font = this.textSize + 'px ' + this.font;
|
||||
this.lines = this.getLinesForWidth(this.text, context, width)
|
||||
}
|
||||
|
||||
animate(msForChar = 100, timeoutMilliseconds = 0)
|
||||
{
|
||||
let milliseconds = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
}, timeoutMilliseconds
|
||||
);
|
||||
}
|
||||
|
||||
draw(context, x = null, y = null)
|
||||
{
|
||||
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--) {
|
||||
if (this.lines[l].chars > 0) {
|
||||
this.lines[l].draw(context, x, currentHeight);
|
||||
currentHeight -= this.textSize;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.lines.forEach(
|
||||
(line, index) => {
|
||||
line.draw(context, x, y + this.textSize * index);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
getLinesForWidth(text, context, width)
|
||||
{
|
||||
let words = text.split(' ');
|
||||
let lines = [];
|
||||
let buffer = words[0];
|
||||
|
||||
for (let w = 1; w < words.length; w++) {
|
||||
let bufferNew = buffer === '' ? words[w] : buffer + ' ' + words[w];
|
||||
|
||||
if (context.measureText(bufferNew).width > width) {
|
||||
lines.push(this.getLine(buffer));
|
||||
bufferNew = words[w];
|
||||
}
|
||||
|
||||
buffer = bufferNew;
|
||||
}
|
||||
|
||||
if (buffer !== '') {
|
||||
lines.push(this.getLine(buffer));
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
getLine(text)
|
||||
{
|
||||
let line = new TextLine(text);
|
||||
|
||||
line.font = this.font;
|
||||
line.size = this.textSize;
|
||||
line.colorText = this.colorText;
|
||||
line.colorShadow = this.colorShadow;
|
||||
line.alignment = this.alignment;
|
||||
line.hasShadow = this.hasShadow;
|
||||
line.hasBorder = this.hasBorder;
|
||||
line.colorBorder = this.colorBorder;
|
||||
|
||||
return line;
|
||||
}
|
||||
}
|
||||
86
js/ui/TextLine.js
Normal file
86
js/ui/TextLine.js
Normal file
@@ -0,0 +1,86 @@
|
||||
import TextAlignment from "./TextAlignment.js";
|
||||
|
||||
export default class TextLine
|
||||
{
|
||||
constructor(text)
|
||||
{
|
||||
this.text = text;
|
||||
this.estimatedTextWidth = null;
|
||||
this.colorText = 'red';
|
||||
this.colorShadow = 'black';
|
||||
this.colorBorder = 'black';
|
||||
this.font = 'sans-serif';
|
||||
this.alphaText = 1.0;
|
||||
this.size = 32;
|
||||
this.alignment = TextAlignment.LEFT;
|
||||
this.chars = this.text.length;
|
||||
this.hasShadow = false;
|
||||
this.hasBorder = false;
|
||||
}
|
||||
|
||||
animate(msPerChar = 100)
|
||||
{
|
||||
this.chars = 0;
|
||||
|
||||
let process = setInterval(
|
||||
() => {
|
||||
this.chars++;
|
||||
|
||||
if (this.chars === this.text.length) {
|
||||
clearInterval(process);
|
||||
}
|
||||
}, msPerChar
|
||||
);
|
||||
}
|
||||
|
||||
draw(context, x, y)
|
||||
{
|
||||
context.font = this.size + 'px ' + this.font;
|
||||
context.globalAlpha = this.alphaText;
|
||||
|
||||
if (this.estimatedTextWidth === null) {
|
||||
this.estimatedTextWidth = Math.ceil(context.measureText(this.text).width);
|
||||
}
|
||||
|
||||
switch (this.alignment) {
|
||||
case TextAlignment.LEFT:
|
||||
break;
|
||||
case TextAlignment.CENTER:
|
||||
x -= this.estimatedTextWidth * 0.5;
|
||||
break;
|
||||
case TextAlignment.RIGHT:
|
||||
x -= this.estimatedTextWidth;
|
||||
break;
|
||||
}
|
||||
|
||||
this.drawShadow(context, x, y);
|
||||
|
||||
let text = this.text;
|
||||
|
||||
if (this.chars !== null && this.chars < this.text.length) {
|
||||
text = this.text.substr(0, this.chars);
|
||||
}
|
||||
|
||||
context.fillStyle = this.colorText;
|
||||
context.fillText(text, x, y + this.size);
|
||||
|
||||
this.drawBorder(context, x, y, text);
|
||||
}
|
||||
|
||||
drawBorder(context, x, y, text)
|
||||
{
|
||||
if (this.hasBorder) {
|
||||
context.strokeStyle = this.colorBorder;
|
||||
context.strokeWidth = '1px';
|
||||
context.strokeText(text, x, y + this.size);
|
||||
}
|
||||
}
|
||||
|
||||
drawShadow(context, x, y)
|
||||
{
|
||||
if (this.hasShadow) {
|
||||
context.fillStyle = this.colorShadow;
|
||||
context.fillText(this.text.substr(0, this.chars), x + 2, y + this.size + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
24
js/ui/TextMessage.js
Normal file
24
js/ui/TextMessage.js
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
10
js/ui/TextMessageGisela.js
Normal file
10
js/ui/TextMessageGisela.js
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
10
js/ui/TextMessageMrCroc.js
Normal file
10
js/ui/TextMessageMrCroc.js
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
25
js/ui/UserInterface.js
Normal file
25
js/ui/UserInterface.js
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
38
js/ui/UserInterfaceElement.js
Normal file
38
js/ui/UserInterfaceElement.js
Normal file
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user