Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions DogTales/dog/dogtales.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <bave/imgui/im_text.hpp>
#include <dog/dogtales.hpp>

namespace dog {
Expand All @@ -6,6 +7,30 @@ 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").value());
bave::im_text("move_y (Press W/S or Up/Down): {:.2f}",
m_player.get_controller_state("move_y").value());
bave::im_text("Jump (Press 'E'): {:.2f}", m_player.get_controller_state("jump").value());
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
}
ImGui::End();
}

// Update player
m_player.tick(dt);
}
Expand Down
15 changes: 9 additions & 6 deletions DogTales/dog/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@ Player::Player(bave::App& app, glm::vec2 const world_space) : m_app(app), m_worl

void Player::tick(bave::Seconds const dt) {

m_physics.tick(dt);
if (physics_enabled) { m_physics.tick(dt); }
m_player_controller.tick(dt, m_app);

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_controller_state("move_x").value();
direction.y += m_player_controller.get_controller_state("move_y").value();

if (direction.x != 0.0f || direction.y != 0.0f) {
direction = glm::normalize(direction);
Expand All @@ -27,6 +26,10 @@ void Player::tick(bave::Seconds const dt) {

void Player::draw(bave::Shader& shader) const { m_sprite.draw(shader); }

std::optional<float> Player::get_controller_state(std::string_view key) const {
return m_player_controller.get_controller_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.
Expand Down
6 changes: 6 additions & 0 deletions DogTales/dog/player.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <bave/app.hpp>
#include <bave/graphics/sprite.hpp>
#include "components/physics.hpp"
#include "player/PlayerController.hpp"

namespace dog {
class Player {
Expand All @@ -15,6 +16,7 @@ class Player {
bave::Sprite m_sprite{};

component::Physics m_physics{};
PlayerController m_player_controller{};

void handle_wall_collision();

Expand All @@ -23,5 +25,9 @@ class Player {

void tick(bave::Seconds dt);
void draw(bave::Shader& shader) const;

std::optional<float> get_controller_state(std::string_view key) const;

bool physics_enabled{}; // for debugging
};
} // namespace dog
41 changes: 41 additions & 0 deletions DogTales/dog/player/PlayerController.cpp
Copy link
Member

@karnkaul karnkaul Feb 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filename should be in snake_case like others.

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "PlayerController.hpp"

namespace dog {

PlayerController::PlayerController() {
key_map.insert(std::make_pair("move_x", 0.f));
key_map.insert(std::make_pair("move_y", 0.f));
key_map.insert(std::make_pair("jump", 0.f));
}

void PlayerController::tick(bave::Seconds dt, bave::App const& app) {

auto const& key_state = app.get_key_state();

bool left = key_state.is_pressed(bave::Key::eA) || key_state.is_pressed(bave::Key::eLeft);
bool right = key_state.is_pressed(bave::Key::eD) || key_state.is_pressed(bave::Key::eRight);
bool up = key_state.is_pressed(bave::Key::eW) || key_state.is_pressed(bave::Key::eUp);
bool down = key_state.is_pressed(bave::Key::eS) || key_state.is_pressed(bave::Key::eDown);

key_map["move_x"] = 0.f;
key_map["move_x"] = left && !right ? -1.f : key_map["move_x"];
key_map["move_x"] = right && !left ? 1.f : key_map["move_x"];
key_map["move_x"] = right && left ? 0.f : key_map["move_x"];

key_map["move_y"] = 0.f;
key_map["move_y"] = down && !up ? -1.f : key_map["move_y"];
key_map["move_y"] = up && !down ? 1.f : key_map["move_y"];
key_map["move_y"] = up && down ? 0.f : key_map["move_y"];

key_map["jump"] = key_state.is_pressed(bave::Key::eW) || key_state.is_pressed(bave::Key::eUp) ? 1.f : 0.f;
}
Copy link
Member

@karnkaul karnkaul Feb 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few things to refactor here.

  1. Don't call key_map["move_x"] a dozen times - it will perform the hash, comparison, and lookup each time. Instead get a reference once and operate on the reference throughout the function.
  2. The left / right logic is unnecessarily complicating things, instead just append the delta to a temp float, and clamp it between -1.0f and 1.0f at the end.
  3. This is still pretty hard-coded and there's no indirection for which key corresponds to which game-action. I think at this level it's better for the logic to be generic: the controller should cycle through its mappings and update the key_map according to the current key_state, without knowing how many mappings there are / what they are.


std::optional<float> PlayerController::get_controller_state(std::string_view key) const {
if (auto search = key_map.find(key); search != key_map.end()) {
return search->second;
} else {
return -1.f;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two points:

  1. Since this always returns a float, there's not much point in wrapping it in std::optional. Even in the user code above you don't check if the returned optional has a value, just call .value() anyway. Returning a float will eliminate that redundancy.
  2. The default returned value should be 0.0f not -1.0f, because that implies: eg "pulling left all the time" if interpreted as a horizontal direction for a key that isn't mapped. 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: else is redundant if all paths in the if above it return.


} // namespace dog
18 changes: 18 additions & 0 deletions DogTales/dog/player/PlayerController.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once
#include <bave/app.hpp>
#include <bave/core/string_hash.hpp>
#include <optional>

namespace dog {
class PlayerController {

public:
PlayerController();

void tick(bave::Seconds dt, bave::App const& app);
std::optional<float> get_controller_state(std::string_view key) const;

private:
std::unordered_map<std::string, float, bave::StringHash, std::equal_to<>> key_map{};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: non-public members have the m_ prefix everywhere else.

};
} // namespace dog