Change how ticking works
This commit is contained in:
+46
-14
@@ -15,9 +15,13 @@ import { InputManager } from "./input_manager.ts";
|
||||
import { Connection } from "./network.ts";
|
||||
import { canvas, resize_canvas } from "./renderer/mod.ts";
|
||||
import { show_fatal_error } from "./fatal.ts";
|
||||
import { TICK_DELTA } from "$/common/constants.ts";
|
||||
|
||||
// the game client, like minecraft's Minecraft class: owns the level, the player, the screens and the renderer,
|
||||
// and runs one step of the game every frame
|
||||
// after a long stall (a hidden tab, a debugger) the game skips ahead instead of running every missed tick at once
|
||||
const MAX_TICKS_PER_FRAME = 10;
|
||||
|
||||
// the game client, like minecraft's Minecraft class: owns the level, the player, the screens and the renderer.
|
||||
// the game runs in fixed ticks (TICKS_PER_SECOND), input and drawing happen every frame
|
||||
export class Client {
|
||||
connection: Connection;
|
||||
options = new Options();
|
||||
@@ -35,6 +39,12 @@ export class Client {
|
||||
hit_result: BlockHitResult | undefined;
|
||||
debugging = false;
|
||||
|
||||
// seconds of game time not ticked yet
|
||||
#pending_time = 0;
|
||||
// whether the attack button is held on a block, breaking it advances every tick
|
||||
#attacking = false;
|
||||
#stopped = false;
|
||||
|
||||
constructor(connection: Connection) {
|
||||
this.connection = connection;
|
||||
|
||||
@@ -74,24 +84,46 @@ export class Client {
|
||||
this.screens.pop()?.on_close();
|
||||
}
|
||||
|
||||
// one frame: network, input, the level and its entities, then drawing
|
||||
// one frame: input, as many ticks as are due, then drawing between the last tick and the next
|
||||
run_frame(delta: number) {
|
||||
this.screen?.on_tick(delta);
|
||||
this.#handle_keybinds();
|
||||
|
||||
this.#pending_time += delta;
|
||||
let ticks = 0;
|
||||
while (this.#pending_time >= TICK_DELTA && ticks < MAX_TICKS_PER_FRAME) {
|
||||
this.tick();
|
||||
if (this.#stopped) {
|
||||
return;
|
||||
}
|
||||
this.#pending_time -= TICK_DELTA;
|
||||
ticks += 1;
|
||||
}
|
||||
if (ticks === MAX_TICKS_PER_FRAME) {
|
||||
this.#pending_time = Math.min(this.#pending_time, TICK_DELTA);
|
||||
}
|
||||
|
||||
this.game_renderer.render(this, this.#pending_time / TICK_DELTA);
|
||||
}
|
||||
|
||||
// one step of the game: what the server sent, breaking, chunk loading, then every entity
|
||||
tick() {
|
||||
this.packet_listener.handle_packets();
|
||||
if (this.connection.closed) {
|
||||
show_fatal_error("Lost connection to the server");
|
||||
this.#stopped = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this.screen?.on_tick(delta);
|
||||
this.#handle_keybinds(delta);
|
||||
if (this.#attacking && this.hit_result) {
|
||||
this.game_mode.continue_destroy_block(this.hit_result);
|
||||
}
|
||||
|
||||
this.level.update_loaded_chunks(this.player.x, this.player.z, this.options.render_distance);
|
||||
this.level.tick(delta);
|
||||
|
||||
this.game_renderer.render(this);
|
||||
this.level.tick();
|
||||
}
|
||||
|
||||
#handle_keybinds(delta: number) {
|
||||
#handle_keybinds() {
|
||||
const options = this.options;
|
||||
const player = this.player;
|
||||
|
||||
@@ -122,16 +154,18 @@ export class Client {
|
||||
InputManager.set_mouse_grabbed(!this.screen);
|
||||
|
||||
this.hit_result = this.level.pick(player.x, player.y + player.eye_height, player.z, player.yaw, player.pitch);
|
||||
this.#handle_block_interaction(delta);
|
||||
this.#handle_block_interaction();
|
||||
|
||||
if (!this.screen) {
|
||||
this.#handle_hotbar();
|
||||
}
|
||||
}
|
||||
|
||||
#handle_block_interaction(delta: number) {
|
||||
// clicks happen right away, holding to break advances in tick()
|
||||
#handle_block_interaction() {
|
||||
const hit = this.hit_result;
|
||||
const attacking = !this.screen && InputManager.is_mouse_down(0);
|
||||
this.#attacking = attacking;
|
||||
|
||||
if (!attacking || !hit) {
|
||||
this.game_mode.stop_destroy_block();
|
||||
@@ -144,9 +178,7 @@ export class Client {
|
||||
if (InputManager.is_mouse_pressed(0)) {
|
||||
this.game_mode.start_destroy_block(hit);
|
||||
}
|
||||
if (attacking) {
|
||||
this.game_mode.continue_destroy_block(hit, delta);
|
||||
} else if (InputManager.is_mouse_pressed(2)) {
|
||||
if (!attacking && InputManager.is_mouse_pressed(2)) {
|
||||
this.game_mode.use_item_on(hit);
|
||||
}
|
||||
} else if (InputManager.is_mouse_pressed(2)) {
|
||||
|
||||
Reference in New Issue
Block a user