better name tags and rounded bubble
This commit is contained in:
parent
a353c0347d
commit
5215b29a0d
@ -1,6 +1,88 @@
|
||||
import { CanvasTexture, LinearFilter, ClampToEdgeWrapping } from 'three';
|
||||
|
||||
/**
|
||||
* Draws a rounded rectangle using the current state of the canvas.
|
||||
* If you omit the last three params, it will draw a rectangle
|
||||
* outline with a 5 pixel border radius
|
||||
*
|
||||
* https://stackoverflow.com/a/3368118
|
||||
*
|
||||
* @param {CanvasRenderingContext2D} ctx
|
||||
* @param {Number} x The top left x coordinate
|
||||
* @param {Number} y The top left y coordinate
|
||||
* @param {Number} width The width of the rectangle
|
||||
* @param {Number} height The height of the rectangle
|
||||
* @param {Number} [radius = 5] The corner radius; It can also be an object
|
||||
* to specify different radii for corners
|
||||
* @param {Number} [radius.tl = 0] Top left
|
||||
* @param {Number} [radius.tr = 0] Top right
|
||||
* @param {Number} [radius.br = 0] Bottom right
|
||||
* @param {Number} [radius.bl = 0] Bottom left
|
||||
* @param {Boolean} [fill = false] Whether to fill the rectangle.
|
||||
* @param {Boolean} [stroke = true] Whether to stroke the rectangle.
|
||||
*/
|
||||
export function roundRect(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number,
|
||||
radius: number | { tl: number; tr: number; br: number; bl: number },
|
||||
fill: boolean,
|
||||
stroke: boolean,
|
||||
) {
|
||||
if (typeof stroke === 'undefined') {
|
||||
stroke = true;
|
||||
}
|
||||
if (typeof radius === 'undefined') {
|
||||
radius = 5;
|
||||
}
|
||||
if (typeof radius === 'number') {
|
||||
radius = { tl: radius, tr: radius, br: radius, bl: radius };
|
||||
} else {
|
||||
var defaultRadius = { tl: 0, tr: 0, br: 0, bl: 0 };
|
||||
for (var side in defaultRadius) {
|
||||
radius[side] = radius[side] || defaultRadius[side];
|
||||
}
|
||||
}
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x + radius.tl, y);
|
||||
ctx.lineTo(x + width - radius.tr, y);
|
||||
ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr);
|
||||
ctx.lineTo(x + width, y + height - radius.br);
|
||||
ctx.quadraticCurveTo(
|
||||
x + width,
|
||||
y + height,
|
||||
x + width - radius.br,
|
||||
y + height,
|
||||
);
|
||||
ctx.lineTo(x + radius.bl, y + height);
|
||||
ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl);
|
||||
ctx.lineTo(x, y + radius.tl);
|
||||
ctx.quadraticCurveTo(x, y, x + radius.tl, y);
|
||||
ctx.closePath();
|
||||
if (fill) {
|
||||
ctx.fill();
|
||||
}
|
||||
if (stroke) {
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
export interface CanvasUtilsOptions {
|
||||
fill?: boolean;
|
||||
backgroundColor?: string;
|
||||
foregroundColor?: string;
|
||||
rounded?: boolean;
|
||||
roundedRadius?: number;
|
||||
textBorderColor?: string;
|
||||
textBorderSize?: number;
|
||||
textShadowBlur?: number;
|
||||
}
|
||||
|
||||
export class CanvasUtils {
|
||||
constructor(private options?: CanvasUtilsOptions) {}
|
||||
|
||||
public createTextCanvas(
|
||||
text: string | string[],
|
||||
bold = true,
|
||||
@ -37,14 +119,47 @@ export class CanvasUtils {
|
||||
ctx.textAlign = 'center';
|
||||
|
||||
// Draw background
|
||||
ctx.fillStyle = '#fff';
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
if (this.options?.fill ?? true) {
|
||||
ctx.fillStyle = this.options?.backgroundColor || '#fff';
|
||||
if (this.options?.rounded) {
|
||||
roundRect(
|
||||
ctx,
|
||||
0,
|
||||
0,
|
||||
width,
|
||||
height,
|
||||
this.options?.roundedRadius || 4,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
} else {
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
// Scale the text to fit within the canvas
|
||||
const scaleFactor = Math.min(1, width / longestLine);
|
||||
ctx.translate(width / 2 - padding, padding + fontSize / 2);
|
||||
ctx.translate(
|
||||
Math.floor(width / 2 - padding) + 0.5,
|
||||
Math.floor(padding + fontSize / 2) + 0.5,
|
||||
);
|
||||
ctx.scale(scaleFactor, 1);
|
||||
ctx.fillStyle = '#000';
|
||||
|
||||
// Draw the text
|
||||
|
||||
if (this.options?.textShadowBlur !== undefined) {
|
||||
ctx.shadowColor = this.options?.textBorderColor || '#000';
|
||||
ctx.shadowBlur = this.options?.textShadowBlur;
|
||||
if (this.options?.textBorderSize !== undefined) {
|
||||
ctx.lineWidth = this.options?.textBorderSize;
|
||||
lines.forEach((line, i) => {
|
||||
ctx.strokeText(line, padding, i * fontSize + padding);
|
||||
});
|
||||
}
|
||||
ctx.shadowBlur = 0;
|
||||
}
|
||||
|
||||
ctx.fillStyle = this.options?.foregroundColor || '#000';
|
||||
lines.forEach((line, i) => {
|
||||
ctx.fillText(line, padding, i * fontSize + padding);
|
||||
});
|
||||
|
@ -8,7 +8,10 @@ import {
|
||||
import { CanvasUtils } from './canvas-utils';
|
||||
import { ChatBubble } from './chat-bubble';
|
||||
|
||||
const chatBuilder = new CanvasUtils();
|
||||
const chatBuilder = new CanvasUtils({
|
||||
rounded: true,
|
||||
roundedRadius: 8,
|
||||
});
|
||||
|
||||
export class PlayerEntity extends PonyEntity {
|
||||
private _updateQueue: PositionUpdatePacket[] = [];
|
||||
|
@ -5,7 +5,13 @@ import { FullStatePacket } from '../../common/types/packet';
|
||||
import { NameTag } from './nametag';
|
||||
import { CanvasUtils } from './canvas-utils';
|
||||
|
||||
const nameTagBuilder = new CanvasUtils();
|
||||
const nameTagBuilder = new CanvasUtils({
|
||||
fill: false,
|
||||
textBorderColor: '#000',
|
||||
foregroundColor: '#fff',
|
||||
textShadowBlur: 2,
|
||||
textBorderSize: 1,
|
||||
});
|
||||
|
||||
export class PonyEntity {
|
||||
public velocity = new THREE.Vector3(0, 0, 0);
|
||||
|
@ -110,6 +110,6 @@ export class Game {
|
||||
);
|
||||
this.io.emit('playerupdate', playerInfo);
|
||||
this._changedPlayers.length = 0;
|
||||
}, 10);
|
||||
}, 1000 / 60);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user