#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 #include namespace godot { void PlayerInput::_bind_methods() {} Vector2 PlayerInput::lastMouseMotion{0.f, 0.f}; bool PlayerInput::primaryExists{false}; PlayerInput::Listener::Listener(String positive, String negative, Callable callable) : actionNegative{negative} , actionPositive{positive} , callable{callable} , isMouseEvent{positive.begins_with("_mouse_") || negative.begins_with("_mouse_")} {} PlayerInput::Listener::Listener(String action, Callable callable) : PlayerInput::Listener::Listener(action, String(), callable) {} std::optional PlayerInput::Listener::evaluate_action(String const &action) { Input *input = Input::get_singleton(); if(action.begins_with("_mouse_")) { 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; } if(action.is_empty()) { return 0.f; } else { return float(input->is_action_pressed(action)); } } bool PlayerInput::Listener::has_changed(Ref const &event) { 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; } float PlayerInput::Listener::evaluate(Ref const &event) { std::optional positive = PlayerInput::Listener::evaluate_action(this->actionPositive); std::optional 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); } bool PlayerInput::Listener::operator==(godot::PlayerInput::Listener const& b) { return this->callable == b.callable && this->actionNegative == b.actionNegative && this->actionPositive == b.actionPositive; } 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(Ref const &event) { GDGAMEONLY(); if(this->isPrimary && event->is_class("InputEventMouseMotion")) PlayerInput::lastMouseMotion = Object::cast_to(*event)->get_relative(); for(Listener& listener: this->listeners) { if(listener.has_changed(event)) { listener.evaluate(event); } } } void PlayerInput::_process(double deltaTime) { if(this->isPrimary) PlayerInput::lastMouseMotion = {0.f, 0.f}; } void PlayerInput::listen_to(Listener const& listener) { this->listeners.push_back(listener); } void PlayerInput::stop_listening(Node *node) { for(size_t i = 0; i < this->listeners.size(); ++i) { Listener& l = this->listeners.at(i); if(l.callable.get_object() == node) { this->listeners.erase(this->listeners.begin() + i); i--; } } } void PlayerInput::stop_listening(Listener const& listener) { std::vector::iterator itr = std::find(this->listeners.begin(), this->listeners.end(), listener); if(itr != this->listeners.end()) this->listeners.erase(itr); } void PlayerInput::clear_listeners() { this->listeners.clear(); } }