import { StateMachine } from "./playerstatemachine.js"; import { Idle } from "./states/idle.js"; 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.state = "ground"; this._lastTx = x; this._lastTy = this.y; this._lastUpdateTime = 0; this.statemachine = new StateMachine(this); this.statemachine.set(Idle) 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(dt) { let prevX = this.x; this._prevY = this.y; this.vx = 0; this.statemachine.update(dt) if (this.keys.a) { this.vx = -this.speed; this.facing = -1; } this.speed = this.crouching ? 0.5 : 2; 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") { if (this.id === 'codegirl007') { console.log(this.x, prevX) } 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; } } this.state = this.onGround ? 'ground' : 'air'; } 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 = 600; // milliseconds this.message = message; } jump() { if (this.onGround) { this.vy = this.jumpStrength; this.onGround = false; this.state = 'air'; } } 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; } }