Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add player controller. add debug window for testing. #33

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

swagween
Copy link
Contributor

added a PlayerController class and gave one to m_player. Also added a small debug menu with ImGui for testing.

if (ImGui::BeginTabItem("Player")) {
bave::im_text("Controller States");
ImGui::Separator();
ImGui::Text("Test (Press 'T'): %.2f", m_player.get_controller_state("test"));
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
ImGui::Text("Test (Press 'T'): %.2f", m_player.get_controller_state("test"));
bave::im_text("Test (Press 'T'): {:.2f}", m_player.get_controller_state("test"));

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

@@ -27,6 +23,12 @@ void Player::tick(bave::Seconds const dt) {

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

float const Player::get_controller_state(std::string key) {
Copy link
Member

Choose a reason for hiding this comment

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

Returning a float const is redundant, compiler/linter should be warning about this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

should I just make it float?

Copy link
Member

Choose a reason for hiding this comment

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

Yep

Comment on lines 27 to 29
try {
return m_player_controller.key_map[key];
} catch (std::out_of_range const& oor) { 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.

We don't want to risk exceptional paths in hot code like this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

what should i do instead? just return the element? or use if()?

Copy link
Member

Choose a reason for hiding this comment

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

First of all the member function should be const. Once that's done key_map[key] will not compile anyway. So you'd want to use key_map.find(key) and return a default value / nullopt if the key isn't present.

Comment on lines 27 to 29
void draw(bave::Shader& shader) const;

float const get_controller_state(std::string key);
Copy link
Member

Choose a reason for hiding this comment

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

Taking a std::string_view would optimize calls made with literals.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed!


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

std::unordered_map<std::string, float> 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.

This shouldn't be public, as anybody can modify it. Also, use an annoyingly long form to enable string_view lookups:

#include <bave/core/string_hash.hpp>

// ...
std::unordered_map<std::string, float, bave::StringHash, std::equal_to<>> key_map{};

Copy link
Contributor Author

Choose a reason for hiding this comment

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

okay, fixed!

@karnkaul
Copy link
Member

Also, player::PlayerController is a bit much, one of the prefixes is sufficient. 😅

Comment on lines 33 to 39
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.

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.

Comment on lines 11 to 31
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.

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.

@karnkaul
Copy link
Member

@swagween I've created a PR targeting this branch, feel free to merge it or adopt the changes yourself and close it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants