88 lines
2.4 KiB
TypeScript
88 lines
2.4 KiB
TypeScript
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;
|
|
}
|
|
}
|