85 lines
2.6 KiB
TypeScript
85 lines
2.6 KiB
TypeScript
const {GRAVITY} = require('./constants.js');
|
|
const {SpriteSheet} = require('./sprite-sheet');
|
|
|
|
export type NPCOptions = {
|
|
bubbleOffset?: [number, number];
|
|
noBounds?: boolean;
|
|
noGravity?: boolean;
|
|
scale?: number;
|
|
}
|
|
|
|
export class NPC {
|
|
private readonly emojis = [
|
|
0x1F600, 0x1F601, 0x1F603, 0x1F603, 0x1F604, 0x1F605, 0x1F606,
|
|
0x1F607, 0x1F609, 0x1F60A, 0x1F642, 0x1F643, 0x1F355, 0x1F354,
|
|
];
|
|
private readonly texturePack: any;
|
|
|
|
private random: number = 0;
|
|
private sprite!: any;
|
|
private text: string;
|
|
|
|
public pos = [0, 0];
|
|
public vel = [0, 0];
|
|
|
|
constructor(private readonly ctx: CanvasRenderingContext2D,
|
|
public readonly spriteSheetPath: string,
|
|
public readonly spriteDefPath: string,
|
|
public readonly options: NPCOptions = {},
|
|
) {
|
|
this.texturePack = new SpriteSheet(this.ctx,
|
|
'./assets/sprites/texture-pack/spritesheet.png',
|
|
'../assets/sprites/texture-pack/spritesheet.json');
|
|
|
|
if(this.options.bubbleOffset == null) this.options.bubbleOffset = [0, 0];
|
|
if(this.options.scale == null) this.options.scale = 1;
|
|
this.sprite = new SpriteSheet(ctx, spriteSheetPath, spriteDefPath);
|
|
|
|
setInterval(() => {
|
|
this.message(String.fromCodePoint(this.emojis[~~(Math.random() * this.emojis.length)]));
|
|
}, 10000);
|
|
}
|
|
|
|
animate(name: string, reverse = false) {
|
|
if(this.text) {
|
|
const bubble = this.texturePack.definitions.sprites['bubble'];
|
|
const x = this.pos[0] + this.options.bubbleOffset[0] * (reverse ? -1 : 1);
|
|
const y = this.pos[1] + this.options.bubbleOffset[1];
|
|
this.texturePack.drawSprite(x, y, 'bubble', reverse);
|
|
this.ctx.save();
|
|
this.ctx.textAlign = 'center';
|
|
this.ctx.textBaseline = 'middle';
|
|
this.ctx.font = '24px serif';
|
|
this.ctx.fillText(this.text, x + (bubble.width / 2 * (reverse ? -1 : 1)), y + (bubble.height / 2));
|
|
this.ctx.restore();
|
|
}
|
|
this.sprite.animate(this.pos[0], this.pos[1], name, reverse, this.options.scale);
|
|
}
|
|
|
|
tick() {
|
|
if(this.random <= 0) {
|
|
const move = Math.random();
|
|
if(move < 0.333) this.vel = [0, 0];
|
|
else if(move < 0.666) this.vel = [-10, 0];
|
|
else this.vel = [10, 0];
|
|
this.random = Math.random() * 50;
|
|
}
|
|
this.random--;
|
|
|
|
this.pos = [this.pos[0] + this.vel[0], this.pos[1] + this.vel[1]];
|
|
if(!this.options.noGravity) this.vel[1] -= GRAVITY;
|
|
if(this.pos[1] < 0) this.pos[1] = 0;
|
|
if(!this.options.noBounds) {
|
|
if(this.pos[0] < 0) this.pos[0] = 0;
|
|
if(this.pos[0] > this.ctx.canvas.width) this.pos[0] = this.ctx.canvas.width;
|
|
}
|
|
|
|
this.animate(this.vel[0] == 0 ? 'idle' : 'walk', this.vel[0] < 0);
|
|
}
|
|
|
|
message(text: string, ms = 5000) {
|
|
setTimeout(() => this.text = null, ms);
|
|
this.text = text;
|
|
}
|
|
}
|