Files
bworld/client/entity/entity.ts
T
2026-09-25 16:26:45 -03:00

82 lines
2.2 KiB
TypeScript

import { AIR } from "$/common/constants.ts";
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;
gravity = -15.8;
// 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
move() {
const collisions = move_body(this, this.gravity, (x, y, z) => this.level.get_block(x, y, z) !== AIR);
this.colliding_x = collisions.x;
this.colliding_y = collisions.y;
this.colliding_z = collisions.z;
}
}