141 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			141 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "player_input.hpp"
 | |
| #include "godot_macros.hpp"
 | |
| #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 <godot_cpp/variant/utility_functions.hpp>
 | |
| #include <optional>
 | |
| 
 | |
| namespace utils {
 | |
| void PlayerInput::_bind_methods() {
 | |
| #define CLASSNAME PlayerInput
 | |
| }
 | |
| 
 | |
| gd::Vector2 PlayerInput::lastMouseMotion{0.f, 0.f};
 | |
| bool PlayerInput::primaryExists{false};
 | |
| 
 | |
| PlayerInput::Listener::Listener(gd::String negative, gd::String positive, gd::Callable callable)
 | |
| : 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 == "_mouse_up")
 | |
|             return vector.y > 0.f ? vector.y : 0.f;
 | |
|         else if(action == "_mouse_down")
 | |
|             return vector.y < 0.f ? -vector.y : 0.f;
 | |
|         else if(action == "_mouse_right")
 | |
|             return vector.x > 0.f ? vector.x : 0.f;
 | |
|         else if(action == "_mouse_left")
 | |
|             return vector.x < 0.f ? -vector.x : 0.f;
 | |
|     }
 | |
|     if(action.is_empty()) {
 | |
|         return 0.f;
 | |
|     } else {
 | |
|         return float(input->get_action_strength(action));
 | |
|     }
 | |
| }
 | |
| 
 | |
| bool PlayerInput::Listener::has_changed(gd::Ref<gd::InputEvent> const &event) {
 | |
|     // do not evaluate mouse events as anything but
 | |
|     if(this->isMouseEvent)
 | |
|         return 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 negative_changed || positive_changed;
 | |
| }
 | |
| 
 | |
| 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);
 | |
| }
 | |
| 
 | |
| bool PlayerInput::Listener::operator==(PlayerInput::Listener const& b) const {
 | |
|     return this->callable == b.callable
 | |
|         && 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();
 | |
|     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::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));
 | |
| }
 | |
| 
 | |
| 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);
 | |
|             i--;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| void PlayerInput::stop_listening(Listener const& listener) {
 | |
|     this->listeners.erase(listener);
 | |
| }
 | |
| 
 | |
| void PlayerInput::clear_listeners() {
 | |
|     this->listeners.clear();
 | |
| }
 | |
| 
 | |
| void PlayerInput::set_device(int id) {
 | |
|     this->device = id;
 | |
| }
 | |
| }
 | |
| 
 | 
