diff --git a/DogTales/dog/dogtales.cpp b/DogTales/dog/dogtales.cpp index 1e86c9a..7868748 100644 --- a/DogTales/dog/dogtales.cpp +++ b/DogTales/dog/dogtales.cpp @@ -1,3 +1,4 @@ +#include #include namespace dog { @@ -6,6 +7,28 @@ DogTales::DogTales(bave::App& app) : bave::Driver(app), m_player(app, world_spac void DogTales::tick() { auto const dt = get_app().get_dt(); + // ImGui calls + if constexpr (bave::imgui_v) { + if (ImGui::Begin("Debug")) { + if (ImGui::BeginTabBar("Main")) { + if (ImGui::BeginTabItem("General")) { + ImGui::Checkbox("Physics", &m_player.physics_enabled); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Player")) { + bave::im_text("Controller States"); + ImGui::Separator(); + bave::im_text("move_x (Press A/D or Left/Right): {:.2f}", m_player.get_controller_state("move_x")); + bave::im_text("move_y (Press W/S or Up/Down): {:.2f}", m_player.get_controller_state("move_y")); + bave::im_text("Jump (Press Space): {:.2f}", m_player.get_controller_state("jump")); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + } + ImGui::End(); + } + // Update player m_player.tick(dt); } diff --git a/DogTales/dog/dogtales.hpp b/DogTales/dog/dogtales.hpp index d627f1f..f7aa509 100644 --- a/DogTales/dog/dogtales.hpp +++ b/DogTales/dog/dogtales.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include namespace dog { class DogTales : public bave::Driver { diff --git a/DogTales/dog/player.cpp b/DogTales/dog/player/player.cpp similarity index 68% rename from DogTales/dog/player.cpp rename to DogTales/dog/player/player.cpp index e8387ca..a75a18d 100644 --- a/DogTales/dog/player.cpp +++ b/DogTales/dog/player/player.cpp @@ -1,20 +1,24 @@ -#include +#include namespace dog { Player::Player(bave::App& app, glm::vec2 const world_space) : m_app(app), m_world_space(world_space) { m_sprite.set_size(size_v); + + m_player_controller.bind_throttle("move_x", {.lo = bave::Key::eLeft, .hi = bave::Key::eRight}); + m_player_controller.bind_throttle("move_x", {.lo = bave::Key::eA, .hi = bave::Key::eD}); + m_player_controller.bind_throttle("move_y", {.lo = bave::Key::eDown, .hi = bave::Key::eUp}); + m_player_controller.bind_throttle("move_y", {.lo = bave::Key::eS, .hi = bave::Key::eW}); + m_player_controller.bind_key("jump", bave::Key::eSpace); } void Player::tick(bave::Seconds const dt) { - m_physics.tick(dt); + if (physics_enabled) { m_physics.tick(dt); } - auto const& key_state = m_app.get_key_state(); auto direction = glm::vec2{}; - if (key_state.is_pressed(bave::Key::eW) || key_state.is_pressed(bave::Key::eUp)) { direction.y += 1.0f; } - if (key_state.is_pressed(bave::Key::eS) || key_state.is_pressed(bave::Key::eDown)) { direction.y -= 1.0f; } - if (key_state.is_pressed(bave::Key::eA) || key_state.is_pressed(bave::Key::eLeft)) { direction.x -= 1.0f; } - if (key_state.is_pressed(bave::Key::eD) || key_state.is_pressed(bave::Key::eRight)) { direction.x += 1.0f; } + + direction.x += m_player_controller.get_state("move_x"); + direction.y += m_player_controller.get_state("move_y"); if (direction.x != 0.0f || direction.y != 0.0f) { direction = glm::normalize(direction); @@ -27,6 +31,8 @@ void Player::tick(bave::Seconds const dt) { void Player::draw(bave::Shader& shader) const { m_sprite.draw(shader); } +float Player::get_controller_state(std::string_view key) const { return m_player_controller.get_state(key); } + void Player::handle_wall_collision() { auto& position = m_physics.position; // bounce_rect represents the play area for the sprite, ie the limits for its centre. diff --git a/DogTales/dog/player.hpp b/DogTales/dog/player/player.hpp similarity index 71% rename from DogTales/dog/player.hpp rename to DogTales/dog/player/player.hpp index 07e51a2..344cc34 100644 --- a/DogTales/dog/player.hpp +++ b/DogTales/dog/player/player.hpp @@ -1,7 +1,8 @@ #pragma once #include #include -#include "components/physics.hpp" +#include +#include namespace dog { class Player { @@ -15,6 +16,7 @@ class Player { bave::Sprite m_sprite{}; component::Physics m_physics{}; + PlayerController m_player_controller{&m_app}; void handle_wall_collision(); @@ -23,5 +25,9 @@ class Player { void tick(bave::Seconds dt); void draw(bave::Shader& shader) const; + + float get_controller_state(std::string_view key) const; + + bool physics_enabled{}; // for debugging }; } // namespace dog diff --git a/DogTales/dog/player/player_controller.cpp b/DogTales/dog/player/player_controller.cpp new file mode 100644 index 0000000..1ae1ee4 --- /dev/null +++ b/DogTales/dog/player/player_controller.cpp @@ -0,0 +1,45 @@ +#include +#include +#include + +namespace dog { + +PlayerController::PlayerController(bave::NotNull app) : m_app(app) {} + +void PlayerController::bind_throttle(std::string_view const id, Throttle const throttle) { + if (throttle.hi == bave::Key::eUnknown) { return; } + auto it = m_mappings.find(id); + if (it == m_mappings.end()) { + auto [i, _] = m_mappings.insert_or_assign(std::string{id}, std::vector{}); + it = i; + } + assert(it != m_mappings.end()); + it->second.push_back(throttle); +} + +void PlayerController::bind_key(std::string_view id, bave::Key key) { + // if Throttle::lo is Key::eUnknown it will be ignored in get_state(), so we exploit that here. + bind_throttle(id, Throttle{.hi = key}); +} + +float PlayerController::get_state(std::string_view const id) const { + auto const search = m_mappings.find(id); + if (search == m_mappings.end()) { return 0.0f; } + + auto const& mappings = search->second; + auto const get_throttle_state = [&](Throttle const throttle) { + auto const is_pressed = [this](bave::Key const key) { return m_app->get_key_state().is_pressed(key); }; + if (throttle.lo != bave::Key::eUnknown && is_pressed(throttle.lo)) { return -1.0f; } + if (is_pressed(throttle.hi)) { return 1.0f; } + return 0.0f; + }; + + auto ret = 0.0f; + for (auto const& mapping : mappings) { + // later a visitor will be required here, to handle Throttle vs GamepadAxis vs GamepadButton. + ret += get_throttle_state(mapping); + } + return std::clamp(ret, -1.0f, 1.0f); +} + +} // namespace dog diff --git a/DogTales/dog/player/player_controller.hpp b/DogTales/dog/player/player_controller.hpp new file mode 100644 index 0000000..e97a055 --- /dev/null +++ b/DogTales/dog/player/player_controller.hpp @@ -0,0 +1,30 @@ +#pragma once +#include +#include +#include +#include + +namespace dog { +class PlayerController { + + public: + struct Throttle { + bave::Key lo{}; // -1 + bave::Key hi{}; // +1 + }; + + explicit PlayerController(bave::NotNull app); + + void bind_throttle(std::string_view id, Throttle throttle); + void bind_key(std::string_view id, bave::Key key); + + float get_state(std::string_view id) const; + + private: + bave::NotNull m_app; + + using Mapping = Throttle; // later to be a variant of Throttle / GamepadAxis / GamepadButton. + + std::unordered_map, bave::StringHash, std::equal_to<>> m_mappings{}; +}; +} // namespace dog