import { move_body } from "$/common/physics.ts"; import type { ClientLevel } from "../level/client_level.ts"; // anything that exists in the level and moves, like minecraft's Entity. position is the middle of its feet. // it's simulated in fixed ticks (common/constants.ts), frames draw it between its last two positions export abstract class Entity { id: string; level: ClientLevel; x = 0; y = 0; z = 0; // where it was at the start of the tick, what frames interpolate from prev_x = 0; prev_y = 0; prev_z = 0; // blocks per second vx = 0; vy = 0; vz = 0; yaw = 0; pitch = 0; // the collision box, width is used for both x and z width: number; height: number; eye_height: number; // blocks per second squared gravity = -32; // what's left of its speed after each tick in the air, like minecraft's 0.98. it caps falling speed // at 49 * -gravity * TICK_DELTA, 78 blocks per second with minecraft's gravity drag = 0.98; // which way it hit something on each axis in the last move: 1 or -1, 0 for nothing. // 1 on y means it's standing on something colliding_x = 0; colliding_y = 0; colliding_z = 0; constructor(level: ClientLevel, id: string, width: number, height: number, eye_height: number) { this.level = level; this.id = id; this.width = width; this.height = height; this.eye_height = eye_height; } get on_ground() { return this.colliding_y === 1; } // jumps there, without interpolating from where it was set_position(x: number, y: number, z: number) { this.x = this.prev_x = x; this.y = this.prev_y = y; this.z = this.prev_z = z; } save_previous_position() { this.prev_x = this.x; this.prev_y = this.y; this.prev_z = this.z; } // where to draw it, partial_tick is how far the frame is between the last tick and the next render_position(partial_tick: number) { return { x: this.prev_x + (this.x - this.prev_x) * partial_tick, y: this.prev_y + (this.y - this.prev_y) * partial_tick, z: this.prev_z + (this.z - this.prev_z) * partial_tick, }; } // one step of the game, TICK_DELTA seconds abstract tick(): void; // falls and moves by its velocity for one tick (see move_body), then slows down from drag move() { const collisions = move_body(this, this.gravity, (x, y, z) => this.level.has_collision(x, y, z)); this.colliding_x = collisions.x; this.colliding_y = collisions.y; this.colliding_z = collisions.z; this.vx *= this.drag; this.vy *= this.drag; this.vz *= this.drag; } }