From 3bf42c6ff3805a0d42bbc661794a95ff31bedc26 Mon Sep 17 00:00:00 2001 From: untodesu Date: Sat, 15 Mar 2025 16:22:09 +0500 Subject: Add whatever I was working on for the last month --- game/client/player_move.cc | 252 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 game/client/player_move.cc (limited to 'game/client/player_move.cc') diff --git a/game/client/player_move.cc b/game/client/player_move.cc new file mode 100644 index 0000000..2c196f9 --- /dev/null +++ b/game/client/player_move.cc @@ -0,0 +1,252 @@ +#include "client/pch.hh" +#include "client/player_move.hh" + +#include "core/angles.hh" +#include "core/config.hh" +#include "core/constexpr.hh" + +#include "shared/dimension.hh" +#include "shared/grounded.hh" +#include "shared/head.hh" +#include "shared/transform.hh" +#include "shared/velocity.hh" + +#include "client/const.hh" +#include "client/gamepad_axis.hh" +#include "client/gamepad_button.hh" +#include "client/gamepad.hh" +#include "client/globals.hh" +#include "client/gui_screen.hh" +#include "client/keybind.hh" +#include "client/session.hh" +#include "client/settings.hh" +#include "client/sound.hh" +#include "client/status_lines.hh" +#include "client/voxel_sounds.hh" + +constexpr static std::uint64_t PMOVE_JUMP_COOLDOWN = 500000; // 0.5 seconds + +constexpr static float PMOVE_FOOTSTEP_SIZE = 2.0f; + +// Movement keys +static ConfigKeyBind key_move_forward(GLFW_KEY_W); +static ConfigKeyBind key_move_back(GLFW_KEY_S); +static ConfigKeyBind key_move_left(GLFW_KEY_A); +static ConfigKeyBind key_move_right(GLFW_KEY_D); +static ConfigKeyBind key_move_down(GLFW_KEY_LEFT_SHIFT); +static ConfigKeyBind key_move_up(GLFW_KEY_SPACE); + +// Movement gamepad axes +static ConfigGamepadAxis axis_move_forward(GLFW_GAMEPAD_AXIS_RIGHT_X, false); +static ConfigGamepadAxis axis_move_sideways(GLFW_GAMEPAD_AXIS_RIGHT_Y, false); + +// Movement gamepad buttons +static ConfigGamepadButton button_move_down(GLFW_GAMEPAD_BUTTON_DPAD_DOWN); +static ConfigGamepadButton button_move_up(GLFW_GAMEPAD_BUTTON_DPAD_UP); + +// General movement options +static ConfigBoolean enable_speedometer(true); + +static std::uint64_t next_jump; +static float speedometer_value; +static float footsteps_distance; +static glm::fvec3 movement_direction; + +// Pitch randomizer +static std::mt19937_64 pitch_random; +static std::uniform_real_distribution pitch_distrib; + +// Quake III's PM_Accelerate clean-roomed +// into my physics and mathematics universe +static glm::fvec3 pm_accelerate(const glm::fvec3 &wishdir, const glm::fvec3 &velocity, float wishspeed, float accel) +{ + auto current_speed = glm::dot(velocity, wishdir); + auto add_speed = wishspeed - current_speed; + + if(add_speed <= 0.0f) { + // Not accelerating + return velocity; + } + + auto accel_speed = cxpr::min(add_speed, accel * globals::fixed_frametime * wishspeed); + + auto result = glm::fvec3(velocity); + result.x += accel_speed * wishdir.x; + result.z += accel_speed * wishdir.z; + return result; +} + +// Returns new player velocity when moving in air +// FIXME: this feels like we have too much air control +static glm::fvec3 pm_airmove(const glm::fvec3 &wishdir, const glm::fvec3 &velocity) +{ + return pm_accelerate(wishdir, velocity, PMOVE_ACCELERATION_AIR, PMOVE_MAX_SPEED_AIR); +} + +// Returns new player velocity when moving on the ground +static glm::fvec3 pm_groundmove(const glm::fvec3 &wishdir, const glm::fvec3 &velocity) +{ + if(auto speed = glm::length(velocity)) { + auto speed_drop = speed * PMOVE_FRICTION_GROUND * globals::fixed_frametime; + auto speed_factor = cxpr::max(speed - speed_drop, 0.0f) / speed; + return pm_accelerate(wishdir, velocity * speed_factor, PMOVE_ACCELERATION_GROUND, PMOVE_MAX_SPEED_GROUND); + } + + return pm_accelerate(wishdir, velocity, PMOVE_ACCELERATION_GROUND, PMOVE_MAX_SPEED_GROUND); +} + +void player_move::init(void) +{ + next_jump = UINT64_C(0); + speedometer_value = 0.0f; + footsteps_distance = 0.0f; + movement_direction = ZERO_VEC3; + + pitch_random.seed(std::random_device()()); + pitch_distrib = std::uniform_real_distribution(0.9f, 1.1f); + + globals::client_config.add_value("player_move.key.forward", key_move_forward); + globals::client_config.add_value("player_move.key.back", key_move_back); + globals::client_config.add_value("player_move.key.left", key_move_left); + globals::client_config.add_value("player_move.key.right", key_move_right); + globals::client_config.add_value("player_move.key.down", key_move_down); + globals::client_config.add_value("player_move.key.up", key_move_up); + globals::client_config.add_value("player_move.gp_axis.move_forward", axis_move_forward); + globals::client_config.add_value("player_move.gp_axis.move_sideways", axis_move_sideways); + globals::client_config.add_value("player_move.gp_button.move_down", button_move_down); + globals::client_config.add_value("player_move.gp_button.move_up", button_move_up); + globals::client_config.add_value("player_move.enable_speedometer", enable_speedometer); + + settings::add_keybind(1, key_move_forward, settings_location::KEYBOARD_MOVEMENT, "player_move.key.forward"); + settings::add_keybind(2, key_move_back, settings_location::KEYBOARD_MOVEMENT, "player_move.key.back"); + settings::add_keybind(3, key_move_left, settings_location::KEYBOARD_MOVEMENT, "player_move.key.left"); + settings::add_keybind(4, key_move_right, settings_location::KEYBOARD_MOVEMENT, "player_move.key.right"); + settings::add_keybind(5, key_move_down, settings_location::KEYBOARD_MOVEMENT, "player_move.key.down"); + settings::add_keybind(6, key_move_up, settings_location::KEYBOARD_MOVEMENT, "player_move.key.up"); + + settings::add_gamepad_axis(0, axis_move_forward, settings_location::GAMEPAD_MOVEMENT, "player_move.gp_axis.move_forward"); + settings::add_gamepad_axis(1, axis_move_sideways, settings_location::GAMEPAD_MOVEMENT, "player_move.gp_axis.move_sideways"); + settings::add_gamepad_button(2, button_move_down, settings_location::GAMEPAD_MOVEMENT, "player_move.gp_button.move_down"); + settings::add_gamepad_button(3, button_move_up, settings_location::GAMEPAD_MOVEMENT, "player_move.gp_button.move_up"); + + settings::add_checkbox(2, enable_speedometer, settings_location::VIDEO_GUI, "player_move.enable_speedometer", true); +} + +void player_move::fixed_update(void) +{ + const auto &head = globals::dimension->entities.get(globals::player); + auto &transform = globals::dimension->entities.get(globals::player); + auto &velocity = globals::dimension->entities.get(globals::player); + + // Interpolation - preserve current component states + globals::dimension->entities.emplace_or_replace(globals::player, transform); + + glm::fvec3 forward, right; + cxangles::vectors(glm::fvec3(0.0f, head.angles[1], 0.0f), &forward, &right, nullptr); + + glm::fvec3 wishdir = ZERO_VEC3; + glm::fvec3 movevars = glm::fvec3(movement_direction.x, 0.0f, movement_direction.z); + wishdir.x = glm::dot(movevars, right); + wishdir.z = glm::dot(movevars, forward); + + auto grounded = globals::dimension->entities.try_get(globals::player); + auto velocity_horizontal = glm::fvec3(velocity.value.x, 0.0f, velocity.value.z); + + if(grounded) { + auto new_velocity = pm_groundmove(wishdir, velocity_horizontal); + velocity.value.x = new_velocity.x; + velocity.value.z = new_velocity.z; + + auto new_speed = glm::length(new_velocity); + + if(new_speed > 0.01f) + footsteps_distance += globals::fixed_frametime * new_speed; + else footsteps_distance = 0.0f; + + if(footsteps_distance >= PMOVE_FOOTSTEP_SIZE) { + if(auto effect = voxel_sounds::get_footsteps(grounded->surface)) + sound::play_player(effect, false, pitch_distrib(pitch_random)); + footsteps_distance = 0.0f; + } + } + else { + auto new_velocity = pm_airmove(wishdir, velocity_horizontal); + velocity.value.x = new_velocity.x; + velocity.value.z = new_velocity.z; + } + + if(movement_direction.y == 0.0f) { + // Allow players to queue bunny-jumps by quickly + // releasing and pressing the jump key again without a cooldown + next_jump = UINT64_C(0); + return; + } + + if(grounded && (movement_direction.y > 0.0f) && (globals::curtime >= next_jump)) { + velocity.value.y = -PMOVE_JUMP_FORCE * globals::dimension->get_gravity(); + + auto new_speed = glm::length(glm::fvec2(velocity.value.x, velocity.value.z)); + auto new_speed_text = fmt::format("{:.02f} M/S", new_speed); + auto speed_change = new_speed - speedometer_value; + + speedometer_value = new_speed; + + next_jump = globals::curtime + PMOVE_JUMP_COOLDOWN; + + if(enable_speedometer.get_value()) { + if(cxpr::abs(speed_change) < 0.01f) { + // No considerable speed increase within + // the precision we use to draw the speedometer + status_lines::set(STATUS_DEBUG, new_speed_text, ImVec4(0.7f, 0.7f, 0.7f, 1.0f), 1.0f); + } + else if(speed_change < 0.0f) { + // Speed change is negative, we are actively + // slowing down; use the red color for the status line + status_lines::set(STATUS_DEBUG, new_speed_text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f), 1.0f); + } + else { + // Speed change is positive, we are actively + // speeding up; use the green color for the status line + status_lines::set(STATUS_DEBUG, new_speed_text, ImVec4(0.0f, 1.0f, 0.0f, 1.0f), 1.0f); + } + } + + if(auto effect = voxel_sounds::get_footsteps(grounded->surface)) { + sound::play_player(effect, false, 1.0f); + } + } +} + +void player_move::update_late(void) +{ + movement_direction = ZERO_VEC3; + + if(globals::gui_screen || !session::is_ingame()) { + // We're either disconnected or have the + // UI opened up; anyways we shouldn't move + return; + } + + if(gamepad::available && gamepad::active.get_value()) { + if(button_move_down.is_pressed(gamepad::state)) + movement_direction += DIR_DOWN; + if(button_move_up.is_pressed(gamepad::state)) + movement_direction += DIR_UP; + movement_direction.x += axis_move_sideways.get_value(gamepad::state, gamepad::deadzone.get_value()); + movement_direction.z -= axis_move_forward.get_value(gamepad::state, gamepad::deadzone.get_value()); + } + else { + if(GLFW_PRESS == glfwGetKey(globals::window, key_move_forward.get_key())) + movement_direction += DIR_FORWARD; + if(GLFW_PRESS == glfwGetKey(globals::window, key_move_back.get_key())) + movement_direction += DIR_BACK; + if(GLFW_PRESS == glfwGetKey(globals::window, key_move_left.get_key())) + movement_direction += DIR_LEFT; + if(GLFW_PRESS == glfwGetKey(globals::window, key_move_right.get_key())) + movement_direction += DIR_RIGHT; + if(GLFW_PRESS == glfwGetKey(globals::window, key_move_down.get_key())) + movement_direction += DIR_DOWN; + if(GLFW_PRESS == glfwGetKey(globals::window, key_move_up.get_key())) + movement_direction += DIR_UP; + } +} -- cgit