add username balloons under agents
This commit is contained in:
parent
55ce8b67f5
commit
e9504c6359
3 changed files with 41 additions and 10 deletions
|
@ -51,16 +51,25 @@ class AgentAnimationState {
|
|||
}
|
||||
}
|
||||
|
||||
enum AgentWordBalloonPosition {
|
||||
AboveCentered,
|
||||
BelowCentered
|
||||
}
|
||||
|
||||
class AgentWordBalloonState {
|
||||
char: Agent;
|
||||
text: string;
|
||||
hasTip: boolean;
|
||||
position: AgentWordBalloonPosition;
|
||||
|
||||
balloonCanvas: HTMLCanvasElement;
|
||||
balloonCanvasCtx: CanvasRenderingContext2D;
|
||||
|
||||
constructor(char: Agent, text: string) {
|
||||
constructor(char: Agent, text: string, hasTip: boolean, position: AgentWordBalloonPosition) {
|
||||
this.char = char;
|
||||
this.text = text;
|
||||
this.hasTip = hasTip;
|
||||
this.position = position;
|
||||
this.balloonCanvas = document.createElement('canvas');
|
||||
this.balloonCanvasCtx = this.balloonCanvas.getContext('2d')!;
|
||||
|
||||
|
@ -74,13 +83,13 @@ class AgentWordBalloonState {
|
|||
// hack fix for above
|
||||
this.balloonCanvas.style.pointerEvents = 'none';
|
||||
|
||||
let rect = wordballoonDrawText(this.balloonCanvasCtx, { x: 0, y: 0 }, this.text, 20);
|
||||
let rect = wordballoonDrawText(this.balloonCanvasCtx, { x: 0, y: 0 }, this.text, 20, hasTip);
|
||||
|
||||
// Second pass, actually set the element to the right width and stuffs
|
||||
this.balloonCanvas.width = rect.w;
|
||||
this.balloonCanvas.height = rect.h;
|
||||
|
||||
wordballoonDrawText(this.balloonCanvasCtx, { x: 0, y: 0 }, this.text, 20);
|
||||
wordballoonDrawText(this.balloonCanvasCtx, { x: 0, y: 0 }, this.text, 20, hasTip);
|
||||
|
||||
this.char.getElement().appendChild(this.balloonCanvas);
|
||||
|
||||
|
@ -101,9 +110,17 @@ class AgentWordBalloonState {
|
|||
|
||||
positionUpdated() {
|
||||
let size = this.char.getSize();
|
||||
|
||||
this.balloonCanvas.style.top = -(this.balloonCanvas.height) + 'px';
|
||||
this.balloonCanvas.style.left = -((this.balloonCanvas.width / 2) - (size.w / 2)) + 'px';
|
||||
switch (this.position) {
|
||||
case AgentWordBalloonPosition.AboveCentered: {
|
||||
this.balloonCanvas.style.top = -(this.balloonCanvas.height) + 'px';
|
||||
break;
|
||||
}
|
||||
case AgentWordBalloonPosition.BelowCentered: {
|
||||
this.balloonCanvas.style.bottom = -(this.balloonCanvas.height) + 'px';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,6 +136,7 @@ export class Agent {
|
|||
|
||||
private animState: AgentAnimationState | null = null;
|
||||
private wordballoonState: AgentWordBalloonState | null = null;
|
||||
private usernameBalloonState: AgentWordBalloonState | null = null;
|
||||
|
||||
constructor(data: AcsData) {
|
||||
this.data = data;
|
||||
|
@ -262,12 +280,22 @@ export class Agent {
|
|||
if (index !== -1) this.playAnimation(index, finishCallback);
|
||||
}
|
||||
|
||||
setUsername(username: string) {
|
||||
if (this.usernameBalloonState !== null) {
|
||||
this.usernameBalloonState.finish();
|
||||
this.usernameBalloonState = null;
|
||||
}
|
||||
|
||||
this.usernameBalloonState = new AgentWordBalloonState(this, username, false, AgentWordBalloonPosition.BelowCentered);
|
||||
this.usernameBalloonState.show();
|
||||
}
|
||||
|
||||
speak(text: string) {
|
||||
if (this.wordballoonState != null) {
|
||||
this.stopSpeaking();
|
||||
}
|
||||
|
||||
this.wordballoonState = new AgentWordBalloonState(this, text);
|
||||
this.wordballoonState = new AgentWordBalloonState(this, text, true, AgentWordBalloonPosition.AboveCentered);
|
||||
this.wordballoonState.positionUpdated();
|
||||
this.wordballoonState.show();
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ export async function wordballoonInit() {
|
|||
}
|
||||
|
||||
// This function returns a rect which is the usable inner contents of the box.
|
||||
export function wordballoonDraw(ctx: CanvasRenderingContext2D, at: Point, size: Size): Rect {
|
||||
export function wordballoonDraw(ctx: CanvasRenderingContext2D, at: Point, size: Size, hasTip: boolean = true): Rect {
|
||||
// Snap the size to a clean 12x12 system,
|
||||
// so we stay (as close to) pixel perfect as possible.
|
||||
// This is "lazy" but oh well. It works!
|
||||
|
@ -93,6 +93,7 @@ export function wordballoonDraw(ctx: CanvasRenderingContext2D, at: Point, size:
|
|||
// For now, we always simply use the center of the bottom..
|
||||
|
||||
// Draw the tip.
|
||||
if (hasTip)
|
||||
spriteDraw(ctx, tip_sprite, at.x + size.w / 2, at.y + 12 * (j + 1) - 1);
|
||||
|
||||
ctx.restore();
|
||||
|
@ -128,7 +129,7 @@ function wordWrapToStringList(text: string, maxLength: number) {
|
|||
}
|
||||
|
||||
// This draws a wordballoon with text. This function respects the current context's font settings and does *not* modify them.
|
||||
export function wordballoonDrawText(ctx: CanvasRenderingContext2D, at: Point, text: string, maxLen: number = 20): Rect {
|
||||
export function wordballoonDrawText(ctx: CanvasRenderingContext2D, at: Point, text: string, maxLen: number = 20, hasTip: boolean = true): Rect {
|
||||
let lines = wordWrapToStringList(text, maxLen);
|
||||
|
||||
// Create metrics for each line
|
||||
|
@ -158,7 +159,7 @@ export function wordballoonDrawText(ctx: CanvasRenderingContext2D, at: Point, te
|
|||
size.h = Math.floor(size.h);
|
||||
|
||||
// Draw the word balloon and get the inner rect
|
||||
let rectInner = wordballoonDraw(ctx, at, size);
|
||||
let rectInner = wordballoonDraw(ctx, at, size, hasTip);
|
||||
|
||||
// Draw all the lines of text
|
||||
let y = 0;
|
||||
|
|
|
@ -142,6 +142,7 @@ export class MSAgentClient {
|
|||
this.charlimit = initMsg.data.charlimit;
|
||||
for (let _user of initMsg.data.users) {
|
||||
let agent = await agentCreateCharacterFromUrl(this.url + '/api/agents/' + _user.agent);
|
||||
agent.setUsername(_user.username);
|
||||
agent.addToDom(this.agentContainer);
|
||||
agent.show();
|
||||
let user = new User(_user.username, agent);
|
||||
|
@ -153,6 +154,7 @@ export class MSAgentClient {
|
|||
case MSAgentProtocolMessageType.AddUser: {
|
||||
let addUserMsg = msg as MSAgentAddUserMessage;
|
||||
let agent = await agentCreateCharacterFromUrl(this.url + '/api/agents/' + addUserMsg.data.agent);
|
||||
agent.setUsername(addUserMsg.data.username);
|
||||
agent.addToDom(this.agentContainer);
|
||||
agent.show();
|
||||
let user = new User(addUserMsg.data.username, agent);
|
||||
|
|
Loading…
Reference in a new issue