84 lines
2.4 KiB
TypeScript
84 lines
2.4 KiB
TypeScript
import { ItemStack } from "$/common/inventory.ts";
|
|
import type { EntityInfo } from "$/common/protocol.ts";
|
|
import type { ClientLevel } from "../level/client_level.ts";
|
|
import { Entity } from "./entity.ts";
|
|
|
|
// how many ticks a server position takes to reach, like minecraft's lerpTo
|
|
const LERP_TICKS = 3;
|
|
// how many ticks it takes to fly into whoever picked it up
|
|
const PICKUP_TICKS = 3;
|
|
|
|
// an item lying on the ground. the server simulates it, this only moves where it's told and spins
|
|
export class ItemEntity extends Entity {
|
|
item: ItemStack;
|
|
// ticks since it showed up, for spinning and bobbing
|
|
age = 0;
|
|
// so items dropped together don't spin in step
|
|
readonly bob_offset = Math.random() * Math.PI * 2;
|
|
|
|
#target_x: number;
|
|
#target_y: number;
|
|
#target_z: number;
|
|
#lerp_ticks = 0;
|
|
|
|
// who's picking it up, and for how many ticks it has been flying to them
|
|
#picked_up_by: Entity | undefined;
|
|
#pickup_age = 0;
|
|
|
|
constructor(level: ClientLevel, info: EntityInfo) {
|
|
super(level, info.id, 0.25, 0.25, 0.125);
|
|
this.item = ItemStack.from_data(info.item);
|
|
this.set_position(info.x, info.y, info.z);
|
|
this.#target_x = info.x;
|
|
this.#target_y = info.y;
|
|
this.#target_z = info.z;
|
|
}
|
|
|
|
lerp_to(x: number, y: number, z: number) {
|
|
this.#target_x = x;
|
|
this.#target_y = y;
|
|
this.#target_z = z;
|
|
this.#lerp_ticks = LERP_TICKS;
|
|
}
|
|
|
|
// it already went into their inventory on the server, this is only the animation
|
|
pick_up(by: Entity) {
|
|
this.#picked_up_by = by;
|
|
}
|
|
|
|
tick() {
|
|
this.age += 1;
|
|
|
|
if (this.#picked_up_by) {
|
|
this.#pickup_age += 1;
|
|
if (this.#pickup_age >= PICKUP_TICKS) {
|
|
this.level.remove_entity(this.id);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (this.#lerp_ticks > 0) {
|
|
this.x += (this.#target_x - this.x) / this.#lerp_ticks;
|
|
this.y += (this.#target_y - this.y) / this.#lerp_ticks;
|
|
this.z += (this.#target_z - this.z) / this.#lerp_ticks;
|
|
this.#lerp_ticks -= 1;
|
|
}
|
|
}
|
|
|
|
// while being picked up it speeds towards the middle of whoever took it, like minecraft's ItemPickupParticle
|
|
override render_position(partial_tick: number) {
|
|
const position = super.render_position(partial_tick);
|
|
const by = this.#picked_up_by;
|
|
if (!by) {
|
|
return position;
|
|
}
|
|
const target = by.render_position(partial_tick);
|
|
const t = Math.min(1, (this.#pickup_age + partial_tick) / PICKUP_TICKS) ** 2;
|
|
return {
|
|
x: position.x + (target.x - position.x) * t,
|
|
y: position.y + (target.y + 0.5 - position.y) * t,
|
|
z: position.z + (target.z - position.z) * t,
|
|
};
|
|
}
|
|
}
|