godot-cpp-utils/player_input.cpp

134 lines
4.5 KiB
C++
Raw Normal View History

2024-02-13 13:59:01 +00:00
#include "player_input.hpp"
#include "godot_macros.h"
#include <godot_cpp/classes/input.hpp>
#include <godot_cpp/classes/input_event.hpp>
#include <godot_cpp/classes/input_event_mouse_motion.hpp>
#include <godot_cpp/variant/callable.hpp>
#include <optional>
2024-02-13 13:59:01 +00:00
namespace utils {
void PlayerInput::_bind_methods() {
#define CLASSNAME PlayerInput
}
2024-02-13 13:59:01 +00:00
gd::Vector2 PlayerInput::lastMouseMotion{0.f, 0.f};
bool PlayerInput::primaryExists{false};
PlayerInput::Listener::Listener(gd::String negative, gd::String positive, gd::Callable callable)
2024-02-13 13:59:01 +00:00
: actionNegative{negative}
, actionPositive{positive}
, callable{callable}
, isMouseEvent{positive.begins_with("_mouse_") || negative.begins_with("_mouse_")} {}
PlayerInput::Listener::Listener(gd::String action, gd::Callable callable)
: PlayerInput::Listener::Listener(gd::String(), action, callable) {}
std::optional<float> PlayerInput::Listener::evaluate_action(gd::String const &action) {
gd::Input *input = gd::Input::get_singleton();
if(action.begins_with("_mouse_")) {
gd::Vector2 vector = PlayerInput::get_last_mouse_motion();
if(action.ends_with("_up"))
return vector.y > 0.f ? vector.y : 0.f;
else if(action.ends_with("_down"))
return vector.y < 0.f ? -vector.y : 0.f;
else if(action.ends_with("_right"))
return vector.x > 0.f ? vector.x : 0.f;
else if(action.ends_with("_left"))
return vector.x < 0.f ? -vector.x : 0.f;
2024-03-20 08:44:25 +00:00
}
if(action.is_empty()) {
return 0.f;
} else {
return float(input->is_action_pressed(action));
}
}
2024-02-13 13:59:01 +00:00
bool PlayerInput::Listener::has_changed(gd::Ref<gd::InputEvent> const &event) {
2024-03-20 08:44:25 +00:00
bool const mouse_changed{this->isMouseEvent && event->is_class("InputEventMouseMotion")};
bool const negative_changed{!this->actionNegative.is_empty() && event->is_action(this->actionNegative)};
bool const positive_changed{!this->actionPositive.is_empty() && event->is_action(this->actionPositive)};
return mouse_changed || negative_changed || positive_changed;
2024-02-13 13:59:01 +00:00
}
float PlayerInput::Listener::evaluate(gd::Ref<gd::InputEvent> const &event) {
std::optional<float> positive = PlayerInput::Listener::evaluate_action(this->actionPositive);
std::optional<float> negative = PlayerInput::Listener::evaluate_action(this->actionNegative);
if(!positive.has_value() || !negative.has_value())
return 0.f;
float newest = positive.value() - negative.value();
if(this->lastCached != newest || this->isMouseEvent)
this->callable.call(event, newest);
return (this->lastCached = newest);
2024-02-13 13:59:01 +00:00
}
bool PlayerInput::Listener::operator==(PlayerInput::Listener const& b) const {
return this->callable == b.callable
2024-02-13 13:59:01 +00:00
&& this->actionNegative == b.actionNegative
&& this->actionPositive == b.actionPositive;
}
gd::Vector2 PlayerInput::get_last_mouse_motion() {
return PlayerInput::lastMouseMotion;
}
void PlayerInput::_enter_tree() { GDGAMEONLY();
if(!PlayerInput::primaryExists) {
this->isPrimary = true;
PlayerInput::primaryExists = true;
}
}
void PlayerInput::_exit_tree() { GDGAMEONLY();
if(this->isPrimary) {
this->isPrimary = false;
PlayerInput::primaryExists = false;
}
}
void PlayerInput::_unhandled_input(gd::Ref<gd::InputEvent> const &event) { GDGAMEONLY();
if(this->isPrimary && event->is_class("InputEventMouseMotion"))
PlayerInput::lastMouseMotion = gd::Object::cast_to<gd::InputEventMouseMotion>(*event)->get_relative();
2024-02-13 13:59:01 +00:00
for(Listener& listener: this->listeners) {
if(listener.has_changed(event)) {
listener.evaluate(event);
}
}
}
void PlayerInput::_process(double deltaTime) {
2024-03-20 08:44:25 +00:00
if(this->isPrimary)
PlayerInput::lastMouseMotion = {0.f, 0.f};
}
2024-02-13 13:59:01 +00:00
void PlayerInput::listen_to(Listener const& listener) {
this->listeners.push_back(listener);
}
void PlayerInput::listen_to(gd::String action, gd::Callable callable) {
this->listeners.push_back(Listener(action, callable));
}
void PlayerInput::listen_to(gd::String negative, gd::String positive, gd::Callable callable) {
this->listeners.push_back(Listener(negative, positive, callable));
}
2024-02-13 13:59:01 +00:00
void PlayerInput::stop_listening(Node *node) {
for(size_t i = 0; i < this->listeners.size(); ++i) {
Listener l = this->listeners.get(i);
if(l.callable.get_object() == node) {
this->listeners.remove_at(i);
2024-02-13 13:59:01 +00:00
i--;
}
}
}
void PlayerInput::stop_listening(Listener const& listener) {
this->listeners.erase(listener);
2024-02-13 13:59:01 +00:00
}
void PlayerInput::clear_listeners() {
this->listeners.clear();
}
2024-02-13 13:59:01 +00:00
}