111 lines
		
	
	
		
			4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			111 lines
		
	
	
		
			4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #ifndef UTILS_PLAYER_INPUT_HPP
 | |
| #define UTILS_PLAYER_INPUT_HPP
 | |
| 
 | |
| #include <optional>
 | |
| #include <godot_cpp/classes/input.hpp>
 | |
| #include <godot_cpp/classes/input_event.hpp>
 | |
| #include <godot_cpp/classes/node.hpp>
 | |
| #include <godot_cpp/templates/vector.hpp>
 | |
| #include <godot_cpp/variant/callable.hpp>
 | |
| 
 | |
| namespace gd = godot;
 | |
| 
 | |
| namespace utils {
 | |
| /*! An event-driven input observer.
 | |
|  *
 | |
|  * Listen for events with `listen_to`, registering godot input action names to callbacks. It's possible to register an "axis" by registering a listener with a positive and negative action.
 | |
|  */
 | |
| class PlayerInput : public gd::Node {
 | |
|     GDCLASS(PlayerInput, gd::Node)
 | |
|     static void _bind_methods();
 | |
| public:
 | |
|     /*! A PlayerInput action listener.
 | |
|      *
 | |
|      * A listener is a combination of a positive and negative action and a callable.
 | |
|      * The expected callable signature is `void (godot::Ref<godot::InputEvent> event, float value)`
 | |
|      * actions can also be "special" actions prefixed with `_`.
 | |
|      * Special actions include `_mouse_up`, `_mouse_down`, `_mouse_left`, and `_mouse_right`.
 | |
|      */
 | |
|     struct Listener {
 | |
|         friend class PlayerInput;
 | |
|     private:
 | |
|         //! Negative action on axis, evaluates to -1.
 | |
|         gd::String actionNegative{""};
 | |
|         //! Positive action on axis, evaluates to +1.
 | |
|         gd::String actionPositive{""};
 | |
|         /*! The last cached action.
 | |
|          *
 | |
|          * If the newest result matches this, the event will be considered duplicate and ignored (not passed to listener)
 | |
|          */
 | |
|         float lastCached{0.f};
 | |
|         //! The listening function.
 | |
|         gd::Callable callable;
 | |
|         //! If either actionNegative or actionPositive is a _mouse_ event this will be true
 | |
|         bool isMouseEvent{false};
 | |
| 
 | |
|     public:
 | |
|         Listener() = default;
 | |
|         Listener(gd::String negative, gd::String positive, gd::Callable callable);
 | |
|         Listener(gd::String action, gd::Callable callable);
 | |
|         // evaluate the current state of an action.
 | |
|         static std::optional<float> evaluate_action(gd::String const &action);
 | |
|         /*! Check if this event has any chance to result in a trigger.
 | |
|          *
 | |
|          * Does not evaluate the event or poll current input state
 | |
|          */
 | |
|         bool has_changed(gd::Ref<gd::InputEvent> const &event);
 | |
|         //! evaluate the event for changes to either actionPositive or actionNegative
 | |
|         float evaluate(gd::Ref<gd::InputEvent> const &event);
 | |
|         bool operator==(PlayerInput::Listener const& b) const;
 | |
|     };
 | |
| public:
 | |
|     //! Returns the last stored mouse delta.
 | |
|     static gd::Vector2 get_last_mouse_motion();
 | |
| 
 | |
|     virtual void _enter_tree() override;
 | |
|     virtual void _exit_tree() override;
 | |
|     virtual void _unhandled_input(gd::Ref<gd::InputEvent> const &event) override;
 | |
|     virtual void _process(double deltaTime) override;
 | |
| 
 | |
|     //! Start listening for action.
 | |
|     void listen_to(Listener const &listener);
 | |
|     /*! Start listening for action.
 | |
|      *
 | |
|      * Shorthand for `listen_to(Listener(action, callable))`.
 | |
|      */
 | |
|     void listen_to(gd::String action, gd::Callable callable);
 | |
|     /*! Start listening for action.
 | |
|      *
 | |
|      * Shorthand for `listen_to(Listener(negative, positive, callable))`.
 | |
|      */
 | |
|     void listen_to(gd::String negative, gd::String positive, gd::Callable callable);
 | |
| 
 | |
|     //! Remove any listeners related to node.
 | |
|     void stop_listening(Node *node);
 | |
|     //! Remove listeners exactly equal to listener.
 | |
|     void stop_listening(Listener const &listener);
 | |
|     //! Remove all listeners.
 | |
|     void clear_listeners();
 | |
|     //! set the device observe events from.
 | |
|     void set_device(int id);
 | |
| private:
 | |
|     //! The last mouse motion, updated by the primary instance
 | |
|     static gd::Vector2 lastMouseMotion;
 | |
|     //! Does a primary instance exist
 | |
|     static bool primaryExists;
 | |
|     /*! Is this the primary instance.
 | |
|      *
 | |
|      * The primary instance is responsible for updating static variables like lastMouseMotion.
 | |
|      */
 | |
|     bool isPrimary{false};
 | |
|     //! which device to observe events from.
 | |
|     int device{-1}; 
 | |
| 
 | |
|     //! current listeners for this instance
 | |
|     gd::Vector<Listener> listeners{};
 | |
| };
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif // !UTILS_PLAYER_INPUT_HPP
 | 
