You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

193 lines
4.7 KiB

export class StickFigure {
constructor(x, facing, id, canvas) {
this.canvas = canvas;
this.id = id;
this.x = x;
this.y = canvas.height - 60;
this.facing = facing;
this._lastTx = x;
this._lastTy = this.y;
this._lastUpdateTime = 0;
this._walkTTL = 0;
this.action = "idle";
this.hitFrame = 0;
this.speed = 2;
this.vx = 0;
this.vy = 0;
this.gravity = 0.5;
this.jumpStrength = -10;
this.onGround = true;
this.talking = false;
this.talkTimer = 0;
this.message = "";
this.keys = {
a: false,
d: false,
}
this.crouching = false;
this.isPunching = false;
this.punchHasHit = false;
this.sentJoin = false;
this.hp = 100;
this.maxHp = 100;
this.isAlive = true;
this._tx = x;
this._ty = canvas.height - 60;
this._lastTs = 0;
this._tFacing = undefined;
this._lastUpdateTime = Date.now();
this._updateInterval = 10;
this.baseAttackPower = 14;
this.baseDefense = 14;
}
update() {
const prevX = this.x;
this._prevY = this.y;
this.vx = 0;
if (this.keys.a) {
this.vx = -this.speed;
this.facing = -1;
}
if (this.crouching && this.keys.d) {
this.speed = 0.5;
this.vx = this.speed;
}
if (this.crouching && this.keys.a) {
this.vx = -this.speed;
}
if (this.keys.d) {
this.vx = this.speed;
this.facing = 1;
}
this.x += this.vx;
if (this.isLocal) {
this.vy += this.gravity;
this.y += this.vy;
}
this.x = Math.max(20, Math.min(this.canvas.width - 20, this.x));
if (this.action === "punch") {
this.hitFrame++;
if (this.hitFrame > 15) {
this.action = 'idle';
this.hitFrame = 0;
this.isPunching = false;
this.punchHasHit = false;
}
}
if (this.talking) {
this.talkTimer--;
if (this.talkTimer <= 0) {
this.talking = false;
}
}
if (!this.isLocal
&& typeof this._tx === "number"
&& typeof this._ty === "number") {
const now = Date.now();
const timeSinceUpdate = now - this._lastUpdateTime;
const targetLerpTime = 200;
const deltaTime = 16.67;
const lerpFactor = Math.min(1, deltaTime / targetLerpTime);
const stalenessFactor = Math.min(2, timeSinceUpdate / this._updateInterval);
const adjustedLerpFactor = lerpFactor * stalenessFactor;
const deltaY = Math.abs(this.y - this._ty);
if (deltaY > 8 || !this.onGround) {
this.x = this._tx;
this.y = this._ty;
} else {
this.x = this.lerp(this.x, this._tx, adjustedLerpFactor);
this.y = this.lerp(this.y, this._ty, adjustedLerpFactor);
}
this.facing = this._tFacing ?? this.facing;
this.vx = this.x - prevX;
if (Math.abs(this.vx) < 0.5) {
this.vx = 0;
}
}
}
lerp(a, b, t) {
return a + (b - a) * Math.min(1, t);
}
applyBuff(type, amount) {
if (type === 'atk') {
this.baseAttackPower += amount;
}
if (type === 'def') {
this.baseDefense += amount;
}
}
punch() {
this.isPunching = true;
this.punchHasHit = false;
if (this.action === 'idle') {
this.action = 'punch';
this.hitFrame = 0;
}
}
talk(message) {
this.talking = true;
this.talkTimer = 120;
this.message = message;
}
jump() {
if (this.onGround) {
this.vy = this.jumpStrength;
this.onGround = false;
}
}
getBodyHitbox() {
const w = 24;
const h = 60 - (this.crouching ? 10 : 0);
return {
x: this.x - w / 2,
y: this.y - 10,
w,
h
};
}
getPunchHitbox() {
if (this.action === 'punch' && this.hitFrame < 10) {
const w = 18;
const h = 14;
const frontX = this.x + this.facing * 22;
const x = this.facing === 1 ? frontX : frontX - w;
const y = this.y + (this.crouching ? 18 : 10);
return {
x,
y,
w,
h
};
}
return null;
}
}