-
Notifications
You must be signed in to change notification settings - Fork 0
add player controller. add debug window for testing. #33
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
base: main
Are you sure you want to change the base?
Conversation
DogTales/dog/dogtales.cpp
Outdated
if (ImGui::BeginTabItem("Player")) { | ||
bave::im_text("Controller States"); | ||
ImGui::Separator(); | ||
ImGui::Text("Test (Press 'T'): %.2f", m_player.get_controller_state("test")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
DogTales/dog/player.cpp
Outdated
@@ -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) { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep
DogTales/dog/player.cpp
Outdated
try { | ||
return m_player_controller.key_map[key]; | ||
} catch (std::out_of_range const& oor) { return -1.f; } |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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()
?
There was a problem hiding this comment.
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.
DogTales/dog/player.hpp
Outdated
void draw(bave::Shader& shader) const; | ||
|
||
float const get_controller_state(std::string key); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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{}; |
There was a problem hiding this comment.
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{};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay, fixed!
Also, |
…dd actual keymaps, and update debug menu accordingly.
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; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two points:
- 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 afloat
will eliminate that redundancy. - 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. 😄
There was a problem hiding this comment.
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{}; |
There was a problem hiding this comment.
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.
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; | ||
} |
There was a problem hiding this comment.
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.
- 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. - The
left
/right
logic is unnecessarily complicating things, instead just append the delta to a tempfloat
, and clamp it between-1.0f
and1.0f
at the end. - 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 currentkey_state
, without knowing how many mappings there are / what they are.
There was a problem hiding this comment.
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.
added a
PlayerController
class and gave one tom_player
. Also added a small debug menu with ImGui for testing.