in libs/game/sprite.ts [308:437]
say(text: string, timeOnScreen?: number, textColor = 1, textBoxColor = 0) {
if (!text) {
this.updateSay = undefined;
if (this.sayBubbleSprite) {
this.sayBubbleSprite.destroy();
}
return;
}
let pixelsOffset = 0;
let holdTextSeconds = 1.5;
let bubblePadding = 4;
let maxTextWidth = 100;
let font = image.font8;
let startX = 2;
let startY = 2;
let bubbleWidth = text.length * font.charWidth + bubblePadding;
let maxOffset = text.length * font.charWidth - maxTextWidth;
let bubbleOffset: number;
// sets the defaut scroll speed in pixels per second
let speed = 45;
// Calculates the speed of the scroll if scrolling is needed and a time is specified
if (timeOnScreen && maxOffset > 0) {
speed = (maxOffset + (2 * maxTextWidth)) / (timeOnScreen / 1000);
speed = Math.max(speed, 45);
holdTextSeconds = maxTextWidth / speed;
holdTextSeconds = Math.min(holdTextSeconds, 1.5);
}
if (timeOnScreen) {
timeOnScreen = timeOnScreen + control.millis();
}
if (!this._hitboxes || this._hitboxes.length == 0) {
bubbleOffset = 0;
} else {
bubbleOffset = this._hitboxes[0].top;
for (let i = 0; i < this._hitboxes.length; i++) {
bubbleOffset = Math.min(bubbleOffset, this._hitboxes[i].top);
}
// Gets the length from sprites location to its highest hitbox
bubbleOffset = this.y - bubbleOffset;
}
if (bubbleWidth > maxTextWidth + bubblePadding) {
bubbleWidth = maxTextWidth + bubblePadding;
} else {
maxOffset = -1;
}
// Destroy previous sayBubbleSprite to prevent leaking
if (this.sayBubbleSprite) {
this.sayBubbleSprite.destroy();
}
this.sayBubbleSprite = sprites.create(image.create(bubbleWidth, font.charHeight + bubblePadding), -1);
this.sayBubbleSprite.setFlag(SpriteFlag.Ghost, true);
this.updateSay = (dt, camera) => {
// Update box stuff as long as timeOnScreen doesn't exist or it can still be on the screen
if (!timeOnScreen || timeOnScreen > control.millis()) {
this.sayBubbleSprite.image.fill(textBoxColor);
// The minus 2 is how much transparent padding there is under the sayBubbleSprite
this.sayBubbleSprite.y = this.y - bubbleOffset - ((font.charHeight + bubblePadding) >> 1) - 2;
this.sayBubbleSprite.x = this.x;
if (!this.isOutOfScreen(camera)) {
const ox = camera.offsetX;
const oy = camera.offsetY;
if (this.sayBubbleSprite.left - ox < 0) {
this.sayBubbleSprite.left = 0;
}
if (this.sayBubbleSprite.right - ox > screen.width) {
this.sayBubbleSprite.right = screen.width;
}
// If sprite bubble above the sprite gets cut off on top, place the bubble below the sprite
if (this.sayBubbleSprite.top - oy < 0) {
this.sayBubbleSprite.y = (this.sayBubbleSprite.y - 2 * this.y) * -1;
}
}
// Pauses at beginning of text for holdTextSeconds length
if (holdTextSeconds > 0) {
holdTextSeconds -= game.eventContext().deltaTime;
// If scrolling has reached the end, start back at the beginning
if (holdTextSeconds <= 0 && pixelsOffset > 0) {
pixelsOffset = 0;
holdTextSeconds = maxTextWidth / speed;
}
} else {
pixelsOffset += dt * speed;
// Pause at end of text for holdTextSeconds length
if (pixelsOffset >= maxOffset) {
pixelsOffset = maxOffset;
holdTextSeconds = maxTextWidth / speed;
}
}
// If maxOffset is negative it won't scroll
if (maxOffset < 0) {
this.sayBubbleSprite.image.print(text, startX, startY, textColor, font);
} else {
this.sayBubbleSprite.image.print(text, startX - pixelsOffset, startY, textColor, font);
}
// Left side padding
this.sayBubbleSprite.image.fillRect(0, 0, bubblePadding >> 1, font.charHeight + bubblePadding, textBoxColor);
// Right side padding
this.sayBubbleSprite.image.fillRect(bubbleWidth - (bubblePadding >> 1), 0, bubblePadding >> 1, font.charHeight + bubblePadding, textBoxColor);
// Corners removed
this.sayBubbleSprite.image.setPixel(0, 0, 0);
this.sayBubbleSprite.image.setPixel(bubbleWidth - 1, 0, 0);
this.sayBubbleSprite.image.setPixel(0, font.charHeight + bubblePadding - 1, 0);
this.sayBubbleSprite.image.setPixel(bubbleWidth - 1, font.charHeight + bubblePadding - 1, 0);
} else {
// If can't update because of timeOnScreen then destroy the sayBubbleSprite and reset updateSay
this.sayBubbleSprite.destroy();
this.updateSay = undefined;
}
}
}